fastbin dup
锵锵!how2heap系列第一篇!正式开始堆漏洞系列的学习!系列模式预计是原理+例题,还有各版本的利用差异。冲!(。・∀・)ノ゙
相关检查(所用源码版本2.23)
malloc中对从fastbin中取chunk的检查只有size的合法性检查
1 |
|
free中对于将chunk放进fastbin的检查有:
- 开始对所有chunk的对齐和大小是否超界的检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//筛掉一些特别大的chunk(超出内存边界)
if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
|| __builtin_expect (misaligned_chunk (p), 0))
{
errstr = "free(): invalid pointer";
errout:
if (!have_lock && locked)
(void) mutex_unlock (&av->mutex);
malloc_printerr (check_action, errstr, chunk2mem (p), av);
return;
}
//对齐检查
if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
{
errstr = "free(): invalid size";
goto errout;
} - 下一个chunk是不是top chunk
1
2
3
4
5
6
7
8
9
10if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
/*
If TRIM_FASTBINS set, don't place chunks
bordering top into fastbins
*/
&& (chunk_at_offset(p, size) != av->top)
) - 下一个chunk的大小是否超界的检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18if (__builtin_expect (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ, 0)
|| __builtin_expect (chunksize (chunk_at_offset (p, size))
>= av->system_mem, 0))
{
/* We might not have a lock at this point and concurrent modifications
of system_mem might have let to a false positive. Redo the test
after getting the lock. */
if (have_lock
|| ({ assert (locked == 0);
mutex_lock(&av->mutex);
locked = 1;
chunk_at_offset (p, size)->size <= 2 * SIZE_SZ
|| chunksize (chunk_at_offset (p, size)) >= av->system_mem;
}))
{
errstr = "free(): invalid next size (fast)";
goto errout;
} - fastbin的第一个chunk是不是插入的chunk(double free检查)
1
2
3
4
5if (__builtin_expect (old == p, 0))
{
errstr = "double free or corruption (fasttop)";
goto errout;
} - 以及chunk的大小合法性检查
1
2
3
4
5if (have_lock && old != NULL && __builtin_expect (old_idx != idx, 0))
{
errstr = "invalid fastbin entry (free)";
goto errout;
}
利用
2.23-2.25
为了避开free中double free的检查(只检查第一个chunk是不是正在free的chunk),一般在double free中间再free另一个chunk形成a->b->a的形式再通过申请回第一个a来改变最后一个a的fd指针指向fake chunk
一般会将fd指针指向__malloc_hook-0x23,这个地址+8有一个0x7f,可以作为合法的size。这样我们可以在申请chunk的时候申请0x60大小的chunk来绕开chunk的size的合法性检查,将malloc_hook改为one_gadget的地址(free_hook前面全是0)
2.27-2.31
2.26比之前最大的变化就是在fastbin之前增加了tcache,利用方法也发(bian)生(jian)了(dan)变(le)化(ne)
- 先申请7个chunk填满tcache
- 再在fastbin中形成a->b->a
- 再把tcache清空
- 再申请一个chunk就可以申请到a,同时b和a(2)就会被放进tcache,这时tcache是这样的b->a(fastbin的chunk放进tcache是每次取最后一个chunk再执行tcache_put)
- 由于tcache中没有size的检查,所以直接改free_hook就行(注意tcache中的指针指向的是chunk中的data)
2.32以上
增加了单链表的指针保护机制以及地址0x10对齐检查(错位找0x7f打fastbin不行了)
例题
hgame2023 week2 fast_note
思路
libc版本2.23
金典的菜单题,有UAF。思路就是先填满tcache利用unsorted bin泄露libc基址,再用fastbin double free将malloc_hook改为one_gadget
这道题麻烦的地方在于四个one_gadget都不可用
其中后三个one_gadget限定的是栈空间,那我们就可以通过realloc调节栈内容
realloc调节栈内容
realloc的执行流程和malloc一样也是先检查hook是否为null,如果不为null就调用hook
realloc函数开头有很多push指令,可以通过push指令抬高栈,push指令的数量可以通过偏移调整
我们可以将malloc_hook填充为realloc+offset(offset可取0,2,4,6,12,13),offset越大,push指令越少,栈地址越高;再将realloc_hook填充为one_gadget。而realloc_hook的地址其实就在malloc_hook上方
在改fd指针时可以一趟改掉
exp
1 |
|
hgame2023 week2 new_fast_note
libc版本2.31
思路
没啥难度,就是tcache版本的fastbin double free,不说了。就是注意这道题没有重复malloc的检查了(做的时候没看见QAQ)
exp
1 |
|