Ptmalloc算法:Unsortedbin Attack
Unsortedbin Attack,也是堆中较为常见的利用手段,可以用来 泄露地址 和 WAA
概念:利用ptmalloc算法中,Unsortedbin的机制进行攻击
Unsorted Chunk
Unsorted Chunk就是暂时没有被程序处理的chunk
来源:
- 当一个较大的chunk被分割成两半后,剩下的部分大于MINSIZE
- 释放一个不属于fastbin的chunk,并且该chunk不和top chunk紧邻
- 当进行malloc_consolidate时,合并后的chunk会优先成为Unsorted Chunk(不与top chunk相邻)
这些Unsorted Chunk会以双向链表的形式构成Unsorted Bin
Unsorted Bin
Unsorted Bin就是专门用于管理Unsorted Chunk的数据结构,可以存储不同大小的chunk,有且只有一条
使用:
- 采用的遍历顺序是FIFO:先被释放的chunk,将会优先被申请( 先进先出队列)
- 在程序 malloc 时,如果在 fastbin,small bin 中找不到对应大小的 chunk,就会尝试从 Unsorted Bin 中寻找 chunk,如果取出来的 chunk 大小刚好满足,就会直接返回给用户,否则就会把这些 chunk 分别插入到对应的 bin 中
Unsorted Bin Leak
原理:
低libc版本的Unsorted Bin有一个特点:
- 第一个chunk的BK指针:指向“main_arena+xx”
- 最后一个chunk的FD指针:指向“main_arena+xx”
而“main_arena+xx”距离“libc_base”的偏移是固定的,所以可以通过泄露“main_arena+xx”来计算“libc_base”
案例:
利用:
如果程序拥有“打印模块”和UAF漏洞,则可以直接打印该地址
除此之外,很难泄露“main_arena+xx”
Unsorted Bin Attack
原理:
当将一个 unsorted bin 取出的时候,会将 bck->fd
的位置写入本 Unsorted Chunk 的位置
1 2 3 4 5
| if (__glibc_unlikely (bck->fd != victim)) malloc_printerr ("malloc(): corrupted unsorted chunks 3"); unsorted_chunks (av)->bk = bck; bck->fd = unsorted_chunks (av);
|
换而言之,如果我们控制了 bk 的值,我们就能将 unsorted_chunks (av)
写到任意地址
unsorted bin
也是以链表的方式进行组织的,和 fast bin
不同的是其分配方式是FIFO
,即一个chunk放入unsorted bin
链时将该堆块插入链表头,而从这个链取堆块的时候是从尾部开始的,因此unsorted bin
遍历堆块的时候使用的是bk
指针
通常 Unsorted Bin Attack 就是为了 Fastbin Attack 提供“\x7f”的
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <stdio.h> #include <malloc.h> #include <unistd.h> #include <string.h> int main() { int size=0x100; char *p=malloc(size); printf("%p\n",p); free(p); sleep(0); *(long*)(p+8)=0x601100; sleep(0); char *r=malloc(size); printf("%p\n",r); sleep(0); return 0; }
|
第一步:
chunkP是 Unsortedbin 中唯一的chunk
第二步:
chunkP的BK指针被改为“0x601100”
第三步:
chunkP被申请后,Unsortedbin 中没有chunk了,但是“0x601100”中被写入“main_arena+xx”
如果“0x601110-0x3”是我们的攻击目标的话,那么“0x601110-0x3”的指定偏移用于表示size的地址处就被我们写入了0x7f的数值
版本对Unsorted Bin Attack的影响
glibc2.23
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| for (;;) { int iters = 0; while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) { bck = victim->bk; if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0) || __builtin_expect (victim->size > av->system_mem, 0)) malloc_printerr (check_action, "malloc(): memory corruption", chunk2mem (victim), av); unsorted_chunks (av)->bk = bck; bck->fd = unsorted_chunks (av); }
|
只检查了“victim->size”,形同虚设,可以直接打Unsorted Bin Attack
glibc2.29
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
| for (;;) { int iters = 0; while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) { bck = victim->bk; size = chunksize (victim); mchunkptr next = chunk_at_offset (victim, size); if (__glibc_unlikely (size <= 2 * SIZE_SZ) || __glibc_unlikely (size > av->system_mem)) malloc_printerr ("malloc(): invalid size (unsorted)"); if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ) || __glibc_unlikely (chunksize_nomask (next) > av->system_mem)) malloc_printerr ("malloc(): invalid next size (unsorted)"); if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != size)) malloc_printerr ("malloc(): mismatching next->prev_size (unsorted)"); if (__glibc_unlikely (bck->fd != victim) || __glibc_unlikely (victim->fd != unsorted_chunks (av))) malloc_printerr ("malloc(): unsorted double linked list corrupted"); if (__glibc_unlikely (prev_inuse (next))) malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)"); unsorted_chunks (av)->bk = bck; bck->fd = unsorted_chunks (av); }
|
直接把“victim的全家”都给检查了,基本上不能打Unsorted Bin Attack
其实也有办法打Unsorted Bin Attack,以后遇到再说