Glibc堆漏洞利用基础-深入理解ptmalloc2 part2

DarkEye 系统安全 2019年1月22日发布
Favorite收藏

导语:在上一篇文章中我们提到过,堆管理将保留关于空闲块的元数据,以便这些空闲块可以被重新分配。为了补充我在上一篇文章中的说法,我在这篇文章中会提到针对不同大小的空闲块,会有不同类型的链表来管理。

本篇文章是该系列的第二篇,第一篇是glibc漏洞利用基础知识。

在上一篇文章中我们提到过,堆管理将保留关于空闲块的元数据,以便这些空闲块可以被重新分配。为了补充我在上一篇文章中的说法,我在这篇文章中会提到针对不同大小的空闲块,会有不同类型的链表来管理,即如下这些链表:

· Unsorted Bin-这个链表用来临时保存那些不属于Fast,Large或者Small bin分类的块。在这里引用某大牛论文中关于此的说法:当释放不在fastbin范围内的块时,这些块就被划到了未分类的bin中,而不会划分到small bins或者large bins中。

论文下载地址:https://loccs.sjtu.edu.cn/wiki/lib/exe/fetch.php?media=gossip:overview:ptmalloc_camera.pdf

· Small bins-正如其他链表一样,这只是另一个链表或者是一组链表,用来保存特定大小的空闲堆块。而这个大小的阈值可能因架构和glibc实现或者是build不同而有所变化。不过,最基本的一点是他们比Fast Bins大,比Large Bins小。我会在以后的文章中再来讲述关于这个的更多细节。

· Large Bins-比最大值还大的块,我现在搞得还不是很明白,所以也留在以后的文章中再讲。

· Fast Bins-本文的重点,保存的是所有小于特定最大块的空闲块。

这里之所以选择讲解Fastbin中的块,是因为它们是作为malloc_chunk基本格式的扩展,而malloc_chunk格式用于普通的未分类的或正常大小的堆块,并且它们也有一些很不错的技巧我们可以尝试一下。所以,本文不会讲解large chunks,只是目前不讲,不过以后等我有了足够的数据,我还是会分析一波。

好了,不叨叨了,开始讲fastbins吧。

Fast Bin格式

Fastbins其实也是内存中的一个堆块。

Fastbins是为小的内存对象保留的(小的结构和字符串)。fastbin的思想就是,这些块大小是能够从常规的计算开销中获得一些优势的,如果不使用的话,那么你使用的仅仅是符合所请求大小的小内存区域的简单链表。根据目前关于堆的研究,Fastbins是不同大小的fast bins的集合,(所以不只是简单的单一链表,对于每种大小的组,可能会有很多fastbins在操作),这里再引用一篇论文中的观点:

“Fastbin是一种针对性能和局部缓存进行了优化的特殊设计。它是一个单独链表,类似于Windows的look aside表格,其中相同大小的空闲块以LIFO方式链接。不同fastbins的块大小各不相同。在arena中有共有10个fastbins,但默认情况下使用前7个,在32位系统上为16到64个字节,在64位系统上为32到128个字节 “

论文地址:

https://loccs.sjtu.edu.cn/wiki/lib/exe/fetch.php?media=gossip:overview:ptmalloc_camera.pdf

还有一点我要提醒的是,如果fastbins被释放了,它们是不会合并的。在glibc- [版本] /malloc/malloc.c的文档中有更多关于fastbins的精彩内容。我建议大家可以去通读一遍 –  我这里就不进行复制了。  

好了,关于fastbins的介绍部分就扯这么多了,现在我们来看看它们到底是什么东西以及它们的工作原理。

关于fastbins大小的阈值在malloc/malloc.c中进行了定义。就像glibc-2.23中一样,它的定义是这样的:MAX_FAST_SIZE   = (SIZE_SZ * 80)/ 4,最大值为80个字节。因此,任何低于80字节的数据都会被分配到fastbins中。

下图是内存中fastbins的一个链表,可以很好的展示fastbins的格式:

1.png

