首页
社区
课程
招聘
[原创]堆利用之unlink小结
发表于: 2019-7-31 15:52 10617

[原创]堆利用之unlink小结

2019-7-31 15:52
10617

unlink_chunk函数用于将空闲的chunk从所在的bin中取出.在malloc_consolidate()函数将fastbin中的空闲chunk整理到unsorted_bin时,在malloc()函数将unsorted中的空闲chunk整理到smallbin或者largebin中,以及在malloc()函数获取堆空间时,都有可能调用unlink_chunk().

因为待脱链空闲chunk p处于双向链表之中,所以有两个地方保存着p的大小,分别是p的size域和后一个chunk的prev_size,首先检查这两个size大小是否一致.

然后通过fd和bk获得p的前一个空闲chunk和后一个空闲chunk,并对双向链表的完整性进行检查

因为p只可能从largebin或者smallbin中脱链,而这两个bin都是双向链表,因此脱链需要分别修改前后chunk的fd或者bk.

如果是smallbin的话这会儿就算是脱链完成了,但对于largebin来说还需要修改fd_nextsize和bk_nextsize.首先是对next_size是否有效的检查

接着是对next_size双向链表的完整性检查.

后面的操作比较直观,就不仔细说了.

首先编译一下程序,我用的是ubuntu 16.04.

先设置断点,然后运行程序.到达断点之后进行单步执行

程序首先申请两个大小为0x80的chunk

假设这个时候存在溢出使得我们可以任意修改chunk0,我们就可以在chunk0之中构造出一个fake chunk.

由上面的源码可知我们有两个检查点需要绕过,第一个检查点就是对双向链表完整性的检查,即fd->bk != p || bk->fd != p.程序中使用了以下代码来绕过这个检查点

以前刚开始看到这的时候是一脸懵圈的,现在结合具体调试讲一讲.不过在开始具体讲解之前有必要先说一些关于堆的前置知识,熟悉的话可以自行跳过.首先,chunk在内存中的结构是这样的

我们malloc()函数返回的指针就是chunk中的mem.知道了这些以后我们回到程序代码中,chunk0_ptr[2]指向fake chunk中的fd,chunk0_ptr[3]指向fake chunk中的bk.执行前chunk0的结构如下

我们的&chunk0_ptr数值为0x602070.(uint64_t) &chunk0_ptr-(sizeof(uint64_t)3)的数值为0x602058,(uint64_t) &chunk0_ptr-(sizeof(uint64_t)3)的数值为0x602060.执行后chunk0的结构如下

现在,我们的fake chunk->fd为602058,由chunk结构可知,fake chunk->fd->bk为0x602070,其中保存着我们的fake chunk(603010).此时,fake chunk->fd->bk == fake chunk == 602010.同理可知fake chunk->bk->fd == fake chunk == 602010.就这样,我们已经绕过了第一个检查点.

这个只要利用chunk0的溢出就可以直接修改fake chunk的size以及chunk1的prev_size.另外为了对fake chunk使用unlink,我们还需要修改chunk1的prev_inuse标志位,将fake chunk伪造为一个free chunk.

执行上述代码之后,chunk0以及chunk1的布局如下

这样的话,我们去free chunk1,系统会检测到fake chunk也是空闲chunk.然后系统会调用unlink将fake chunk从双向链表中拿出来(虽然这个双向链表是我们自己构建的).unlink过程如下

未执行unlink之前,chunk0_ptr的值是这样的

执行unlink之后,原本指向堆上fake chunk的chunk0_ptr指向了自身地址-24的地址.如下

现在,chunk0_ptr[3]的值为chunk0_ptr的值,即修改chunk0_ptr[3]就意味着修改chunk0_ptr指针指向的地方,chunk0_ptr成为了一个可以指向任意地址的指针.如果我们可以读取chunk0_ptr[0]的值,就有了任意地址读;如果我们可以写入chunk0_ptr[0],就有了任意地址写.

glibc源码:2.29
实验主机:ubuntu 16.04
实验glibc版本:2.23
/* Take a chunk off a bin list.  */
static void
unlink_chunk (mstate av, mchunkptr p)
{
    //检查chunk的size和next_chunk的prev_size是否一致
    if (chunksize (p) != prev_size (next_chunk (p)))
        malloc_printerr ("corrupted size vs. prev_size");
    mchunkptr fd = p->fd;
    mchunkptr bk = p->bk;
    //检查fd和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)
    {
        //检查largebin中next_size双向链表的完整性
        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;
        }
    }
}
if (chunksize (p) != prev_size (next_chunk (p)))
        malloc_printerr ("corrupted size vs. prev_size");
mchunkptr fd = p->fd;
mchunkptr bk = p->bk;
//检查fd和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)
//检查largebin中next_size双向链表的完整性
if (p->fd_nextsize->bk_nextsize != p
|| p->bk_nextsize->fd_nextsize != p)
    malloc_printerr ("corrupted double-linked list (not small)");

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-8-6 18:30 被0x2l编辑 ,原因:
收藏
免费 4
支持
分享
最新回复 (2)
雪    币:
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark
2019-7-31 17:23
0
雪    币: 7
活跃值: (4331)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
3
有一个地址写错了,已修改
2019-8-6 18:30
0
游客
登录 | 注册 方可回帖
返回
//