本来想用docker实现的,装了ubuntu 16.04之后发现kali开不开了,查了下才知道docker启用了一种叫HYPER V的东西,和VM冲突了。。这俩不能同时开。
没想到还有How2heap这种好东西,对我这种堆问题的苦手帮助很大。从Fastbin的DoubleFree开始,先来看看Fastbin的漏洞。
Fastbin Double Free(dup)
这是我们后面要谈的漏洞操作的基础。Fastbin中chunk的prev_inuse位不会被置空,这意味着我们可以多次释放同一个物理chunk从而在fastbin的逻辑链表中插入多个相同物理地址的chunk进行利用。引用CTF Wiki的说法:
Fastbin Double Free 是指 fastbin 的 chunk 可以被多次释放,因此可以在 fastbin 链表中存在多次。这样导致的后果是多次分配可以从 fastbin 链表中取出同一个堆块,相当于多个指针指向同一个堆块,结合堆块的数据内容可以实现类似于类型混淆 (type confused) 的效果。
Fastbin Double Free 能够成功利用主要有两部分的原因:
- fastbin 的堆块被释放后 next_chunk 的 pre_inuse 位不会被清空
- fastbin 在执行 free 的时候仅验证了 main_arena 直接指向的块,即链表指针头部的块。对于链表后面的块,并没有进行验证。——CTF Wiki
由于只对main_arena直接连接的chunk进行检查,所以在申请三个符合大小的chunk之后,只需要这样就可以达成doublefree的效果:
1 | int *a = malloc(8); |
Fastbin dup consolidate (malloc_consolidate vul)
开始之前,先来谈一些前置的知识:
这个漏洞的标题指的是malloc_consolidate()
函数。consolidate意为“整合”,这个函数专门用于处理合并fastbin中的chunk,是我们取largebin大小chunk前ptmalloc所谓的“大循环”操作调用的一个重要函数。同时它还兼具初始化(设置一些宏)fastbin的作用。这里我们根据how2heap的提示,学习它关于fastbin的一些漏洞利用。
如果申请的chunk大小smallbin也无法满足,在调用largebin之前,malloc()
就会调用这个函数对fastbin进行整理,将他们合并到unsorted_bin或者topchunk。这个函数网上的分析感觉都非常会乱或者有的地方有矛盾,这里参考了一篇带完整源码的文章。大概过程是这样:
-
调用
clear_fastchunks()
清空fastbin的prev_inuse标志位 -
用二层循环(表头数组+链表)遍历所有的fastbin,检查物理地址的前后是个什么状况
-
如果物理相邻的前一个chunk也是free的,就将p从bin中unlink后将其合并到前一个chunk,否则不管
-
如果物理地址相邻后一个chunk是topchunk,就直接放进去然后退出循环
-
如果不是topchunk,就对后一个chunk重复3,把他们合并。
-
最后放入unsorted_bin中
几个小细节:topchunk是地址最高的那块;同时上面提到的所有所谓“合并”操作,基本就是将对应chunk解链unlink出来后更新相邻chunk的size大小而已。
这个漏洞的利用还涉及一些fastbin的小细节:
默认情况下(32 位系统为例),fastbin 中默认支持最大的 chunk 的数据空间大小为 64 字节。但是其可以支持的 chunk 的数据空间最大为 80 字节。除此之外, fastbin 最多可以支持的 bin 的个数为 10 个,从数据空间为 8 字节开始一直到 80 字节(注意这里说的是数据空间大小,也即除去 prev_size 和 size 字段部分的大小)——CTF Wiki
虽然代码中写的这是用于绕过tcache double free检测的,但是tcache是glibc-2.26之后引入的技术,所以我们复现漏洞时使用的glibc-2.23这里应该还是利用了fastbin漏洞。
然后来看代码,这里之前没懂的地方都打上注释:
1 |
|
这个漏洞的关键是malloc_consolidate()
的这段代码:
1 | else { //判断紧邻topchunk之后的动作 |
因此上述漏洞的本质就是在topchunk边缘不停地取chunk再放回去再取出来再放回去的过程。
House of Spirit
首先写点没用的,在堆漏洞的利用中,house of xx一般代表的是通过伪造chunk来达到攻击目的。这种说法最早出自于2004 年《The Malloc Maleficarum-Glibc Malloc Exploitation Techniques》中提出的一系列针对 glibc 堆分配器的利用方法。
不过现在我们说的House of XX的利用和最初提出时候的说法显然是大不相同了。这些漏洞利用手段各不相同,针对的点也都各不一样。House of Spirit就是一种把我们精心伪造的chunk通过free()
放进fastbin中,再通过malloc()
从里面“取出”实现任意地址分配chunk的攻击方式。
检查原理?
思想很简单,但具体怎么构造这个fake_chunk就要考虑free()
函数的检查方式了,到了最痛苦的glibc源码环节,我们先只看fastbin的部分。先来个CTFWiki的省流版本,后面一点点看:
要想构造 fastbin fake chunk,并且将其释放时,可以将其放入到对应的 fastbin 链表中,需要绕过一些必要的检测,即
- fake chunk 的 ISMMAP 位不能为 1,因为 free 时,如果是 mmap 的 chunk,会单独处理。 ——这一步在
__libc_free()
函数(一个包装函数)中实现,发现是mmap的就不进入_init_free()
了- fake chunk 地址需要对齐, MALLOC_ALIGN_MASK ——开头检查
- fake chunk 的 size 大小需要满足对应的 fastbin 的需求,同时也得对齐。 ——开头检查
- fake chunk 的 next chunk 的大小不能小于 2 * SIZE_SZ,同时也不能大于av->system_mem 。 ——通过size判断是fastbin之后内部会有检查
- fake chunk 对应的 fastbin 链表头部不能是该 fake chunk,即不能构成 double free 的情况。 ——释放前检查,只查链表头
——CTFWiki
_init_free()
函数在开头做了一些小检查:
1 | /* Little security check which won't hurt performance: the |
同时,_init_free()
是通过size判断是否按fastbin处理,换句话说在整个函数中fastbin是最先被判断的。
1 | /* |
攻击exp…
How2heap中提供的exp代码是这样的:
1 |
|
chunk的每个字段都是机器字长8字节,他们都是:
二编:这里并不确定
-
0:prev_size:前一个chunk的复用段,不使用
-
1:chunk1的size字段
-
2-7: 0x30大小,chunk1的数据域
-
8和9:假装有nextchunk,chunk2的prevsize和size字段
所以其实很简单地就绕过了free()
的检查,我们将一个chunk分配到了栈上!
fastbin_dup_into_stack
参考下面exp的注释:
1 |
|
思路很好懂了,操作也比house_of_spirit简单。利用double_free,劫持fastbin里面chunk的fd指针。当仅剩一个chunk的时候,劫持fd指针到我们的栈上,这样malloc会以为fastbin中还有剩余chunk,下下次分配就会把chunk分配到栈上。