首先,检查一下程序的保护机制

然后,我们在IDA里分析一下,在add函数里,存在一个null off by one漏洞。

在delete里,会先清空内容,再free

输入函数遇0截断,并且也存在null off by one。

从上述来分析,我们无法同时构造好prev_size和size,因为遇到0就截断了,并且,由于delete时清空了内容,因此也无法利用分步的方法来构造好prev_size。由此,可以使用shrink unsorted bin的方法。问题又来了,当我们shrink unsorted bin后,想要成功从unsorted bin里切割,需要将unsorted bin尾部多余的部位伪造成一个chunk,但是在这里没法实现,因为在free之前。内容已经清空。通过阅读glibc的源码,进一步加深了理解。Malloc的时候,首先尝试查找fastbin,不成功,则查找unsorted bin,如果这个unsorted bin和last_reminder一样,那么就直接从last_rminder里切割,并且切割的时候不会坚检查;否则,则将unsorted bin里的chunk放入对应的bin里面,然后从bin里面拿chunk切割,如果是在bin里面拿chunk切割的话,则会进行unlink,而unlink是会检查下一个chunk的。最后,如果从bin里切割成功,则剩余的部分放入unsorted bin,同时last_reminder也指向这个剩余部分,那么第二次切割时,就可以直接从last_reminder里切割。

综上,我们先构造出一块unsorted bin,然后从unsorted bin里切割一个堆,并且利用这个堆来进行shrink 剩余的部分,这样last_reminder被初始化,以后的切割就不会检查这个unsorted bin下一个chunk的头,直接从last_reminder里切割,由此绕过了unlink。
那么,就比较简单了。
1 | #coding:utf8 |