2026-4-14-栈迁移
四月 14, 2026
栈迁移
栈迁移题目分析
第一步,为什么要栈迁移?
栈迁移因为可写缓冲区也就是buff 不足以支持完整的RPO链
我们只能将RPO链放到 .bss
.bss解释:.bss是内存上一块内存区域,它的存在是编译器预留了存放未初始化的全局变量/静态变量的位置- 这也是我们平时写代码,为什么存在了未使用的变量会导致报错的原因。
1 | ; Attributes: bp-based frame |
这段汇编代码中,你可能认为buf是.bss地址,这是个常见的错误。
1 | ; __unwind { |
buf 没有被程序主动初始化,既没有清零,也没有赋值,但并不属于.bss,因为其在栈上。
pwntools工具可以直接寻找,不需要手动找
1 | from pwn import * |
output:
1 | (base) ┌──(.venv)(cure㉿LAPTOP-CMAM5D0J)-[~/CTF/pwn/19] |
.bss=0x404020
然后我们即可开始第二步,伪造假栈,迁移原栈
首先我们必须知道 fake_rpb 也就是假栈的地址,是交给leave; ret 去执行的
我们需要让rsp精确落到伪造好的假栈开头
行为:
1 | leave ; mov rsp, rbp ; pop rbp |
例:
1 | leave_ret = 0x4011c8 |
假栈内容
1 | fake_stack = p64(0) # 新 rbp |
1 | fake_rbp = fake_stack_addr = 0x401146 |
ruler =
1 | [fake_rbp + 0x00] = new_rbp |
利用流程总结
本题的整体思路如下:
1. 确认栈空间不足
当前 buf 只有 0x80,不足以支撑完整 ROP 链。
2. 寻找可写区域
使用 .bss 作为假栈区域。
3. 找到 .bss 地址
通过 elf.bss() 获取 .bss 起始地址,再偏移一段距离作为真正使用的假栈区域。
4. 伪造假栈内容
在 .bss 中布置:
- 新 rbp
- 第一个 gadget
- 后续参数
- 后续 ROP 链
5. 控制 saved rbp
把它改成 fake_rbp
6. 控制返回地址
把返回地址改成 leave; ret
7. 执行栈迁移
当 leave; ret 执行后,rsp 就会落到 .bss 上,开始从假栈继续执行。
一句话总结
栈迁移的本质就是:
当前栈空间不够用,于是把 rsp 迁移到 .bss 这种更大、可写的区域中,再从那里继续执行 ROP 链。
而 fake_rbp 的本质,就是:
你希望下一次 leave 执行时,rsp 落到的那个地址。
最近要去准备开发类的比赛了暂放CTF,预留AI补充的思路过程暂时收尾此博客。
查看评论