Double Free浅析

最近在研究一些堆上面的漏洞。然后某一天骑自行车在路上跑的时候我突然悟出了Double Free的真谛。
2333好像太中二了一点,我是根据堆溢出的利用方法启发,再结合linux中libc的源码。研究出了double free的利用方法。虽然有关double free的利用技巧已经不是一个秘密。不过好像很少有相关的中文的介绍,所以以一个初学者的角度来讲解一下double free漏洞的利用方法。
如果有错误,希望大家批评指正。Orz

简介

Double Free其实就是同一个指针free两次。虽然一般把它叫做double free。其实只要是free一个指向堆内存的指针都有可能产生可以利用的漏洞
double free的原理其实和堆溢出的原理差不多,都是通过unlink这个双向链表删除的宏来利用的。只是double free需要由自己来伪造整个chunk并且欺骗操作系统。
这里是glibc中有关内存管理的源代码

内存管理介绍

有关内存管理的部分我放在另外的一篇博客上。

传送门

这篇文章首发于乌云知识库。现在我将它发到自己的博客上,我只在这2个地方发过此文章。
转载求写个出处Orz

漏洞的原理

要利用Double Free的漏洞。我们就要让系统进行unlink的操作,达到篡改指针的目的。但是一般的情况下,我们两次释放同一块内存会被操作系统给检测出来,怎么欺骗过操作系统才是最重要的。

我们结合实际的情况来讲解会比较好。这里我自己写了个demo程序,代码发比较长,所以我放在gitcafe上。

因为是自己写自己玩的demo程序,所以这程序是堆漏洞大礼包。用Double Free,heap corruption,use after free这3种方法都用各拿了一次shell
这里我们用Double Free,其他漏洞一律不使用。

这个程序在free的时候很明显的没有检验指针的有效性,而且没有在free之后将野指针清零。而且可以任意的指定每一个chunk的大小。所以可以很容易的构造double free。我们首先构造一个野指针。

malloc(504)
malloc(512)

然后释放这2块内存。这样子我们就可以在距离第一个指针偏移量为0x200的地方有了一个野指针。

img

我们留下了一个野指针p指向偏移为0x200的地方。然后我们需要做的就是伪造chunk。再free野指针p。首先是申请一块更大的内存,大小应该等于我们刚才申请的内存的总和。

malloc(768)

最好和刚才2块内存大小总和一样,如果不一样大也也可以,就是待会伪造第二快内存块的大小的时候,要让伪造的大小等于我们申请的chunk的大小,否则会无法绕过检查。会被系统检查出double free。

然后这是我在第二次申请的内存中填入的内容。

0x0 + 0x1f9 + 0x0804bfc0 - 0xc + 0x0804bfc0 - 0x8 + ‘a’*(0x200-24) + 0x000001f8 + 0x108

现在的chunk就是这个样子了

img

可以看到现在我们在内存中伪造了出了2个chunk。它们的结构就像图中我们看到的样子。首先是第一个chunk的chunk头部分。我们分别填上了0x0和0x1f9代表了前一个chunk正在使用,当前chunk的大小是1f8。然后就是伪造的双向链表指针了。为了绕过unlink中的检查,这里需要稍微构造一下这个双向链表的指针了。payload中的0x0804bfc0位置其实就是存放在.data段中的指针ptr。这样子就可以绕过保护了。

1
2
if (__builtin_expect (FD->bk != P || BK->fd != P, 0))
malloc_printerr (check_action, "corrupted double-linked list", P, AV);

结合而源代码,可以看到现在FD->bk的值正好也是指向我们伪造的chunk的头部分。然后我们在野指针p的前面又伪造了一个chunk头。prve_size部分填0x1f8正好是前一个伪造chunk的大小。然后size部分填的是0x108。这样的话两个chunk正将我们申请的空间填满。然后第二个伪造chunk的size中最低位的flag置为0.这样free指针p的时候,就会将前一个伪造的chunk给unlink。

现在,只要在free一次指针p。就可以触发漏洞了。这时候,我们的操作系统不会报错,而且我们本来正常的指针ptr已经变成了ptr-0xc。这要如果我们如果调用Edit函数来修改这个chunk的话,就可以干各种各样的事情了。

我把完整利用的poc也放在了gitcafe上,如果需要的话可以看看,最终通过ret2kibc的方法拿到的shell.所以只要吧几个函数的地址稍微修改一下,可以在随意的一台机器上使用。PS:没有开PIE保护的。

poc传送门