Chunk Extend and Overlapping
介绍
chunk extend是堆漏洞的一种常见利用手法,通过extend可以实现chunk overlapping的效果。这种利用方法需要以下的时机和条件:
程序中存在基于堆的漏洞
漏洞可以控制 chunk header 中的数据
原理
chunk extend技术能够产生的原因在于ptmalloc在对堆chunk进行操作时使用的各种宏。
在ptmalloc中,获取 chunk 块大小的操作如下
/* Get size, ignoring use bits */
#define chunksize(p) (chunksize_nomask(p) & ~(SIZE_BITS))
/* Like chunksize, but do not mask SIZE_BITS. */
#define chunksize_nomask(p) ((p)->mchunk_size)一种是直接获取 chunk 的大小,不忽略掩码部分,另外一种是忽略掩码部分。
在 ptmalloc 中,获取下一 chunk 块地址的操作如下
/* Ptr to next physical malloc_chunk. */
#define next_chunk(p) ((mchunkptr)(((char *) (p)) + chunksize(p)))即使用当前块指针加上当前块大小。
在 ptmalloc 中,获取前一个 chunk 信息的操作如下
即通过malloc_chunk->prev_size获取前一块大小,然后使用本 chunk 地址减去所得大小。
在 ptmalloc,判断当前 chunk 是否是use状态的操作如下:
即查看下一 chunk 的 prev_inuse 域,而下一块地址又如我们前面所述是根据当前 chunk 的 size 计算得出的。
更多的操作详见 堆相关数据结构 一节。
通过上面几个宏可以看出,ptmalloc通过chunk header的数据判断chunk的使用情况和对chunk的前后块进行定位。简而言之,chunk extend就是通过控制size和pre_size域来实现跨越块操作从而导致overlapping的。
与chunk extend类似的还有一种称为chunk shrink的操作。这里只介绍chunk extend的利用。
基本示例1:对inuse的fastbin进行extend
简单来说,该利用的效果是通过更改第一个块的大小来控制第二个块的内容。 注意,我们的示例都是在64位的程序。如果想在32位下进行测试,可以把8字节偏移改为4字节。
当两个malloc语句执行之后,堆的内存分布如下
之后,我们把 chunk1 的 size 域更改为 0x41,0x41 是因为 chunk 的 size 域包含了用户控制的大小和 header 的大小。如上所示正好大小为0x40。在题目中这一步可以由堆溢出得到。
执行 free 之后,我们可以看到 chunk2 与 chunk1 合成一个 0x40 大小的 chunk,一起释放了。
之后我们通过 malloc(0x30) 得到 chunk1+chunk2 的块,此时就可以直接控制chunk2中的内容,我们也把这种状态称为 overlapping chunk。
基本示例2:对inuse的smallbin进行extend
通过之前深入理解堆的实现部分的内容,我们得知处于 fastbin 范围的 chunk 释放后会被置入 fastbin 链表中,而不处于这个范围的 chunk 被释放后会被置于unsorted bin链表中。 以下这个示例中,我们使用 0x80 这个大小来分配堆(作为对比,fastbin 默认的最大的 chunk 可使用范围是0x70)
在这个例子中,因为分配的 size 不处于 fastbin 的范围,因此在释放时如果与 top chunk 相连会导致和top chunk合并。所以我们需要额外分配一个chunk,把释放的块与top chunk隔开。
释放后,chunk1 把 chunk2 的内容吞并掉并一起置入unsorted bin
再次进行分配的时候就会取回 chunk1 和 chunk2 的空间,此时我们就可以控制 chunk2 中的内容
基本示例3:对free的smallbin进行extend
示例3是在示例2的基础上进行的,这次我们先释放 chunk1,然后再修改处于 unsorted bin 中的 chunk1 的size域。
两次 malloc 之后的结果如下
我们首先释放chunk1使它进入unsorted bin中
然后篡改chunk1的size域
此时再进行 malloc 分配就可以得到 chunk1+chunk2 的堆块,从而控制了chunk2 的内容。
Chunk Extend/Shrink 可以做什么
一般来说,这种技术并不能直接控制程序的执行流程,但是可以控制chunk中的内容。如果 chunk 存在字符串指针、函数指针等,就可以利用这些指针来进行信息泄漏和控制执行流程。
此外通过extend可以实现chunk overlapping,通过overlapping可以控制chunk的fd/bk指针从而可以实现 fastbin attack 等利用。
基本示例4:通过extend后向overlapping
这里展示通过extend进行后向overlapping,这也是在CTF中最常出现的情况,通过overlapping可以实现其它的一些利用。
在malloc(0x50)对extend区域重新占位后,其中0x10的fastbin块依然可以正常的分配和释放,此时已经构成overlapping,通过对overlapping的进行操作可以实现fastbin attack。
基本示例5:通过extend前向overlapping
这里展示通过修改pre_inuse域和pre_size域实现合并前面的块
前向extend利用了smallbin的unlink机制,通过修改pre_size域可以跨越多个chunk进行合并实现overlapping。
HITCON Trainging lab13
基本信息
程序为 64 位动态链接程序,主要开启了 Canary 保护与 NX 保护。
基本功能
程序大概是一个自定义的堆分配器,每个堆主要有两个成员:大小与内容指针。主要功能如下
创建堆,根据用户输入的长度,申请对应内存空间,并利用 read 读取指定长度内容。这里长度没有进行检测,当长度为负数时,会出现任意长度堆溢出的漏洞。当然,前提是可以进行 malloc。此外,这里读取之后并没有设置 NULL。
编辑堆,根据指定的索引以及之前存储的堆的大小读取指定内容,但是这里读入的长度会比之前大 1,所以会存在 off by one 的漏洞。
展示堆,输出指定索引堆的大小以及内容。
删除堆,删除指定堆,并且将对应指针设置为了 NULL。
利用
基本利用思路如下
利用off by one 漏洞覆盖下一个chunk 的 size 字段,从而构造伪造的 chunk 大小。
申请伪造的 chunk 大小,从而产生 chunk overlap,进而修改关键指针。
更加具体的还是直接看脚本吧。
2015 hacklu bookstore
基本信息
可以看出该程序是动态链接的 64 位程序,主要开启了 Canary 与 NX 保护。
基本功能
该程序的主要功能是订书,具体如下
最多可以订购两本书。
根据编号来选择订购第几本书,可以为每本书添加对应的名字。然而在添加名字处出现了任意长度堆溢出的漏洞。
根据编号来删除 order,但是这里只是单纯地 free 掉,并没有置为 NULL,因此会出现 use after free 的漏洞。
提交订单,将两本书的名字合在一起。这里由于上面堆溢出的问题,这里也会出现堆溢出的漏洞。
此外,在程序退出之前存在一个格式化字符串漏洞。
这里虽然程序的漏洞能力很强,但是所有进行 malloc 的大小都是完全固定的,我们只能借助这些分配的 chunk 来进行操作。
利用思路
程序中主要的漏洞在于堆溢出和格式化字符串漏洞,但是如果想要利用格式化字符串漏洞,必然需要溢出对应的dest 数组。具体思路如下
利用堆溢出进行 chunk extend,使得在 submit 中
malloc(0x140uLL)时,恰好返回第二个订单处的位置。在 submit 之前,布置好堆内存布局,使得把字符串拼接后恰好可以覆盖 dest 为指定的格式化字符串。通过构造 dest 为指定的格式化字符串:一方面泄漏 __libc_start_main_ret 的地址,一方面控制程序重新返回执行。这时,便可以知道 libc 基地址,system 等地址。需要注意的是由于一旦 submit 之后,程序就会直接直接退出,所以我们比较好的思路就是修改 fini_array 中的变量,以便于达到程序执行完毕后,重新返回我们期待的位置。这里我们会使用一个trick,程序每次读取选择的时候会读取 128 大小,在栈上。而程序最后在输出 dest 的时候,之前所读取的那部分选择必然是在栈上的,所以我们如果我们在栈上预先布置好一些控制流指针,那就可以来控制程序的执行流程。
再次利用格式化字符串漏洞,覆盖 free@got 为 system 地址,从而达到任意命令执行的目的。
这里,各个参数的偏移是
Fini_array0 : 5+8=13
__libc_start_main_ret : 5+0x1a=31。
!!!待补充!!!
题目
Last updated