用途比较大的一个办法 通常适用的是开启了沙盒的堆 然后用来构造orw链
不过libc2.29是一个比较大的分水岭 前后的版本关于setcontext的利用不一样
libc2.27
.text:0000000000052070 public setcontext ; weak .text:0000000000052070 setcontext proc near ; CODE XREF: sub_586B0+C↓p .text:0000000000052070 ; DATA XREF: LOAD:0000000000009018↑o .text:0000000000052070 ; __unwind { .text:0000000000052070 push rdi .text:0000000000052071 lea rsi, [rdi+128h] ; nset .text:0000000000052078 xor edx, edx ; oset .text:000000000005207A mov edi, 2 ; how .text:000000000005207F mov r10d, 8 ; sigsetsize .text:0000000000052085 mov eax, 0Eh .text:000000000005208A syscall ; LINUX - sys_rt_sigprocmask .text:000000000005208C pop rdi .text:000000000005208D cmp rax, 0FFFFFFFFFFFFF001h .text:0000000000052093 jnb short loc_520F0 .text:0000000000052095 mov rcx, [rdi+0E0h] .text:000000000005209C fldenv byte ptr [rcx] .text:000000000005209E ldmxcsr dword ptr [rdi+1C0h] .text:00000000000520A5 mov rsp, [rdi+0A0h] .text:00000000000520AC mov rbx, [rdi+80h] .text:00000000000520B3 mov rbp, [rdi+78h] .text:00000000000520B7 mov r12, [rdi+48h] .text:00000000000520BB mov r13, [rdi+50h] .text:00000000000520BF mov r14, [rdi+58h] .text:00000000000520C3 mov r15, [rdi+60h] .text:00000000000520C7 mov rcx, [rdi+0A8h] .text:00000000000520CE push rcx .text:00000000000520CF mov rsi, [rdi+70h] .text:00000000000520D3 mov rdx, [rdi+88h] .text:00000000000520DA mov rcx, [rdi+98h] .text:00000000000520E1 mov r8, [rdi+28h] .text:00000000000520E5 mov r9, [rdi+30h] .text:00000000000520E9 mov rdi, [rdi+68h] .text:00000000000520E9 ; } .text:00000000000520ED ; __unwind { .text:00000000000520ED xor eax, eax .text:00000000000520EF retn
|
你可以在libc文件中搜索函数setcontext找到这一串汇编
前面的指令没啥用 重点是 .text:00000000000520A5 mov rsp, [rdi+0A0h] 这一句
rsp寄存器的值由rdi寄存器决定的 rdi可太好控制了 我们执行free函数 rdi的值就是被释放的chunk的用户区地址
但是光控制rsp寄存器也没用 他不执行啊 还得再把rop链弹到rip寄存器里面
那就要用到ret指令了是吧 往下看一看 找到了 .text:00000000000520CE push rcx
把rcx的值入栈 rcx能不能控制啊 能啊 .text:00000000000520C7 mov rcx, [rdi+0A8h]
那就意味着 我们可以利用这三行 实现一个栈迁移 劫持程序执行流
并且所需要的只是覆盖free_hook
演示的话 可以看一看wp分类里的Ciscn复现里的一题
libc2.29
2.29对于setcontext进行了优化 不好利用了
.text:0000000000055E00 public setcontext ; weak .text:0000000000055E00 setcontext proc near ; CODE XREF: sub_5C160+C↓p .text:0000000000055E00 ; DATA XREF: LOAD:000000000000C6D8↑o .text:0000000000055E00 ; __unwind { .text:0000000000055E00 push rdi .text:0000000000055E01 lea rsi, [rdi+128h] ; nset .text:0000000000055E08 xor edx, edx ; oset .text:0000000000055E0A mov edi, 2 ; how .text:0000000000055E0F mov r10d, 8 ; sigsetsize .text:0000000000055E15 mov eax, 0Eh .text:0000000000055E1A syscall ; LINUX - sys_rt_sigprocmask .text:0000000000055E1C pop rdx .text:0000000000055E1D cmp rax, 0FFFFFFFFFFFFF001h .text:0000000000055E23 jnb short loc_55E80 .text:0000000000055E25 mov rcx, [rdx+0E0h] .text:0000000000055E2C fldenv byte ptr [rcx] .text:0000000000055E2E ldmxcsr dword ptr [rdx+1C0h] .text:0000000000055E35 mov rsp, [rdx+0A0h] .text:0000000000055E3C mov rbx, [rdx+80h] .text:0000000000055E43 mov rbp, [rdx+78h] .text:0000000000055E47 mov r12, [rdx+48h] .text:0000000000055E4B mov r13, [rdx+50h] .text:0000000000055E4F mov r14, [rdx+58h] .text:0000000000055E53 mov r15, [rdx+60h] .text:0000000000055E57 mov rcx, [rdx+0A8h] .text:0000000000055E5E push rcx .text:0000000000055E5F mov rsi, [rdx+70h] .text:0000000000055E63 mov rdi, [rdx+68h] .text:0000000000055E67 mov rcx, [rdx+98h] .text:0000000000055E6E mov r8, [rdx+28h] .text:0000000000055E72 mov r9, [rdx+30h] .text:0000000000055E76 mov rdx, [rdx+88h] .text:0000000000055E76 ; } .text:0000000000055E7D ; __unwind { .text:0000000000055E7D xor eax, eax .text:0000000000055E7F retn
|
你可以看到 变成rdx寻址了 不过也不碍事 还是有办法解决
介绍一个新的工具 ropper 其可以查询libc文件中的一些gadget
ropper -f libc文件路径 --search '指令'
|
就比如此时我们想要 可以修改rdx值的gadget
找到了很多串 远不止图片上这些
rdi寄存器还是很好控制的 所以我们想的是利用rdi控制rdx 利用rdx控制rsp 这样利用rdx做一个中间商
那就找呗 找啊找啊 找到下面这串
前面的mov 就不提了 可以修改rdx的值 最后的call才是关键呐
rdx此时已经被我们操控了 那么[rdx+0x20]也是可被控制的 这里填入setcontext的地址不就好了 此时rdx的值已经被控制了 所以rsp也可以 那么就跟上面一样了
实战利用在wp分类中的hgame2023