setcontext 函数exploit

本篇文章主要借鉴自:https://n132.github.io/2019/05/10/2019-05-08-Startctf2019-Heap-master/#setcontext

一个很好用的函数。

setcontext

#include <ucontext.h>

int setcontext(const ucontext_t *ucp);

其作用是用户上下文的设置,所以我们在可以小范围控制执行流已知libc_base但不足以完成我们的目标时可以先跳setcontext+53来扩大控制范围。

感觉非常好用,可以直接控制大部分寄存器和执行流。

<setcontext>:     push   rdi
<setcontext+1>:   lea    rsi,[rdi+0x128]
<setcontext+8>:   xor    edx,edx
<setcontext+10>:  mov    edi,0x2
<setcontext+15>:  mov    r10d,0x8
<setcontext+21>:  mov    eax,0xe
<setcontext+26>:  syscall 
<setcontext+28>:  pop    rdi
<setcontext+29>:  cmp    rax,0xfffffffffffff001
<setcontext+35>:  jae    0x7ffff7a7d520 <setcontext+128>
<setcontext+37>:  mov    rcx,QWORD PTR [rdi+0xe0]
<setcontext+44>:  fldenv [rcx]
<setcontext+46>:  ldmxcsr DWORD PTR [rdi+0x1c0]
<setcontext+53>:  mov    rsp,QWORD PTR [rdi+0xa0]
<setcontext+60>:  mov    rbx,QWORD PTR [rdi+0x80]
<setcontext+67>:  mov    rbp,QWORD PTR [rdi+0x78]
<setcontext+71>:  mov    r12,QWORD PTR [rdi+0x48]
<setcontext+75>:  mov    r13,QWORD PTR [rdi+0x50]
<setcontext+79>:  mov    r14,QWORD PTR [rdi+0x58]
<setcontext+83>:  mov    r15,QWORD PTR [rdi+0x60]
<setcontext+87>:  mov    rcx,QWORD PTR [rdi+0xa8]
<setcontext+94>:  push   rcx
<setcontext+95>:  mov    rsi,QWORD PTR [rdi+0x70]
<setcontext+99>:  mov    rdx,QWORD PTR [rdi+0x88]
<setcontext+106>: mov    rcx,QWORD PTR [rdi+0x98]
<setcontext+113>: mov    r8,QWORD PTR [rdi+0x28]
<setcontext+117>: mov    r9,QWORD PTR [rdi+0x30]
<setcontext+121>: mov    rdi,QWORD PTR [rdi+0x68]
<setcontext+125>: xor    eax,eax
<setcontext+127>: ret    
<setcontext+128>: mov    rcx,QWORD PTR [rip+0x356951]        # 0x7ffff7dd3e78
<setcontext+135>: neg    eax
<setcontext+137>: mov    DWORD PTR fs:[rcx],eax
<setcontext+140>: or     rax,0xffffffffffffffff
<setcontext+144>: ret

setcontext_53

至于为什么要跳到 setcontext+53 这个位置。因为fldenv [rcx]指令会造成程序执行的时候直接crash,所以要避开这个指令。

注意:要构造好rsp的值,因为有 push rcx 指令,如果rsp指向的内存不可访问,则会crash。

构造ucontext_t

可以直接使用 pwntools 的 SigreturnFrame()来构造ucontext_t结构体。

类似于下面这种形式:

# 指定机器的运行模式
context.arch = "amd64"
# 设置寄存器
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = 0
frame.rdx = 0

注意:[rdi+0xa8](被弹到rcx的那个地址)对应的是 frame 框架的 rip 。

也就是说,frame.rip 就是我们执行完setcontext后执行的地址。而 frame.rsp 的值就是我们执行完 frame.rip 后,要执行的值,也就是说我们可以连续控制。

利用思路

一般是用来执行mprotect函数,后注入shellcode。也可以直接用来构造ROP链。