houseofminho
前言
houseofminho
最早是在宁波赛上遇到的,没想到这玩意给了我迎头痛击。当时老觉得这些过于复杂的堆利用有点钻牛角尖了,实战意义不大,但是现在想想,还是得认真学这些。
这种复杂的堆利用如果一直畏难的话,那我就一直不会有长进,但是啃下来之后却也觉得还能接受了。
题目详情
这是完整题目附件
通过出题人给的源码我们可以发现,我们至始至终最多只能操控一个堆块,并且大小只能是0x40或0x80。尽管题目在0x40的堆块读入时给了0x80的大溢出,但是我们的利用还是有很大麻烦。
有一个很重要而且有趣的点是这道题对于scanf的利用
scanf在收到大量字节输入时会调用malloc来创建缓冲区
而这道题看似scanf只有一个读入数字的处理?怎么让他收到大量字节输入呢
答案是在原来与题目交互时输入的1,2,3前面加上很多个0,这样就会让scanf有一个malloc大量字节后再free的操作
以上有一个前提,就是没有setbuf(stdin,0)
初步利用思路
- 在smallbin内放入多个0x90大小的堆块
- 通过scanf的大malloc来触发将smallbin放入tcachebin的机制,从而利用溢出改fd指针获得任意地址写
那么下一步就是如何获得smallbin了
- 首先smallbin只需要有一个,剩下我们可以通过bk指针在可控的堆上通过布局伪造,即使显示被corrupted,但是将它们放入tcachebin的过程是沿着bk进行且没有检查,所以这样是可以的
- 那么smallbin从哪里来呢,答案是从unsortedbin
- 我们可以先将堆块size改大,放入unsortedbin,再改小size(由于unsortedbin本身就是什么size大小的堆块都有,在此处自然没有对其size的检查)
- 通过scanf的大堆块申请之后,被我们改小size的unsortedbin就会落入smallbin
当然上述都只是相对简化的,实际这题中还有两个点
- 利用unsortedbin伪造smallbin的过程中,在改小了size的unsortedbin下方,我们还需要伪造glibc的保护块来防止出错,而这样我们的可控空间就不够大了。
图中很明显,我们可控的部分是绿色堆块往下0x80的大小,以及蓝色堆块往下数0x80的大小,但是我们必须伪造0x90大小的堆块!而且在0x90大小的堆块下方还需伪造两个哨兵块来防止malloc报错 - 所以在这里还有一个unlink手法,将unsortedbin向上合并0x30的大小以提高伪造利用率。
- 在图中可以看到绿色堆块中的0x31大小的堆块就是准备用来合并的,这样我们利用0x50大小堆块的uaf范围就可以从(0x80-0x48)变成(0x80-0x18),大大增加了伪造的可能性
- 利用unsortedbin伪造smallbin的过程中,在改小了size的unsortedbin下方,我们还需要伪造glibc的保护块来防止出错,而这样我们的可控空间就不够大了。
- 在程序最开始还利用scanf的大堆块写往图中最下方的橙色堆块后方写了一个\x33,也就是3的ascii码。这样的布局可以防止蓝色堆块被free成unsortedbin之后的合并检查出错,因为\x33的prev_in_use位为1,被启用。
我这里也只是简单写一下思路,这题中的很多细节我都讲的比较粗略或者不够完整。
更完整详细的解题思路可以去看看看雪Csome的记录
这是完整exp
1 | from pwn import * |