glibc2.27以后,该方法失效。另:部分资料参考看雪学院
目录
(七)malloc大堆块触发malloc_consolidate - malloc_init_state
前言
malloc_consolidate 会根据 global_max_fast 是否为 0 来判断 ptmalloc 是否已经初始化,因此如果能 通过任意地址写将 global_max_fast 置 0 然后触发 malloc_consolidate 就可以调用 malloc_init_state。
一、malloc_init_state
malloc_consolidate主要有两个功能
- 若 fastbin 未初始化,即 global_max_fast 为 0,那就初始化 malloc_state。
- 如果已经初始化的话,就合并 fastbin 中的 chunk。
可以参考:
// malloc_consolidate逻辑
if (get_max_fast () != 0) {
//global_max_fast不为0,表示ptmalloc已经初始化
//...
} else {
//如果global_max_fast为0
malloc_init_state(av);
//非debug模式下该宏定义为空
check_malloc_state(av);
}
在 malloc_init_state 中,清空bin后,会将top_chunk的指针指向main_arena:
static void malloc_init_state (mstate av) {
int i;
mbinptr bin;
for (i = 1; i < NBINS; ++i) {
bin = bin_at (av, i);
bin->fd = bin->bk = bin;
//遍历所有的bins,初始化每个bin的空闲链表为空,即将bin的fb和bk都指向bin本身
}
#if MORECORE_CONTIGUOUS
if (av != &main_arena)
#endif
set_noncontiguous (av);
//对于非主分配区,需要设置为分配非连续虚拟地址空间
if (av == &main_arena)
set_max_fast (DEFAULT_MXFAST);
//设置fastbin中最大chunk大小
//只要该全局变量的值非0,也就意味着主分配区初始化了
av->flags |= FASTCHUNKS_BIT;
//标识此时分配区无fastbin
av->top = initial_top (av);
//#define initial_top(M) (unsorted_chunks(M))
//#define unsorted_chunks(M) (bin_at(M, 1))
//#define bin_at(m, i) (mbinptr)(((char *) &((m)->bins[((i) - 1) * 2])) -
offsetof (struct malloc_chunk, fd))
//暂时把top chunk初始化为unsort chunk,仅仅是初始化一个值而已,这个chunk的内容肯定不能用于top chunk来分配内存,主要原因是top chunk不属于任何bin,但ptmalloc中的一些check代码可能需要top chunk属于一个合法的bin
}
事实上,此时 top chunk 的地址为 &av->bins[0] - 0x10 ,且 size 为之前的 last_remainder 的值(通常来说堆指 针都会很大),只要不断 malloc ,就可以分配到 hook 指针,实现劫持。
二、思路与调试
我们的整体思路,核心是触发consolidate中的malloc_init_state分支,也就是
get_max_fast () == 0
(一)任意地址写地址实现写入数值0
如果我们有任意地址写任意值的能力,自然可以在global_max_fast上写数值0。
如果更严苛一些,利用一些已有漏洞,如何实现覆写global_max_fast为0呢。我们知道,在64位程序中,堆地址、libc地址的高两个字节总是为0,我们可以通过错位的方式来写入0。
什么手法可以任意地址写一个libc地址或者堆地址呢?unsortedbin attack或者largebin attack。鉴于largebin attack所需要修改的地址都在堆上,比较方便多次控制,所以通过largebin attack是写入0的一般方式。
利用方式例如:0x00007f12345678是写入某个内存区域的一个“指针”数据
通过错位:0x0000000000000000,