简介

  • 学习double free的具体利用

Fastbin Double free

Fastbin Double Free 是指 fastbin 的 chunk 可以被多次释放, 因此可以在 fastbin 链表中存在多次。这样导致的后果是多次分配可以从 fastbin 链表中取出同一个堆块, 相当于多个指针指向同一个堆块, 结合堆块的数据内容可以实现类似于类型混淆 (type confused) 的效果。

例子

这里我们还是用how2heap中的fastbin_dup.c来学习

➜  double_free gcc --version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

➜ double_free gcc fastbin_dup.c -o fastbin_dup
➜ double_free ./fastbin_dup
This file demonstrates a simple double-free attack with fastbins.
Allocating 3 buffers.
1st malloc(8): 0x7fffd4435260
2nd malloc(8): 0x7fffd4435280
3rd malloc(8): 0x7fffd44352a0
Freeing the first one...
If we free 0x7fffd4435260 again, things will crash because 0x7fffd4435260 is at the top of the free list.
So, instead, we'll free 0x7fffd4435280.
Now, we can free 0x7fffd4435260 again, since it's not the head of the free list.
Now the free list has [ 0x7fffd4435260, 0x7fffd4435280, 0x7fffd4435260 ]. If we malloc 3 times, we'll get 0x7fffd4435260 twice!
1st malloc(8): 0x7fffd4435260
2nd malloc(8): 0x7fffd4435280
3rd malloc(8): 0x7fffd4435260

解释得蛮清楚的, 但依旧惯例还是自己解释一波吧

  • 首先我们malloc三块chunk

  • 然后free掉第一块

  • 由于fastbin的机制原因, 它在执行free时会验证main_arena直接指向的块, 即指针头部的块。因此如果我们再一次freechunk1, 会报错。

    /* Another simple check: make sure the top of the bin is not the
    record we are going to add (i.e., double free). */
    if (__builtin_expect (old == p, 0))
    {
    errstr = "double free or corruption (fasttop)";
    goto errout;
    }

    直接再一次free chunk1:

    root@6268e63608bf:/ctf/work# ./elf
    This file demonstrates a simple double-free attack with fastbins.
    Allocating 3 buffers.
    1st malloc(8): 0x55d65bb9f010
    2nd malloc(8): 0x55d65bb9f030
    3rd malloc(8): 0x55d65bb9f050
    Freeing the first one...
    If we free 0x55d65bb9f010 again, things will crash because 0x55d65bb9f010 is at the top of the free list.
    *** Error in `./elf': double free or corruption (fasttop): 0x000055d65bb9f010 ***
    Aborted (core dumped)
  • 但是它也只检测了第一块, 对链表后面的块却没有执行检测, 因此我们先free chunk2, 再free chunk1是没有问题的, 我们在三个free后下断来看一下fast bin

    pwndbg> bins
    fastbins
    0x20: 0x555555757020 —▸ 0x555555757000 ◂— 0x555555757020 /* ' puUUU' */
    0x30: 0x0
    0x40: 0x0
    0x50: 0x0
    0x60: 0x0
    0x70: 0x0
    0x80: 0x0
    unsortedbin
    all: 0x0
    smallbins
    empty
    largebins
    empty
  • 然后我们再申请回来三个chunk, 就会发现我们第一个申请的chunk和第三个申请的chunk是同一个chunk

  • 这就是fast bindouble free

总结

通过 fastbin double free 我们可以使用多个指针控制同一个堆块, 这可以用于篡改一些堆块中的关键数据域或者是实现类似于类型混淆的效果。 如果更进一步修改 fd 指针, 则能够实现任意地址分配堆块的效果 (首先要通过验证), 这就相当于任意地址写任意值的效果。

Tcache Double free

类似于fastbin, 但是tcache free时没有会验证main_arena直接指向的块

static __always_inline void
tcache_put (mchunkptr chunk, size_t tc_idx)
{
tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
assert (tc_idx < TCACHE_MAX_BINS);
e->next = tcache->entries[tc_idx];
tcache->entries[tc_idx] = e;
++(tcache->counts[tc_idx]);
}

可以看出, tcache_put() 的检查也可以忽略不计(甚至没有对 tcache->counts[tc_idx] 的检查), 大幅提高性能的同时安全性也下降了很多。

因为没有任何检查, 所以我们可以对同一个 chunk 多次 free, 造成 cycliced list。

例子

这里以tcache_dup.c为例

➜  Desktop ./tcache_dup
This file demonstrates a simple double-free attack with tcache.
Allocating buffer.
malloc(8): 0xff4e5160
Freeing twice...

Now the free list has [ 0xff4e5160, 0xff4e5160 ].
Next allocated buffers will be same: [ 0xff4e5160, 0xff4e5160 ].
  • 首先我们malloc一块大小为8的chunk

  • 然后我们直接free两次, 现在看tcache bins, 可以看到已经形成环链

    tcache_bins

  • 这时我们malloc(8)两次, 这时两个chunk指针指向了同一个chunk

例题

0CTF 2016 freenote