j师傅牛逼,直接带飞,记录下ddctf的一道pwn题,we_love_free
这道题挺有意思的,巧妙利用vector的扩容机制设置了一个漏洞,我自己解的时候是用unsortedbin attack攻击的cin,赛后还看到了用unlink来unlink自己的骚操作,这里把两种解法都记录下
解法一
vector结构:
1 | 00000000 vector struc ; (sizeof=0x18, mappedto_7) |
vector的扩容规则是1,2,4,8,16,32,依次乘2个元素的时候会先申请新的空间,在把原来的数据拷贝到新申请的空间中,在释放原先的空间,对应申请的堆块大小(加上头部)0x20,0x20,0x30,0x50,0x90…..
漏洞点:
思路为:
- 先
add
16个元素(0x90的堆块),这样调用show
函数的时候,在push 0xAABBCCDD
之后,原先的堆块就会被释放,这样就能有UAF
的效果,先泄露下libc的地址,在调用clear
函数清空,这里调用clear
会触发malloc_consolidate
,所以堆又会变成原来的样子 - 在
add
至少0x20
个元素,每个元素都为one_gadget
,在堆上残留数据,在调用clear
函数清空堆 - 接着在
add
16个元素,调用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:
1 | from pwn import * |
解法二
如果把presize给改成-0x10
,这样unlink的时候,p就会指向自己+0x10偏移处:
1 | /* consolidate backward */ |
我们可以在这里构造好假的fd和bk,这样在free之后就可以改到数据段上的vec结构,连同迭代器也一起改了,这样就可以直接任意地址读写,把vec的begin
改成__free_hook-8
,cur改的比begin
大就好,end也是,然后add数据的时候就可以修改__free_hook
,getshell
exp:
1 | from pwn import * |