当遇到堆题禁用execve时我们就需要用ORW的方法来读取flag,那么堆题如何实现栈迁移来进行ORW就成了一个问题,而利用setcontext是解决这个问题的一个方案
首先来了解什么是setcontext?
setcontext是libc中的一个函数,而它的汇编代码中含有大量的 mov <寄存器>
这类汇编语句,如下图(注:setcontext以glibc2.29为分界线,2.29以下和2.29及以上有较大不同
):
上图是glibc2.27中的 setcontext
的汇编部分,可以看到其中有非常多的控制寄存器的mov指令,它们都利用 rdi+<偏移值>
来获取具体的数值,所以如果我们可以控制 rdi寄存器
随后将程序跳转到 setcontext+53(也就是图中mov rsp,[rdi+0xa0h]的位置)
这样我们就可以控制包括 rip
rsp
这两个重要寄存器,
基本思路
控制执行流之后就有两种思路:
- 是直接控制程序执行流去执行
ROP链
- 是先用
mprotect
函数开辟一段可读可写可执行的空间
再跳到上面去执行shellcode
这里我们主要讲解执行ROP链
打ORW
的思路:
控制 rsp寄存器
到我们布置好 ROP的地址
,然后控制 rip
为 ret地址
如何控制rip并开始ORW?
通过观察上图发现最后一条指令是ret
而其中有一个push rcx
的操作,因此可以判断ret
返回的地方就是rcx中存储的地址
那么此时栈中的情况就是下面的这样
ORW部分的代码
... ...
ORW部分的代码
rcx中的值 <-- rsp
-----我是分割线-----
ret指令 <-- rip
而setcontext
最后是一个ret指令
那么就是
ORW部分的代码
... ...
ORW部分的代码 <-- rsp
-----我是分割线-----
rcx中存放的指令 <-- rip
那么为了能够开始我们的ORW,所以我们需要控制rcx
为ret指令的地址
也就是控制rdi+0xa8h
这个地方为ret指令的地址
glibc2.29之前的一般利用思路:
1.想办法修改free_hook为setcontext+53
2.申请一个chunk1
chunk1_usr_addr+0xa0=rsp迁移地址;
chunk1_usr_addr+0xa8=ret指令地址;
3.申请一个chunk2
chunk2中存放ORW的ROP链,同时这也是rsp需要迁移的地方
4. free(chunk1) 此时的rdi恰好指向chunk_usr_addr,然后可以触发后续一些列的东西
glibc2.29之后的改变
下面来看看glibc2.29之后setcontext做出了哪些改变
调整:从rdi+偏移
变成了rdx+偏移
而rdi+偏移
变成了rdx+偏移
这是一个很大的改变,因为我们打堆题一般利用setcontext
的思路是修改free_hook
为setcontext+53
,然后这个时候rdi
恰好指向了 chunk_usr_addr
,但是如果从 rdi
到了 rdx
,那么我们该如何控制 rdx
就成了一个问题
由于在free
的时候我们可以控制的只有rdi
那么我们就需要一个既可以通过rdi
来控制rdx
,又可以通过rdi
来控制rip
的gadget
那么真的会有这样的gadget吗?(有的兄弟,有的)
在glibc2.29中有类似这样的gadget,既可以控制rdx,最后又可以控制rip
mov rdx, [rdi+0x8]; mov rax, [rdi]; mov rdi, rdx; jmp rax;
mov rdx, [rdi+0x8]; mov [rsp], rax; call qword ptr [rdx+0x20];
这里我们就简单讲一下第二个gadget要咋用
一般我们需要构造三个堆块,三个堆块的作用分别如下
将free_hook赋值为上面mov rdx,qword ptr [rdi+8];
chunk1:
prev_size, size
setcontext+53, rdi_addr[一般是chunk2_usr_data-0xa0] (这里需要计算好,rdi+0xa0的位置是rsp_addr也就是chunk3_usr_data,rdi+0xa8得是rip的地址[一般放ret])
chunk2:
orw_addr(chunk3_usr_data), ret_addr
chunk3:
prev_size, size
... ... ... ...
pop_r_ret, XXXX --> orw 的ROP链
然后再glibc2.31的setcontext再次做出了调整 mov rsp, [rdx+0xa0h]
的位置变成了setcontext+61
但是这个改变并不算大,但是在glibc2.31中上面我们发现的两个牛逼gadget被制裁了,只剩下一个了(泪目了,老铁)
mov rdx, [rdi+0x8]; mov [rsp], rax; call qword ptr [rdx+0x20];
参考:
文章 - srop搭配高低版本的setcontext - 先知社区
setcontext+orw - 狒猩橙 - 博客园