SROP 链利用
1)BUUCTF-ciscn_2019_es_7(BABY_SROP)


发现这里 buf 是写在栈上的,我们需要自己去寻找栈上的地址
ubuntu18,先换一下 2.27 的 libc, 发现有很明显的系统调用以及栈溢出,觉得是 SROP
我们知道 buf 的值是存入 rsi 的,我们可以通过 rsi 的变化去计算输入的东西压入栈后的偏移:
看一下初始的 RSI 值:
c 运行,之后输入 aaaa 去看一下 RSI,计算偏移: 0xe08 - 0xcf0 = 0x118
先明确思路,我们需要构造 execve(‘/bin/sh\x00, NULL, NULL’);
先尝试泄露输入的数据存入栈上的地址:先截取 32 位,再截取 8 位去获取栈上面的地址:
1 | p.send(b'/bin/sh\x00' + b'a'*8 + p64(rax)) |
1 | from pwn import * |
2)BUUCTF-rootersctf_2019_srop
1 | ; Segment type: Pure code |
没有 main 函数,
整体攻击思路:
- 第一次利用栈溢出 -> 构造 sigreturn 假帧 -> 让程序执行一次 read(0, buf, 0x400)
- 第二次把 /bin/sh\x00 + 新的帧写入到 buf 区域
- 触发第二次 sigreturn -> 执行 execve(“/bin/sh”, 0, 0)
1 | [栈溢出] |
1 | from pwn import * |
- b’a’ * (0x80 + 8):填充到返回地址(典型栈溢出偏移 0x88)
- p64(poprax_addr) → p64(15):把 rax 设成 15(对应 rt_sigreturn)自己构造 gadgets
- 后面直接跟上伪造的 SigreturnFrame 结构体
当执行 rt_sigreturn(syscall nr=15)时,内核会把我们伪造的 frame 里的寄存器值恢复出来,于是:
- rax ← 0(SYS_read)
- rdi ← 0, rsi ← 0x402000, rdx ← 0x400
- rip ← 0x401033(syscall; ret)
于是程序就执行了:
1 | read(0, 0x402000, 1024); |
之后继续利用 SROP 构造 execve(“/bin/sh”);
1 | frame.rax = constants.SYS_execve # rax = 59 |
b’a’ * 0x8:
- 这里的 8 字节 不是整个 buffer,而是你之前 read 的数据中 覆盖返回地址前的填充。
- 你第一次 read 写入了 0x400 字节,第二次 payload2 开始是对第一次写入内存中位置的覆盖。
- 因为你的 SigreturnFrame 指定了 rbp = buf,所以栈顶偏移只需要 8 字节就能到返回地址
0x200 是随意规定的,只要 确保 /bin/sh\x00 位于 frame 后、并和 frame.rdi 对应 即可
总 exp:
1 | from pwn import * |
根据两道题说一下 buf:


两个 buf 虽然都是缓冲区,但是由于存放位置不同,导致一个需要泄露地址,一个不需要。
1)的 buf 在栈上,是函数 vuln 的局部变量,每次函数调用都会重新分配地址,不能写死。
2)的 buf 在.data 段,程序运行之前就已经写进去了,是固定的,是全局静态变量,不会变,可以写死。
更新: 2026-04-10 10:37:52
原文: https://www.yuque.com/idcm/wnemg9/gz84blqg6044m0yq