-
-
[原创]看雪6月 京东 2018CTF 第九题——羞耻player pwn
-
发表于: 2018-7-3 15:14 3212
-
第一次做C++的pwn,然后做的时候走了点弯路,做完之后发现此题其实并不难。。。所以打算把心路历程记录一下,总结经验以免以后掉进同样的坑。。。
这次C++的struct没弄好,浪费了好多时间,IDA一直不支持C++的类,所以特别蛋疼。。。这次是拿union
搞的,把所有类放在一个共用体,弄完之后发现可读性极差。。。其实感觉最好还是把父类作为一个成员放在最前面(这里的话只有虚表),然后后面放其他子类的成员。。。
漏洞点在subtitle_init 0x26D0
函数中
可见,当a1->length + buf <= 400
,但是buf
是一个很大的无符号数0xffffffff
时,存在整形溢出,能过前面<=400
的检查,也能分配一个正常大小的堆。但是在read(0, (char *)dest + a1->length, buf)
时,相当于执行了read(0, (char *)dest + a1->length, 0xffffffff)
,存在堆溢出!
打开程序,发现bins里面并不是空的,有很多chunks,可能是因为C++的原因吧。这很不方便我们的利用,所以先通过不停地分配clips来把这些bins清空
这个/bin/sh
没用的。。。不管他。。。
一开始没看到read之后把size字段重置了,以为那样直接就能leak。。(盲人CTF,bestCTF
首先是要泄露libc的基址,也许要通过虚表地址泄露程序的基址,然后leak需要存在一个UAF,或者overlap chunk,所以要把溢出转换成这种东西。
然后这个我想了一段时间,最后觉得还是用null byte poisoning的思路比较合适。
这个利用方法不详细说了,不知道可以看看上面shellphish的how2heap。
然后这里要注意,null byte poisoning要让3个非fastbin的chunk互相连接,而这道题会先new
一个类的对象,然后在初始化函数里面再new
其data,所以直接从top chunk取的话没法保证data互相连接,所以要预先对堆做一点处理。还有就是,这题有内存泄露,delete
掉类的时候只delete
了data没有delete
这个类。
怎么预先处理,就是让类的new
从fastbin里面拿就好了,很简单,所以预先先放几个0x60
的chunks在fastbin即可。(Video类大小为0x50)
这个时候,再create_video
只要data字段不会被分到0x60的chunk,类就会从fastbin里拿,而data就会从topchunk里面拿,这样就能有null byte poison的利用条件了。
接下来便是null byte poison利用,基本上跟how2heap上面差不多。首先新建一个subtitle
,然后这个的类和data都会从topchunk里面取,其data的chunk作为chunk a,然后chunk b2先是用来作为一个video的data,再分配一个video的chunk在相同的位置,同时后面也有一个unsorted bin,所以一下子可以把程序基址和libc都leak出来。注意最后一个chunk很重要,不然就不是unsorted bin而是topchunk了,这样libc就leak不出来
然后对堆做一些清理,进行下一阶段的利用
本来想溢出盖指针实现任意写这样直接利用的,就不用攻击堆管理器了比较简单,然后能直接改data字段的数据结构也就只有subtitle,所以就想通过subtitle那个整形溢出直接溢出他自己的类对象,改写指针到__free_hook
,然后发现不行,因为subtitle_init 0x26D0
在后面会把data
字段delete掉,这个时候会delete掉__free_hook
的地址,直接出错。。。
然后试着构造一个unsorted bin overlap chunk,就是覆盖unsorted bin的头延伸chunk大小,同时在相应新大小的尾部也要有正确的prev_size
和size
,这能使得unsorted bin的chunk跟subtitle的类重合,再次new
就可以重写subtitle
的类,然后就快成功了,我在subtitle_edit 295A
突然发现了这行代码。。。
小于等于4。。小于等于4。。。也就是说这个执行了一定会退出。。。看到这里有种想打死出题人的冲动。。。
所以还是攻击堆管理器吧(为什么早不这么做呢),可以fastbin attack写__malloc_hook
到one_gadget。。这个具体原理说一下,就是在__malloc_hook
前有一个0x7fxxxxxxxxxx
的地址,后面紧随一个0,然后我们可以利用这个0x7f做一个伪造的0x70 fastbin chunk(思考在小端情况下这两个数在内存中的布局),可以把在0x70的fastbin的fd指针写成libc_addr + e.symbols["__malloc_hook"] - 3 - 0x10
,这样malloc两次0x70就能覆盖__malloc_hook
了。这个利用的是libc在分配fastbin中的free chunk时只会检查size,而且不会检查低4位,什么prev size,align和next chunk都不会检查,所以可以这么利用。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!