【PWN】unlink exploit

堆机制

当一个small chunk被free掉时,会有如下操作:

  1. 检查是否能向后合并,如果相邻低位的chunk也处于被free的状态,则向后合并。

    • 合并两个chunk的内存
    • 修改当前chunk指针为前一个chunk指针
    • 触发unlink操作将前一个chunk从双向链表(bin)中移除
  2. 检查是否能向前合并,如果相邻高位的chunk处于被free的状态,则向前合并,同样能出发unlink 操作

unlink的操作为:

static void 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;
        }
    }
}

其中重要的操作为:(主要就是将chunk从双向链表中移除)

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

还有需要注意的检查:

if (chunksize (p) != prev_size (next_chunk (p)))
    malloc_printerr ("corrupted size vs. prev_size");

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

Exploit

由于有了检查机制,所以unlink所能做的操作有所限制。具体操作为:

  1. 构造p->fd=(p)-12,p->bk=(p)-8
  2. 触发unlink(p)
  3. 于是unlink操作变为了 (p)=(p)-8 => (p)=(p)-12

所以最终结果为(p)指针-12,(p)可以是任何存放p指针的地方。
虽然操作有限,但在一些场合下可以与堆溢出user after free等配合,从而任意地址写。

你可能感兴趣的:(【PWN】unlink exploit)