简单讲解通过extend_overlopping来利用fast bin实现任意位置的读写
老话长谈,学习堆溢出,还是基础知识要好,今天就说说我自己总结的extend overlopping ,也就是伪造chunk的长度来欺骗glibc。从而来间接控制任意位置的读写。好了这么说就有点抽象了。我们还是用简单的例子来讲解吧。这个例子选自CTFwiki的一个例子。
1 | int main() |
这个就是一个典型的例子。当修改了第一个chunk的size为0x61之后,系统会把着四个chunk全部假装free掉,又因为这个四个chunk的大小,刚好再fast bin 之间,这个大的chunk就进如了fast bin 。当我们再次malloc的时候我们就能的到这个大块。
好了,道理我们都懂了,要怎么利用呢,找到懂了,要办法利用,这里直接写总结可能都看不懂,所以我们就简单的用一个例子来讲解吧。
题目链接:https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/heap/chunk-extend-shrink/hitcontraning_lab13
拖入IDA,我们会看到这个例子的几个功能。然后我们在仔细分析一下代码。大致的功能我这里总结一下,具体怎么分析程序我就不说了,这里就不乱七八糟的说一堆了。 在create_heap这个函数: 首先会创建一个结构体,这个结构体很简单。
1 | struct heap |
然后存放到heaparray的数组里,这个数组再bss段。 这里就判断出来不能使用unlink漏洞了。为什么不能使用unlink漏洞,这个就仔细看看我上篇文章写的总结。具体不懂再问我。 然后我们可以控制输入的长度,而且可以实现任意的输入,没有任何限制条件。 然后我们发现这里可以实现堆溢出。然后就没有其他的了。
接下来看edit_heap这个函数 这个函数就是让我们输入一个索引值 然后根据这个索引值,编辑相应结构体的content所指向的内存。 show_heap: 这里就根据我们的create输入的,打印出来heap这个结构体和结构体里content指向的内存。 Delete_heap: 这个函数就是根据我们输入的索引值来free掉相应结构体的content所指向的内存和相应结构体所占用的内存。
整个程序的流程大致就是这么回事,很简单,也很好懂。但是我们现在要思考的是怎么利用着堆溢出的漏洞。
我们前面刚刚提到了,extend_overlopping。刚好我们这一题就可以利用堆溢出来实现这个漏洞。很简单的利用。 在我们动态调试的时候,我们能看到,heap结构体开辟的内存和content开辟的内存是相邻的,具体如下:
1 | 0x13f7000: 0x0000000000000000 0x0000000000000021 |
这里我们就有思路了,我们创建两个chunk,然后我们伪造第二个chunk大小,然后假装释放掉,最后我们实现任意位置的都和写,我现在这么说,可能还是不懂。但是没关系,看我下面的一步步的操作就ok了。
首先我们create_heap两个结构体。第一个申请大小为0x18,第二个为0x10 内存分布如下:
1 | 0x13f7000: 0x0000000000000000 0x0000000000000021 |
现在我们通过edit来覆盖0x13f7048地址的值。 当我们修改第一个结构体的时候,我们 入’a’*24+’\x24’。这个时候我们就将第二个结构体的伪装完成了,当我们通过delete_heap的时候,先free掉0x13f7068这个content。然后再free掉第二个结构体。这个时候会出现问题。我们仔细回忆fast bin的回收机制。Fast bin有十个,每个bin的大小不一样。当回收的时候,相应的大小进入相应的fast bin的链尾。然后我们再回到这里看一看。0x13f7068进入大小为0x20的fast bin的链尾。但是在这里0x13f7048本应该也是进入0x20的fast bin的链尾,可是我们改掉了该size,所以0x13f7048进入了0x40的fast bin中。这个时候出现问题了,0x0x13f7068进入了两个bin中,当我们再create_heap,一次0x30的结构体的时候,这个时候函数会先分配一个0x20大小的chunk来存放结构体,这个大小刚好属于0x20 的fast bin,也就是将0x13f7068分配给了这个结构体,然后再申请0x40的大小的chunk来存放content。这个0x40的chunk也就是从刚才的0x40fast bin的链尾获取,也就是0x13f7048这块地方。这个时候恰恰好,0x13f7048-0x13f7088刚刚让0x13f7068-0x13f7088在里面了。也就是我们可以通过edit_heap功能来改写content指针了,可以实现任意位置的写。当edit任意地址之后,我们可以通过show_heap功能来实现任意位置的读。 这个时候就可以实现任意位置的读和写。
很简单的漏洞,还是要基础打牢固。通过伪造大小来欺骗glibc的分配机制。
好了,大致就说到这里了,有什么不懂得或者我写错了得地方,望各位大佬斧正。