pwntools

pwntools 是 CTF Pwn 题最常用的 Python 库,提供了与二进制程序交互、调试、ROP 链构造等功能。

模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
import sys

context.terminal = ['tmux', 'sp', '-h']
context.update(log_level='debug', os='linux', arch='amd64')

if len(sys.argv) > 1 and sys.argv[1] == "r":
io = remote('')
else:
io = process('')

elf = ELF('')
# exploit

io.interactive()

常用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 进程和远程连接
io = process('./binary') # 本地进程
io = remote('host', port) # 远程连接
io = gdb.debug('./binary', gdbscript) # 附加 gdb 调试

# 数据打包和解包
p64(0x41414141) # 打包为 64 位小端序
p32(0x41414141) # 打包为 32 位小端序
u64(data) # 解包 64 位数据
u32(data) # 解包 32 位数据

# 发送和接收数据
io.send(data) # 发送数据(不换行)
io.sendline(data) # 发送数据(带换行)
io.sendafter(delim, data) # 接收到 delim 后发送
io.recv(n) # 接收 n 字节
io.recvline() # 接收一行
io.recvuntil(delim) # 接收到 delim 为止
io.interactive() # 进入交互模式

# ELF 文件操作
elf = ELF('./binary')
elf.symbols['main'] # 获取符号地址
elf.got['puts'] # 获取 GOT 表地址
elf.plt['puts'] # 获取 PLT 表地址
elf.bss() # 获取 bss 段地址
elf.search(b'/bin/sh') # 搜索字符串

# Shellcode 生成
context.arch = 'amd64'
shellcode = asm(shellcraft.sh()) # 生成 shellcode
shellcode = asm(shellcraft.execve('/bin/sh'))

# ROP 链构造
rop = ROP(elf)
rop.call('puts', [elf.got['puts']])
rop.chain() # 生成 ROP 链
rop.find_gadget(['pop rdi', 'ret']) # 查找 gadget

# 其他工具
libc = ELF('./libc.so.6')
libc.symbols['system'] # libc 中的函数地址
next(libc.search(b'/bin/sh')) # 搜索字符串

pwndbg

pwndbg 是 gdb 的一个增强插件,提供了更友好的界面和强大的堆分析功能。

打印

1
2
3
4
5
6
7
print *0xAAAA
x /20xg 0xAAAA # 以 16 进制格式打印 20 个 8 字节
x /20xw 0xAAAA # 以 16 进制格式打印 20 个 4 字节
x /20xb 0xAAAA # 以 16 进制格式打印 20 个字节
x /20s 0xAAAA # 以字符串格式打印
print *0xAAAA # 打印地址处的值
print $rsp # 打印寄存器值

1
2
3
4
5
6
7
8
9
10
vmmap                            # 查看内存映射
heap # 显示堆信息
parseheap # 解析堆结构
vis # 可视化堆块
bins # 显示所有 bin
fastbins # 显示 fastbin
unsortedbin # 显示 unsorted bin
smallbins # 显示 smallbin
largebins # 显示 largebin
tcache # 显示 tcache(glibc 2.26+)

其他常用命令

1
2
3
4
5
6
7
8
9
context                           # 显示当前上下文(寄存器、栈、代码)
break *0x400000 # 在地址处下断点
continue # 继续执行
nexti # 执行下一条汇编指令
stepi # 单步进入(会进入函数)
finish # 执行到当前函数返回
backtrace # 显示调用栈
info registers # 显示所有寄存器
disassemble # 反汇编当前函数

patchelf

patchelf 用于修改 ELF 文件的动态链接器和库依赖,常用于本地调试时使用指定版本的 libc。

1
2
3
4
5
6
7
8
9
10
11
12
# 设置动态链接器
sudo patchelf --set-interpreter ./ld-2.23.so ./binary

# 替换库依赖
sudo patchelf --replace-needed libc.so.6 ./libc-2.23.so ./binary

