内容简介:本篇文章是该系列的第二篇,第一篇是glibc漏洞利用基础知识。在上一篇文章中我们提到过,堆管理将保留关于空闲块的元数据,以便这些空闲块可以被重新分配。为了补充我在上一篇文章中的说法,我在这篇文章中会提到针对不同大小的空闲块,会有不同类型的链表来管理,即如下这些链表:
本篇文章是该系列的第二篇,第一篇是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的格式:
在这个示例图片中,它也比较了一个非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按照它们分配的顺序进入堆中):
你应该能够很容易地找出最先返回的块。另请注意显示在释放列表中的指针; 这些0x602yyy 在堆块中的值是malloc_chunk-> bk指针。
毫无疑问,你的下一个问题是我们如何让它返回一个我们想要的指针,或者我们如何影响空闲块,比方说,强制返回某个指定的空闲块?当我们“在使用中”时覆盖这些信息然后查看返回哪个fastbin时会发生什么?这里我们提供了下面这个测试方案:
1.释放一些块
2.重新指向fastbins 的malloc_chunk-> bk指针
3.看看哪些可用的块被写入0x4242 (这个0x4242 / 0x4141纯粹是因为我让这个程序对我有所帮助)
我们来看看这些块在内存中的视图:
解释一下。
首先,我用set {size_t} 0x602100 = 0x0000000000602000命令覆盖bk指针。这基本上告诉堆在返回第一个fast bin后(LIFO中的第一个fastbin在0x6020f0位置处),指针应该根据链表指向下一个空闲的fastbin,它位于0x0602000。
下一个截图显示了如何重定向分配; 它不是在最底层的上方分配下一个块,而是一直跳到顶部:
可以清楚地看到,我们只是重定向堆重新分配!链表权现在属于我们!!
你也可以将堆重定向到内存中可写可读部分中的其他位置的伪块。为此,需要做到如下几点:
1.释放所有的fastbins
2.就在第一次重新分配之前; 重新指向首先适合你的伪fastbin的fastbin
例如:set {size_t} 0x602100 = 0x601050 (这会将块的bk指针设置为0x6020f0 )
3.将fast bin的大小设置为可接受的值,这里我只是回收与被替换的fast bin相同的大小,如下所示:set {size_t} 0x601058 = 0x0000000000000051
下面的截图展示了这一点。
我们可以在0x6010yy地址区域中看到一个奇怪的堆块,而其余的块在0x6020yy范围内:
这并不是一个完整的安全漏洞,但它确实让我们更加接近一个漏洞。它还让我们学到了一个重要的小技巧,就是让堆去做一些奇怪的事情。
好了,本文就到这里,我将在下一篇文章中介绍更多关于堆元数据的内容。敬请关注!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 漏洞分析:对CVE-2018-8587(Microsoft Outlook)漏洞的深入分析
- MacOS/iOS CVE-2019-6231 漏洞深入分析
- 由Typecho 深入理解PHP反序列化漏洞
- 深入分析Windows系统DHCP漏洞(CVE-2019-0726)
- 对CVE-2018-8587(Microsoft Outlook)漏洞的深入分析
- Apache Tomcat从文件包含到RCE漏洞原理深入分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Fluent Python
Luciano Ramalho / O'Reilly Media / 2015-8-20 / USD 39.99
Learn how to write idiomatic, effective Python code by leveraging its best features. Python's simplicity quickly lets you become productive with it, but this often means you aren’t using everything th......一起来看看 《Fluent Python》 这本书的介绍吧!