• Unlink


    题外:学pwn快三个月了,从刚开始的师傅领进门到现在的个人修行,期间经历了太多的辛酸,在2019年10月12日晚9:40分,我终于做出了我的第一个堆题(原谅我这个菜鸡的不易),这道题是关于unlink的利用,特写此博客记录自己的所得。(笔者的环境是64位系统)

    Unlink原理:

    假设申请了两个大小分别为0x30和0x80的chunk,其中chunk1_head=0x4000h,chunk2_head=0x4040h,然后把返回的地址存在首地址为0x3000h的数组中,如果这时我们向chunk1中写入如下数据payload=p64(0)+p64(0x30)+p64(0x3040-0x18)+p64(0x0340-0x10)+'a'*16然后在free chunk2,便可以得到0x3028的地址,如下:

    具体的原理是ptmalloc在free chunk2时会检查其前后的chunk是否为空,这里我们忽略其后的chunk,只看chunk1。由于我们覆盖chunk2的size为0x80,其最低位被覆盖为0,表示此chunk为空闲,那么ptmalloc会利用unlink把chunk1从bins中取出然后进行合并。unlink的源码如下:

    /* Take a chunk off a bin list.  */
    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;
            }
        }
    }

    我们可以看出在unlink主要有两个检查:

    • chunksize (p) != prev_size (next_chunk (p)
    • __builtin_expect (fd->bk != p || bk->fd != p, 0)
    • 注意这里的p指向的是chunk1。

    要绕过第一个检查,我们必须使伪造的chunk大小等于其后一个chunk的prev_size的大小,即地址为0x4018h的内存块里的内容和地址为0x4040h的内存块里的内容相等。

    在进行第二检查前,ptmalloc会先执行fd=p->fd,bk=p->bk,即取p前后chunk的地址,然后检查p前后两个chunk的bk和fd指针是否指向p,这里我们覆盖p->fd为0x3040-0x18,故fd指向地址为0x3028h的内存块,bk指向地址为0x3030h的内存块。

    • fd->bk!=p,即判断 *(0x3028+0x18)是否等于p,
    • bk->fd!=p,即判断 *(0x3030+0x10)是否等于p,

    可知等于我们伪造的chunk的首地址。因此可以绕过第二个检查。(上图2地址为0x3040h的内存块里的内容在unlink前应是0x4010h,这里笔者偷个懒,直接把最终结果放上去了)

    之后执行fd->bk=bk,即*(0x3028+0x18)=0x3030,执行bk->fd=fd,即*(0x3030+0x10)=0x3028,故最后地址为0x3040的内存块里的内容会被修改为0x3028,这是再向其中写入一些数据便可达到一些利用。

  • 相关阅读:
    udelay、mdelay、ndelay、msleep使用比较说明
    linux多线程驱动中调用udelay()对整个系统造成的影响(by liukun321咕唧咕唧)
    linux设备驱动那点事儿之平台设备理论篇
    misc_register、 register_chrdev 的区别总结
    platform_driver与file_operations两种方法开发led驱动
    rc522 ,pn544区别
    内核驱动中常见的miscdevice、platform_device、platform_driver
    file_operations结构2
    file_operations结构体解析 1
    android5.0问题
  • 原文地址:https://www.cnblogs.com/countfatcode/p/11668332.html
Copyright © 2020-2023  润新知