在这个示例图片中,它也比较了一个非fastbins的块,只是一个普通的大块,大小为0xb0  (内存指针分配的第一个块,位置是0x602010) – 这是为了更加清楚的显示格式之间的区别。

在图片左侧,你可以看到“live”的fastbin块(从0x6020b0开始)。除了它们的大小之外,在这种状态下,不能把它们像fastbin一样分配出去。在图片右侧,你可以看到被释放的空闲fastbins块; 这里需要注意的一个关键事项是它们有一个后向指针(形成一个fastbin块的链表),指示下一个空闲fastbins块的位置。

还有一点你可能也会注意到,这个例子中:在内存中彼此相邻的fastbin'd块是空闲的; 但是大小字段都没有重叠,也没有块合并在一起。如前所述,他们不会合并。

OK,现在我们知道它们在内存中的格式,我们再来谈谈另一个重要机制,也就是fastbin first fit。

Fastbin First Fit

fastbins的重新分配规则略有不同。当他们进行重新分配时,他们位于后进先出的队列中。这意味着,如果我们一个接一个的将它们释放出来,那么第一个返回重新分配的块将会是系列中最后一个释放的。

在下面的内存分布图片中,图片左边显示了在调用malloc之前和所有fastbin块被释放之后的堆状态。右边是第二个malloc(或重新分配)被调用后的堆。所以我们基本上能够看到哪些fastbin块被返回和使用,以及它们的顺序(主要是因为我使用程序将一些信息写入堆块 – 每个分配写入0xAA,0xBB按照它们分配的顺序进入堆中):

2.png

你应该能够很容易地找出最先返回的块。另请注意显示在释放列表中的指针; 这些0x602yyy  在堆块中的值是malloc_chunk-> bk指针。

毫无疑问,你的下一个问题是我们如何让它返回一个我们想要的指针,或者我们如何影响空闲块,比方说,强制返回某个指定的空闲块?当我们“在使用中”时覆盖这些信息然后查看返回哪个fastbin时会发生什么?这里我们提供了下面这个测试方案:

1.释放一些块

2.重新指向fastbins 的malloc_chunk-> bk指针

3.看看哪些可用的块被写入0x4242 (这个0x4242 / 0x4141纯粹是因为我让这个程序对我有所帮助)

我们来看看这些块在内存中的视图:

3.png

解释一下。

首先,我用set {size_t} 0x602100 = 0x0000000000602000命令覆盖bk指针。这基本上告诉堆在返回第一个fast bin后(LIFO中的第一个fastbin在0x6020f0位置处),指针应该根据链表指向下一个空闲的fastbin,它位于0x0602000。

下一个截图显示了如何重定向分配; 它不是在最底层的上方分配下一个块,而是一直跳到顶部:

4.png

可以清楚地看到,我们只是重定向堆重新分配!链表权现在属于我们!!

你也可以将堆重定向到内存中可写可读部分中的其他位置的伪块。为此,需要做到如下几点:

1.释放所有的fastbins

2.就在第一次重新分配之前; 重新指向首先适合你的伪fastbin的fastbin

例如:set {size_t} 0x602100 = 0x601050 (这会将块的bk指针设置为0x6020f0 )

3.将fast bin的大小设置为可接受的值,这里我只是回收与被替换的fast bin相同的大小,如下所示:set {size_t} 0x601058 = 0x0000000000000051

下面的截图展示了这一点。

我们可以在0x6010yy地址区域中看到一个奇怪的堆块,而其余的块在0x6020yy范围内:

5.png

这并不是一个完整的安全漏洞,但它确实让我们更加接近一个漏洞。它还让我们学到了一个重要的小技巧,就是让堆去做一些奇怪的事情。

好了,本文就到这里,我将在下一篇文章中介绍更多关于堆元数据的内容。敬请关注!

本文翻译自:https://blog.k3170makan.com/2018/12/glibc-heap-exploitation-basics.html如若转载,请注明原文地址: https://www.4hou.com/system/15486.html
点赞 0
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论