ret2all详细分析与总结
最近高本版only_read的题目很多,不管是有输出还是无输出,各种形式下。ret2all都能中的各种方法都能起到作用,因此复现一下这个手法。感谢YX-hueimie师傅出的那么棒的题目,在复现中温故而知新了许多知识了。

这里就是给了rread函数的返回地址和保存的旧的rbp的值,后面mprotect限制不能修改这个rbp的值。开启沙箱。关闭标准错误。
沙箱的话
read和write的分支全禁,留下本体,read的第一个参数不能大于等于1,write的第一个参数只能等于2,但是后面又close(2),需要dup2(1, 2)更改fd才能再调用write

vuln中的read存在栈溢出可以溢出0x28

shadow函数限制了前0x60字节为LOVE中的内容,不能修改旧的rbp的值和ret的值
所有真正溢出的只有0x18
1 | |

溢出可以修改vuln中的旧的rbp的值


vuln执行完leave_ret后返回main中还是执行leave_ret,这里联系的leave_ret可以造成栈迁移,因此我们刚刚的溢出,将vuln的rbp的值改成0x7fffb01c6e70,栈迁移后rip旧变成了0x7fffb01c6e70 + 8 即为read_addr,rbp中为0x7fffb01c6e90
控制了rbp就是控制了read的rsi,可以控制read读的地址

构造好read,第二段读入
1 | |

这里涉及到几个点,首先是覆盖read的返回地址,达成栈返回。在调用read的时候会将返回地址压栈,我们可以修改这个返回地址达到劫持程序流但是可以不用经过shadow检测。
然后就是这里的0x7ffd1ac556b8这里的mov edi, eax是libc中的地址,是栈中常见的libc地址,距离这里附近有一个syscall,我们利用溢出将这个地址最后两位改成ec后变成syscall后方便后面srop的利用

后续的栈风水为什么这样,画个图来表示吧,执行完read之后

(图中有误,应该是rbp+0x100,RBP+0xf0-0x60)
1 | |

这段栈风水,准备读入srop的参数,但是有检测,所以我们先读一段正常的修改read的返回地址,栈返回来绕过shadow
1 | |
这里0x60读入的数据是srop参数,0x60后面的数据可以rop,修改read的返回地址为leave_ret到去执行read,这样可以绕过检测

这里读入参数从第二行开始是从rdi开始对应signal frame中得rdi至err,其中uc_flags字段需要设置为0cs/gs/fs字段一般设置为0x33&fpstate字段需要设置为0。或者一个可读地址

(借用hueimie师傅的图)
1 | |
读入15字节,在没有gadgets可以依靠这个来控制rax寄存器,用于后面栈迁移到syscall处系统调用sigreturn,执行pop_rbp_ret可以用于抬栈,执行leave_ret

leave_ret指向完毕后会执行rt_sigreturn

这次srop没有进行相关的系统调用,更多的是设置好参数为了系统调用做准备。rip = read_addr2这里执行完后会直接call read,执行read(0,RBP+0x30,0x200)rbp = RBP + 0x65rsp = RBP + 0x40
1 | |
接下来重新读入srop参数
由于我们将rsp设置为RBP+0x40,call read会将read的返回地址压栈,保存在RBP+0x38


因此我们读入的add_rbp_3d_ebx就是返回地址,直接开始rop
因为刚刚srop,rbp = RBP + 0x65,rbx = 0x6edca这个偏移
执行完add_rbp_3d_ebx后就变成新的syscall_ret了


之后就是执行read,读入的地方在RBP+0x49
1 | |

再次栈迁移调用执行rt_sigreturn,设置好寄存器rbp = RBP+0x68rsp = RBP+0x28rip = retsyscall后ret,pop_rip会再次调用syscall_ret,从而完成dup(1,2)的系统调用,ret到leave,迁移到下面的read再次读入
执行的read(0,0xd0-0x60,0x88)
执行完read时,会将返回地址压栈压到RBP+0x70
所以read完之后直接执行rop
随后也是读入15字节,来执行syscall
1 | |
和上次调用dup(1.2)原理一致
这里调用write(2,RBP+0x28,0x200)
设置rip = retrsp = RBP+0x28rbp = RBP + 0xe8
因为rbp = RBP + 0xe8,执行完syscall后将会leave_ret迁移到read_addr3
执行read(0,RBP+0x28,0x200)
这也是为什么要设置0x200的原因,为了这里方便转read
1 | |
这里read的返回地址为RBP+0xf0,后面在跟上orw的rop

exp
1 | |
参考:ret2all - 飞书云文档
LilCTF pwn ret2all-CSDN博客
- 标题: ret2all详细分析与总结
- 作者: heart22
- 创建于 : 2025-11-03 14:29:56
- 更新于 : 2025-11-03 14:31:28
- 链接: https://heart22.top/2025/11/03/ret2all详细分析与总结/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。