# 添加库依赖
sudo patchelf --add-needed ./libc-2.23.so ./binary

# 查看当前设置
patchelf --print-interpreter ./binary
patchelf --print-needed ./binary

ROPgadget

ROPgadget 用于在二进制文件中搜索 ROP gadget,是构造 ROP 链的重要工具。

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 搜索所有 gadget
ROPgadget --binary ./binary

# 搜索特定指令
ROPgadget --binary ./binary --only "pop|ret"
ROPgadget --binary ./binary --only "pop rdi"

# 搜索字符串
ROPgadget --binary ./binary --string "/bin/sh"

# 搜索特定字节序列
ROPgadget --binary ./binary --opcode "5fc3" # pop rdi; ret

# 只显示 gadget 地址(不显示指令)
ROPgadget --binary ./binary --only "pop|ret" --ropchain

# 生成完整的 ROP 链(如果支持)
ROPgadget --binary ./binary --ropchain

常用选项

1
2
3
4
5
6
--binary <file>                   # 指定二进制文件
--only <instructions> # 只显示包含特定指令的 gadget
--string <string> # 搜索字符串
--opcode <bytes> # 搜索字节序列
--depth <n> # 设置搜索深度
--badbytes <bytes> # 排除包含特定字节的 gadget

ropper

ropper 是另一个强大的 ROP gadget 搜索工具,功能比 ROPgadget 更强大,支持交互式使用。

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 启动交互模式
ropper

# 在交互模式中搜索
search pop rdi # 搜索包含 "pop rdi" 的 gadget
search /1/ pop # 搜索包含 1 个 pop 的 gadget
search "pop rdi; ret" # 搜索精确的 gadget

# 命令行模式
ropper --file ./binary --search "pop rdi"
ropper --file ./binary --search "pop rdi; ret"

# 生成 ROP 链
ropper --file ./binary --chain "execve"
ropper --file ./binary --chain "mprotect"

# 显示所有 gadget
ropper --file ./binary

# 搜索特定指令
ropper --file ./binary --opcode "5fc3" # pop rdi; ret

高级功能

1
2
3
4
5
6
7
8
9
10
11
12
# 过滤坏字符
ropper --file ./binary --badbytes "000a0d"

# 设置搜索深度
ropper --file ./binary --depth 5

# 导出 gadget 到文件
ropper --file ./binary --output gadgets.txt

# 搜索 syscall gadget
ropper --file ./binary --search "syscall"
ropper --file ./binary --search "int 0x80" # 32位

Seccomp-tools

seccomp-tools 用于分析和转储 seccomp(Secure Computing)沙箱规则,帮助理解程序的系统调用限制。

基本用法

1
2
3
4
5
6
7
8
9
10
11
# 转储 seccomp 规则
seccomp-tools dump ./binary

# 反汇编 seccomp bpf
seccomp-tools disasm <bpf_file>

# 跟踪系统调用
seccomp-tools trace ./binary

# 从 strace 输出中提取规则
strace ./binary 2>&1 | seccomp-tools dump

使用场景

当程序使用 seccomp 限制系统调用时,需要了解哪些系统调用被允许:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 运行程序并查看允许的系统调用
seccomp-tools dump ./binary

# 输出示例:
# line CODE JT JF K
# =================================
# 0000: 0x20 0x00 0x00 0x00000004 A = arch
# 0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007
# 0002: 0x20 0x00 0x00 0x00000000 A = sys_number
# 0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
# 0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007
# 0005: 0x15 0x01 0x00 0x00000000 if (A == read) goto 0007
# 0006: 0x06 0x00 0x00 0x00000000 return KILL
# 0007: 0x06 0x00 0x00 0x7fff0000 return ALLOW

在 pwntools 中使用

1
2
3
4
5
6
from pwn import *

# 检查程序的 seccomp 规则
io = process('./binary')
# 运行 seccomp-tools dump 查看规则
# 根据规则调整 exploit(例如:如果禁止 execve,需要使用 orw)