glibc heap Fastbin Corruption

基础知识:

  • fastbin: Chunk Size <= get_max_fast()的chunk(其实就是64bits的是128bytes,32位的是64bytes) ,它们会被放在被称为fastbin的bin里面

上面的fastbinsY 里面存放fastbin , 最大是128bytes,最小是32bytes,然后依次加16bytes,32位的类似,不过最大是64bytes

  • 需要注意的是get_max_fast()事实上返回的是 global_max_fast,但是这个值得初始值为0,只有当第一次malloc之后它才会被赋值为相应的值
  • 同时fastbin是Single linked list,所以它只使用fd,以NULL结尾
  • free的时候呢,不取消下一个chunk 的prev_inuse bit,因为fastbin chunk不会和其他chunk合并
  • malloc 和 free的时候glibc会有一些检查,确认heap metadata是否正确,避免一些可能的攻击方式
  • fastbin执行效率高,它的里面的检查比其他类型的bin少很多
  • fastbin的linklist和其他的相反,跟Stack很像free和malloc的时候先进后出
  • fastbin的prev_inuse标志位在free的时候不会改变还是1,这防止了它和其他的free_chunk进行合并操作

Fastbin Corruption:

1..让fastbin linked list 指向任意位置,之后的malloc时就会把改地址当做chunk拿出来

 2.free(not in_use)的chunk会被存在bin里面,修改它的fd才会造成corruption
    1.double free
    2.Over flow

fastbin的检查方式:

  • malloc从bin里面取出chunk,要拿到合适大小的chunk(检查你这个chunk的chunk_size
  • free的时候,next_chunk的size必须正确(overflow的时候才会用到)
  • free时看看bin里面的第一个chunk和现在要free的是不是同一个(fasttop),这个的缺点就是它只和第一个检查,那么你可以在double free之前先free一个其他的大小合适的chunk

我们可以看源码了解一下(源码我会的不多,只说点关键的)
对应1:

    //这个nb是chunk的bytes 它来源于上面的一个checked_request2size(bytes,nb) 这的作用就是malloc的bytes+8然后16对齐
        if ((unsigned long)(nb) <= (unsigned long)(get_max_fast()))   //chunk的size(nb)小于128 or 64的话就会执行下面
        {
               idx = fastbin_index(nb);     //这是在fastbin里面找,把chunk的size转换成fastbin里面对应的哪一个(size/16-2)注意:0是fastbin的第一个
               mfastbinptr *fb = &fastbin(av, idx);
               mchunkptr pp;
               victim = *fb;
               if (victim != NULL)
               {
                       if (SINGLE_THREAD_P)
                              *fb = victim->fd;

                       else
                              REMOVE_FB(fb, pp, victim);
                       if (__glibc_likely(victim != NULL))
                       {
                              size_t victim_idx = fastbin_index(chunksize(victim));   //victim是要等一下要return的chunk
                              if (__builtin_expect(victim_idx != idx, 0))      //这边就是在检查你拿出来的chunk的idx跟bin的idx是不是一样,不对的话error
                                      malloc_printerr("malloc(): memory corruption  (fast)");

对应2:

               if (SINGLE_THREAD_P)
               {
                       /* Check that the top of the bin is not the record we are going to
                          add (i.e., double free).  */
                       if (__builtin_expect(old == p, 0))   //这个检查就是看看你free的chunk跟bin里面的chunk是不是同一个,同一个的话就error
                              malloc_printerr("double free or corruption (fasttop)");
                       p->fd = old;
                       *fb = p;
               }

double free也会形成类似UAF的效果,可以改掉bin里面的chunk的fd,可以看一下调试截图和源码

int main()
{
    void *p,*q,*r,*s;
    p = malloc(30);
    q = malloc(30);
    free(q);
    free(p);
    free(q); 第一次断点下在这里
}

更重要的是,现在bin里面有两个q(其实是同一块)都指向了P,
利用姿势注意点:

  1. 取出的chunk 的size要正确,所以也不是任意地址,需要可以制作假的size

    1. stack上的变量做size ,可以malloc出一个stack上的位置 (可以制作stack上的overflow)
    2. got上,用64bits地址常见的0x40(这个got没被call过的话)做size
  2. 取得chunk后,有机会对改地址任意写

fastbin double free:

  1. fasttop只检查bin里面的第一个chunk,只要不是连续free同一个chunk就没关系
  2. double free有类似use after free的效果,可以改掉bin里面的chunk的fd

例子:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void sh(char *cmd)
{
    system(cmd);
}
int main()
{
    setvbuf(stdout,0,_IONBF,0);
    int cmd,idx,sz;
    char *ptr[10];
    memset(ptr,0,sizeof(ptr));
    puts("1. malloc + gets\n2. free\n3. puts");
    while(1)
    {
        printf("> ");
        scanf("%d %d",&cmd, &idx);
        idx %= 10;
        if(cmd==1)
        {
            scanf("%d%*c",&sz);
            ptr[idx] = malloc(sz);
            gets(ptr[idx]);
        }
        else if(cmd==2)
        {
            free(ptr[idx]);
        }
        else if(cmd==3)
        {
            puts(ptr[idx]);
        }
        else
        {
            exit(0);
        }
    }
    return 0;
}

在64位机器上这个题目有个经典的手法来必过fastbin的检查,因为malloc必须要拿到合适的chunk,所以你malloc的chunk的size位必须要跟fastbin里面的chunk的size大小相同,我们可以在构造fastbin的时候用到了double free,这个操作就是先随便malloc2个大小一样的chunk p和q(必须是fastbin的大小),我们一次free p q p,那么就会绕过一个fastbin检测,同时这个double free也会形成一个类似环状的fastbin

那么在malloc的时候,如果从这个bin里面获取chunk的话,我们就可以通过三次malloc,两次使用chunk p,这样就可以利用gets实现有限制的地址写入,这个限制就来源于chunk大小检查,同样我们可以利用64位机器好多都是0x40,来将malloc的chunk p利用gets修改到got表的相应位置,那么第三次malloc就会把这个地址的内存当做一个chunk来取出来,进行gets,我们写入shell的地址,那么下次调用got表相应函数的时候就直接getshell


   转载规则


《glibc heap Fastbin Corruption》 时钟 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
2019第五空间pwn题解 2019第五空间pwn题解
於讴首先是一个简单的逆向分析只要大于或等于1000即可,接下来就是一个很简单的栈溢出的ROP利用: #!/usr/bin/env python # coding=utf-8 from pwn import * from LibcSearch
2019-08-31
下一篇 
Chunk Extend and Overlapping Chunk Extend and Overlapping
chunk extend 堆利用: 程序中堆的利用 可以控制chunk header中的数据 例如:heap overflowptmalloc 对chunk 操作的存在漏洞。 首先:怎么获取chunk的大小? /* Get size
2019-08-16
  目录