堆漏洞挖掘:17---last remainder

一、什么是last remainder

  • 如果在bins链中存在freechunk时,当我们去malloc的时候,malloc的请求大小比freechunk的大小小,那么arena就会切割这个freechunk给malloc使用,那么切割之后剩余的chunk就被称为“last remainder”
  • 当产生last remainder之后,表示arena的malloc_state结构体中的last_remainder成员指针就会被初始化,并且指向这个last remainder

二、last remainder产生的情景(重点)

  • malloc的时候,不论malloc的大小,首先会去检查每个bins链(出去fastbins链)是否有与malloc相等大小的freechunk,如果没有就去检查bins链中是否有大的freechunk可以切割,如果切割,那么就切割大的freechunk,那么切割之后的chunk成为last remainder,并且last remainder会被放入到unsortedbin中

切割unsortedbin其实就是_int_malloc函数的for大循环的第一步,切割smallbins、largebins其实就是_int_malloc函数的for大循环的第三步(见_int_malloc函数文章:https://blog.csdn.net/qq_41453285/article/details/99005759)

切割unsortedbin中的大chunk时:

当unsortedbin有对应的freechunk可以给malloc切割使用时,unsortedbin会发生以下步骤:

  • ①先将这些freechunk放置到对应大小的bins链上(放入smallbin或largebin)
  • ②放置到对应的bins链上之后,切割此freechunk
  • ③切割之后会产生last remainder,再将last remainder放到unsortedbin上

例如:

  • 此时,unsortedbin有两个0x800的freechunk
  • 此时申请一个0x600的chunk
  • 那么unsortedbin会先consolidate,把两个0x800的freechunk先移动到largebin中
  • 然后再切割largebin的freechunk,将切割后余留下的0x200放入unsortedbin

切割smallbins、largebins中的大chunk时:

  • ①切割smallbins或者largebins中的大freechunk,产生last remainder
  • ②将last remainder放入到unsortedbin中
  • 注意(重点):malloc永远不会去检测切割fastbins(详情见_int_malloc函数的执行顺序)

三、last remainder的consolidate

  • 概念:当我们切割一个bins链中的大chunk时产生last reminader时,会发生consolidate,但是此种consolidate不会去整理fastbins中的freechunk(重点)

四、演示案例

#include 
#include
#include
#include
int main(){
    int size = 0x120;
    void *p = malloc(size);
    void *junk = malloc(size);  //放置释放p和q之后,p和q发生合并
    void *q = malloc(size);
    void *r = malloc(size);   //放置释放q之后,q和topchunk发生合并
	
    printf("p:0x%x\n",p);
    printf("q:0x%x\n",q);
    printf("r:0x%x\n",r);
	
    strcpy(p,"aaaaaaaabbbbbbbb");
    strcpy(q,"ccccccccdddddddd");
    strcpy(r,"eeeeeeeeffffffff");
    
    sleep(0);  //只为了打断点使用,无其他作用
    free(p);
	
    sleep(0);
    free(q);
	
    sleep(0);
    malloc(0x90);
    sleep(0);

    return 0;
}
  • 第一步:打断点到第一个sleep,并运行程序

  • 第二步:c一下,来到第二个sleep,此时p已经被释放

堆漏洞挖掘:17---last remainder_第1张图片

  • 第三步:c一下,来到第三个sleep,此时q也被释放

堆漏洞挖掘:17---last remainder_第2张图片

  • 第四步:c一下,来到第四个sleep,此时申请了一块0x90的chunk,在glibc中其实是申请了0xa0的chunk

因为p是先被放入unsortedbin的,所以malloc(0x90)时切割的就是p所指的chunk,可以看到原先的0x130的堆块前0xa0给malloc使用了,剩下的0x30就是我们的last remainder

并且通过bins可以看到,此次切割还触发了一次unsortedbin的consolidate,使q所指的chunk被整理到了smallbin中,但是切割之后的last remainder还留在unsortedbin中

堆漏洞挖掘:17---last remainder_第3张图片

堆漏洞挖掘:17---last remainder_第4张图片

  • 第五步:查看一下表示arnea的struct malloc_state结构体的last_remainder指针此时指向了我们的last remainder

五、演示案例

#include 
#include 

int main()
{
    int size=0x30;
    int size2=0x200;

    int *p1=malloc(size);
    int *p2=malloc(size2);
    int *temp=malloc(size); //防止p2和p3都被释放之后,p2和p3发生合并
    int *p3=malloc(size2);
    int *temp2=malloc(size); //防止p3被释放之后与topchunk合并

    sleep(0);  //只为打断点使用
    free(p1);

    sleep(0);
    free(p2);
    free(p3);

    sleep(0);
    malloc(0x100);

    sleep(0);
    return 0;
}
  • 第一步:打端点到sleep并运行起来

堆漏洞挖掘:17---last remainder_第5张图片

  • 第二步:c一下释放p1,可以看到其被加到fastbin中

堆漏洞挖掘:17---last remainder_第6张图片

  • 第三步:c一下,释放p2和p3,可以看到p2和p3都被加到unsortedbin中

堆漏洞挖掘:17---last remainder_第7张图片

  • 第四步:c一下,又申请了一个0x100的堆块,此时会去切割unsortedbin中的freechunk,并且触发consolidate,但是这个consolidate没有去整理fastbins,fastbins中的chunk没有变动

堆漏洞挖掘:17---last remainder_第8张图片

六、演示案例

#include 
#include 

int main()
{
    int size=0x300;
    
    int *p1=malloc(size);
    int *p2=malloc(size);  //防止p1被释放之后与topchunk合并
    
    sleep(0);  //为了程序打断点使用,无其他作用
    free(p1);

    sleep(0);
    malloc(0x700);

    sleep(0);
    malloc(0x200);

    return 0;
}
  • 第一步:打断点到sleep函数,运行程序,查看一下当前的堆块

堆漏洞挖掘:17---last remainder_第9张图片堆漏洞挖掘:17---last remainder_第10张图片

  • 第二步:n几下,释放p1,可以看到p1被放入unsortedbin中

堆漏洞挖掘:17---last remainder_第11张图片堆漏洞挖掘:17---last remainder_第12张图片

  • 第三步:n几下,malloc(0x700)的堆块,此时unsortedbin中的chunk(p1)被整理到smallbins中

堆漏洞挖掘:17---last remainder_第13张图片

  • 第四步:n几下,然后申请一个0x200的堆块,申请的时候malloc发现smallbins中有满足的chunk可以切割,于是就去切割smallbins中的堆块,并产生last remainder,将last remainder放入unsortedbin中

堆漏洞挖掘:17---last remainder_第14张图片堆漏洞挖掘:17---last remainder_第15张图片

七、演示案例

#include 
#include 

int main()
{
    int size=0x300;
    
    int *temp=malloc(0x30);
    int *p1=malloc(size);

    //防止p1释放并consolidate到smallbins中之后,再释放p2导致p1和p2合并,合并之后又被放入unsortedbin中
    int *temp2=malloc(0x30);

    int *p2=malloc(0x100); 
    int *p3=malloc(size);//防止p2被释放之后与topchunk合并
    
    sleep(0);  //为了程序打断点使用,无其他作用
    free(p1);

    sleep(0);
    malloc(0x700);
    
    sleep(0);
    free(temp);
    free(p2);

    sleep(0);
    malloc(0x200);

    return 0;
}
  • 第一步:打断点到sleep,运行程序,并查看当前堆块(由于屏幕原因,topchunk没有截图下来)

堆漏洞挖掘:17---last remainder_第16张图片

  • 第二步:c一下,释放p1

堆漏洞挖掘:17---last remainder_第17张图片

  • 第三步:c一下,malloc(0x700),将unsortedbin中的p1整理到smallbin中

堆漏洞挖掘:17---last remainder_第18张图片

  • 第四步:c一下,释放temp和p2,此时temp被放入fastbins中,p2被放入unsortedbin中(注意:如果没有temp2这个堆块,此处释放p2之后,由于p1和p2是物理相邻的chunk,那么p1和p2就会合并然后一起放入到unsortedbin中了)

堆漏洞挖掘:17---last remainder_第19张图片

  • 第五步:n几下,malloc(0x200),此时malloc会切割smallbins中的p1,并产生last remainder(0x602250),并把last remainder放入到unsortedbin中。由于切割chunk并产生last remainder会发生consolidate,所以unsortedbin中的p2从unsortedbin中整理到smallbins中(由于此种情况的consolidate不会整理fastbins中的chunk,所以fastbins中的chunk仍然在fastbins中)

堆漏洞挖掘:17---last remainder_第20张图片

你可能感兴趣的:(堆漏洞挖掘)