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…..
漏洞点:

思路为:
- 先
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做好了准备 - 最后只要在
add9 个元素,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 * |