欢迎光临散文网 会员登陆 & 注册

二进制安全之堆溢出(系列)——堆基础 & 结构(四)

2020-03-26 16:50 作者:汇智知了堂  | 我要投稿

二进制安全之堆溢出(系列)——“堆基础&结构”第四节上回咱们聊到碎块合并问题本次咱们从ulink讲起

unlink

  • unlink用来将一个双向链表bin链中的一个元素取出来,即断链过程

  • 引发unlink的几种方式

malloc

  • 从恰好大小合适的largebin中获取chunk会unlink

  • fastbin和smallbin没有使用unlink

  • 依次遍历unsorted bin时也没有使用unlink

  • 合并和切割的时候都会unlink

free

  • 后向合并,合并物理相邻低地址空闲chunk的时候会unlink

  • 前向后并,合并物理相邻高地址空闲chunk的时候会unlink(除了top chunk)

relloc

consolidate

  • unlink源码分析

    /* Take a chunk off a bin list 用于将某一个空闲 chunk从其所处的bin中脱链*/

    #define unlink(AV, P, BK, FD) {  //P 即为待脱链的空闲 chunk                        \

    if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0))

    /*检查一下其大小是否一致(size检查)

    故在做overlap的时候,伪造的堆块的size需要和presize一致

    */

    malloc_printerr ("corrupted size vs. prev_size");               \

    FD = P->fd;         //FD为   P的前一个空闲chunk

    BK = P->bk;         //BK为p的后一个空闲chunk

    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))

    /*承上检查,检查当前的p是否与两边相连

    */

    malloc_printerr ("corrupted double-linked list");

    else {      //设置相邻 chunk 的 fd 或 bk 指针

    FD->bk = BK;

    BK->fd = FD;

    /*

    可以在这里修改p的fd和bk

    p->fd = target  //修改fd

    p->bk = target    //修改bk

    因此

    FD = target

    BK = target

    FD->bk = *(target + 0x18)   //prev_size + size +fd = 0x18

    BK->fd = *(target + 0x10)

    上面的改法无法绕过FD->bk != P || BK->fd != P的检查

    //TODO follow

    FD = target - 0x18               //自己控制堆块修改值即可

    BK = target - 0x10

    FD->bk = *(target - 0x18 + 0x18) = BK = target - 0x10 = p

    BK->fd = *(target - 0x10 + 0x10) = FD = target - 0x18 = p

    这样就可以绕过当前的校验

    payload = 0x18 *'a' + target_addr

    构造payload,替换target为got或任意地址

    */

    /*对于smallbin而言,以上脱链完成

    下面处理largebin的脱链,多了fd/bk_nextsize的unlink过程

    */

    if (!in_smallbin_range (chunksize_nomask (P))

    && __builtin_expect (P->fd_nextsize != NULL, 0)) {

    //说明P是相应bins的第一个chunk,否则fd_nextsize和bk_nextsize没有意义

    if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)

    || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    \

    malloc_printerr ("corrupted double-linked list (not small)");

    if (FD->fd_nextsize == NULL) { //p断链之后,FD成为当前bins的第一个chunk

    if (P->fd_nextsize == P)    //只有唯一的chunk时

    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成为下一组bins的第一个chunk

    P->fd_nextsize->bk_nextsize = P->bk_nextsize;

    P->bk_nextsize->fd_nextsize = P->fd_nextsize;

    }

    }

    }

    }

  • 泄露libc的地址

P位于双向链表头部,bk泄露P位于双向链表尾部,fd泄露双向链表中只包含一个空闲chunk时,P位于双向链表中,fd和bk均可泄露tips:这里的头部指的是bin的fd指向的chunk,即双向链表中最新加入的chunk,反之亦然
  • 实例分析

断链的目标:p ,p之后需要有一个已经free的堆块覆盖p->fd = target - 0x18 p->bk = target - 0x10,注意此时的fd和bk都是地址的值


 target 为堆中的任意堆块的地址的值,前提是可以通过heap_base + offset 获得地址现在假设target为note2,note2的地址为heap_base+0x60,则target需要填heap_base+0x60

当free p的时候,就会和之后的空闲堆块发生合并,从而引发unlink此时按顺序断链 *(p->fd->bk)= bk,*(p->bk->fd) = fd,即最终实现*(target)=target-0x18

 p->fd->bk的内容为bk的值,故`*(p->fd->bk)= bk`p->bk->fd的内容为bk的值,故`*(p->bk->fd)= fd`最终结果为第二条语句的执行结果这时前面的target为指针,上述结果相当于target指向了target-0x18的地址空间

此时我们向target里面写入0x18 * 'a',就相当于指针target+0x18指向了target起始的地址紧接着写入malloc_hook的地址,然后再edit target,写入system的地址,就相当于target+0x18+0x8指向了target+0x8的地址空间此时就相当于*(malloc_hook) = system ,再次malloc的时候就会调用system了。

调试

源代码一

  #include<stdio.h>

    #include<malloc.h>

    #include<unistd.h>

    #include<string.h>

    int main(){

    int size = 0x70;

    void *p = malloc(size);

    void *q = malloc(size);

    void *junk = malloc(size);

    sleep(0);

    free(q);

    sleep(0);

    printf("%p\n",q);

    int *r = malloc(0x60);

    printf("%p\n",r);

    sleep(0);

    return 0;

堆块分配后的heap与内存布局


 0x602000 FASTBIN {  ===>chunk1

    prev_size = 0,

    size = 129,

    fd = 0x0,

    bk = 0x0,

    fd_nextsize = 0x0,

    bk_nextsize = 0x0

    }

    0x602080 FASTBIN {  ===>chunk2

    prev_size = 0,

    size = 129,

    fd = 0x0,

    bk = 0x0,

    fd_nextsize = 0x0,

    bk_nextsize = 0x0

    }

    0x602100 FASTBIN {  ===>chunk3

    prev_size = 0,

    size = 129,

    fd = 0x0,

    bk = 0x0,

    fd_nextsize = 0x0,

    bk_nextsize = 0x0

    }

    0x602180 PREV_INUSE {

    prev_size = 0,

    size = 134785,            ===>top_chunk

    fd = 0x0,

    bk = 0x0,

    fd_nextsize = 0x0,

    bk_nextsize = 0x0

    }

    }


---------------------------------------------------------------------------------------------------------------------------

 0x602000:       0x0000000000000000      0x0000000000000081 <=== chunk1

    0x602010:       0x0000000000000000      0x0000000000000000

    0x602020:       0x0000000000000000      0x0000000000000000

    0x602030:       0x0000000000000000      0x0000000000000000

    0x602040:       0x0000000000000000      0x0000000000000000

    0x602050:       0x0000000000000000      0x0000000000000000

    0x602060:       0x0000000000000000      0x0000000000000000

    0x602070:       0x0000000000000000      0x0000000000000000

    0x602080:       0x0000000000000000      0x0000000000000081 <=== chunk2

    0x602090:       0x0000000000000000      0x0000000000000000

    0x6020a0:       0x0000000000000000      0x0000000000000000

    0x6020b0:       0x0000000000000000      0x0000000000000000

    0x6020c0:       0x0000000000000000      0x0000000000000000

    0x6020d0:       0x0000000000000000      0x0000000000000000

    0x6020e0:       0x0000000000000000      0x0000000000000000

    0x6020f0:       0x0000000000000000      0x0000000000000000

    0x602100:       0x0000000000000000      0x0000000000000081  <=== chunk3

    0x602110:       0x0000000000000000      0x0000000000000000

    0x602120:       0x0000000000000000      0x0000000000000000

    0x602130:       0x0000000000000000      0x0000000000000000

    0x602140:       0x0000000000000000      0x0000000000000000

    0x602150:       0x0000000000000000      0x0000000000000000

    0x602160:       0x0000000000000000      0x0000000000000000

    0x602170:       0x0000000000000000      0x0000000000000000

    0x602180:       0x0000000000000000      0x0000000000020e81  <=== top chunk

    0x602190:       0x0000000000000000      0x0000000000000000

    0x6021a0:       0x0000000000000000      0x0000000000000000

    0x6021b0:       0x0000000000000000      0x0000000000000000

    0x6021c0:       0x0000000000000000      0x0000000000000000

    0x6021d0:       0x0000000000000000      0x0000000000000000

free(q)之后的heap与内存布局

 0x602000 FASTBIN {

      prev_size = 0,

      size = 129,

      fd = 0x0,

      bk = 0x0,

      fd_nextsize = 0x0,

      bk_nextsize = 0x0

    }

    0x602080 FASTBIN {

      prev_size = 0,

      size = 129,

      fd = 0x7ffff7dd1be8 <main_arena+200>,

      bk = 0x7ffff7dd1be8 <main_arena+200>,

      fd_nextsize = 0x0,

      bk_nextsize = 0x0

    }

    0x602100 FASTBIN {

      prev_size = 128,

      size = 129,

      fd = 0x0,

      bk = 0x0,

      fd_nextsize = 0x0,

      bk_nextsize = 0x0

    }

    0x602180 PREV_INUSE {

      prev_size = 0,

      size = 1041,

      fd = 0x3039303230367830,

      bk = 0xa,

      fd_nextsize = 0x0,

      bk_nextsize = 0x0

    }

    0x602590 PREV_INUSE {

      prev_size = 0,

      size = 133745,

      fd = 0x0,

      bk = 0x0,

      fd_nextsize = 0x0,

      bk_nextsize = 0x0

    }

---------------------------------------------------------------------------------------------------------------------------

 0x602000:       0x0000000000000000      0x0000000000000081

    0x602010:       0x0000000000000000      0x0000000000000000

    0x602020:       0x0000000000000000      0x0000000000000000

    0x602030:       0x0000000000000000      0x0000000000000000

    0x602040:       0x0000000000000000      0x0000000000000000

    0x602050:       0x0000000000000000      0x0000000000000000

    0x602060:       0x0000000000000000      0x0000000000000000

    0x602070:       0x0000000000000000      0x0000000000000000

    0x602080:       0x0000000000000000      0x0000000000000081  ==>chunk未发生变化

    0x602090:       0x0000000000000000      0x0000000000000000

    0x6020a0:       0x0000000000000000      0x0000000000000000

    0x6020b0:       0x0000000000000000      0x0000000000000000

    0x6020c0:       0x0000000000000000      0x0000000000000000

    0x6020d0:       0x0000000000000000      0x0000000000000000

    0x6020e0:       0x0000000000000000      0x0000000000000000

    0x6020f0:       0x0000000000000000      0x0000000000000000

    0x602100:       0x0000000000000000      0x0000000000000081

    0x602110:       0x0000000000000000      0x0000000000000000

    0x602120:       0x0000000000000000      0x0000000000000000

    0x602130:       0x0000000000000000      0x0000000000000000

    0x602140:       0x0000000000000000      0x0000000000000000

    0x602150:       0x0000000000000000      0x0000000000000000

    0x602160:       0x0000000000000000      0x0000000000000000

    0x602170:       0x0000000000000000      0x0000000000000000

    0x602180:       0x0000000000000000      0x0000000000020e81

    //此时free掉的chunk_size为81的原因 :free掉了,但没有把指针置空,第二个堆块变成空闲堆块,由bins链管理,chunk_size依然为0x80


此时的bins链

fastbins

    0x20: 0x0

    0x30: 0x0

    0x40: 0x0

    0x50: 0x0

    0x60: 0x0

    0x70: 0x0

    0x80: 0x602080 ?— 0x0           ==》被释放的chunk进入了fastbin链

    unsortedbin

    all: 0x0

    smallbins

    empty

    largebins

    empty

分配新的0x60的chunk后的heap和内存布局

0x602000 FASTBIN {

      prev_size = 0,

      size = 129,

      fd = 0x0,

      bk = 0x0,

      fd_nextsize = 0x0,

      bk_nextsize = 0x0

    }

    0x602080 FASTBIN {    ===>chunk2被切割出0x70的空间,剩下的0x10自动和top_chunk合并

      prev_size = 0,

      size = 129,

      fd = 0x7ffff7dd1be8 <main_arena+200>,

      bk = 0x7ffff7dd1be8 <main_arena+200>,

      fd_nextsize = 0x0,

      bk_nextsize = 0x0

    }

    0x602100 {

      prev_size = 128,      //说明上一个chunk被free掉了,大小为0x80

      size = 128,

      fd = 0x0,

      bk = 0x0,

      fd_nextsize = 0x0,

      bk_nextsize = 0x0

    }

    0x602180 PREV_INUSE {   //printf的缓冲区堆块 ,从top_chunk中分配,多个printf分配一个chunk

      prev_size = 0,

      size = 1041,

      fd = 0x3039303230367830,      

      bk = 0xa,

      fd_nextsize = 0x0,

      bk_nextsize = 0x0

    }

    0x602590 PREV_INUSE {

      prev_size = 0,

      size = 133745,

      fd = 0x0,

      bk = 0x0,

      fd_nextsize = 0x0,

      bk_nextsize = 0x0

    }

---------------------------------------------------------------------------------------------------------------------------


0x602000:       0x0000000000000000      0x0000000000000081

    0x602010:       0x0000000000000000      0x0000000000000000

    0x602020:       0x0000000000000000      0x0000000000000000

    0x602030:       0x0000000000000000      0x0000000000000000

    0x602040:       0x0000000000000000      0x0000000000000000

    0x602050:       0x0000000000000000      0x0000000000000000

    0x602060:       0x0000000000000000      0x0000000000000000

    0x602070:       0x0000000000000000      0x0000000000000000

    0x602080:       0x0000000000000000      0x0000000000000081  ==>重新组装的chunk2

    0x602090:       0x00007ffff7dd1be8      0x00007ffff7dd1be8  ==>fd和bk指向main_arena的地址

    0x6020a0:       0x0000000000000000      0x0000000000000000

    0x6020b0:       0x0000000000000000      0x0000000000000000

    0x6020c0:       0x0000000000000000      0x0000000000000000

    0x6020d0:       0x0000000000000000      0x0000000000000000

    0x6020e0:       0x0000000000000000      0x0000000000000000

    0x6020f0:       0x0000000000000000      0x0000000000000000

    0x602100:       0x0000000000000080      0x0000000000000081

    0x602110:       0x0000000000000000      0x0000000000000000

    0x602120:       0x0000000000000000      0x0000000000000000

    0x602130:       0x0000000000000000      0x0000000000000000

    0x602140:       0x0000000000000000      0x0000000000000000

    0x602150:       0x0000000000000000      0x0000000000000000

    0x602160:       0x0000000000000000      0x0000000000000000

    0x602170:       0x0000000000000000      0x0000000000000000

    0x602180:       0x0000000000000000      0x0000000000000411

    0x602190:       0x3039303230367830      0x000000000000000a

    0x6021a0:       0x0000000000000000      0x0000000000000000

    0x6021b0:       0x0000000000000000      0x0000000000000000

    0x6021c0:       0x0000000000000000      0x0000000000000000

    0x6021d0:       0x0000000000000000      0x0000000000000000

此时的bins链

fastbins

    0x20: 0x0

    0x30: 0x0

    0x40: 0x0

    0x50: 0x0

    0x60: 0x0

    0x70: 0x0

    0x80: 0x0

    unsortedbin

    all: 0x0

    smallbins

    0x80: 0x602080 —? 0x7ffff7dd1be8 (main_arena+200) ?— 0x602080

    largebins

    empty

源代码二

#include<stdio.h>

#include<malloc.h>

#include<unistd.h>

#include<string.h>

int main(int argc,char *argv[])

{

     int size = 0x100;

     void *p = malloc(size);

     void *junk = malloc(size);     //创建以junk防止释放p,q时q的prev_inuse为0而合并

     void *q = malloc(size);

     void *r = malloc(size);          //防止q和top_chunk合并,在没有printf的前提下

     sleep(0);

     printf("p:0x%x\n",p);

     printf("q:0x%x\n",q);

     printf("r:0x%x\n",r);

     sleep(0);

     strcpy(p,"aaaaaaaaaaaaaaaaa");

     strcpy(q,"bbbbbbbbbbbbbbbbb");

     strcpy(r,"ccccccccccccccccc");

     sleep(0);

     free(p);

     free(q);

     sleep(0);

   return 0;

}

在不创建junc和r的情况下,p,q以及p,q,top_chunk会发生合并

#include<stdio.h>

#include<malloc.h>

#include<unistd.h>

#include<string.h>

int main(int argc,char *argv[])

{

     int size = 0x100;

     void *p = malloc(size);

     void *q = malloc(size);

     sleep(0);

     strcpy(p,"aaaaaaaaaaaaaaaaa");

     strcpy(q,"bbbbbbbbbbbbbbbbb");

     free(p);

     free(q);

     sleep(0);

   return 0;

}

---------------------------------------------------------------------------------------------------------------------------

0x602000 PREV_INUSE {                                     ===>p、q合并

  prev_size = 0, 

  size = 545, 

  fd = 0x7ffff7dd1b78 <main_arena+88>,  ===>fd指向main_arena

  bk = 0x7ffff7dd1b78 <main_arena+88>,  ===>bk指向main_arena

  // 因为当前只有一个main_arena只管理一个合并之后的堆块了

  fd_nextsize = 0x61, 

  bk_nextsize = 0x0

}

0x602220 {

  prev_size = 544, 

  size = 1040, 

  fd = 0x3132303678303a71,                          ===>print

  bk = 0xa3032, 

  fd_nextsize = 0x0, 

  bk_nextsize = 0x0

}

0x602630 PREV_INUSE {

  prev_size = 0, 

  size = 133585, 

  fd = 0x0, 

  bk = 0x0, 

  fd_nextsize = 0x0, 

  bk_nextsize = 0x0

此时的bins链

fastbins

0x20: 0x0

0x30: 0x0

0x40: 0x0

0x50: 0x0

0x60: 0x0

0x70: 0x0

0x80: 0x0

unsortedbin

all: 0x602000 —? 0x7ffff7dd1b78 (main_arena+88) ?— 0x602000 ==>只有一个合并之后的堆块

smallbins

empty

largebins

empty

(main_arena+88)的原因

main_arena的结构体前项变量:

__libc_lock_define (, mutex);       //定义了一个0x4字节的lock

int flags;                      //0x4

int have_fastchunks;                //0x4

mfastbinptr fastbinsY[NFASTBINS]; //fastbin链的管理头,总共10个, 每个0x10字节

mchunkptr top;      //0x4 到此为止总共0x96字节

注:glibc2.27为0x96

vmmap查看到(main_arena+88)出现在libc的地址范围

0x7ffff7dd1000 0x7ffff7dd3000 rw-p 2000 1c4000 /lib/x86_64-linux-gnu/libc-2.23.so

相同版本的libc,main_arena的偏移固定

main_arena的地址存放在0x602000中

pwndbg> x/20gz 0x602000

0x602000:   0x0000000000000000  0x0000000000000221

0x602010:   0x00007ffff7dd1b78  0x00007ffff7dd1b78

利用方法

overlap --> 打印当前堆块的内容 --> 获取main_arena的地址 --> 通过固定的偏移计算出libc的地址

当size大于0x400的时候,free之后的堆块首先会进入unsorted bin,触发整理后才会进入large bin

free掉0x400以上的堆块后,再malloc一个堆块,才会触发整理,进入到large bin如在源码二的最后加上malloc(0x2000),并把size改为0x1000

#include<stdio.h>

 #include<malloc.h>

 #include<unistd.h>

 #include<string.h>

 int main(int argc,char *argv[])

{

      int size = 0x1000;

      void *p = malloc(size);

      void *junk = malloc(size);

      void *q = malloc(size);

      void *r = malloc(size);

      sleep(0);

      printf("p:0x%x\n",p);

      printf("q:0x%x\n",q);

      printf("r:0x%x\n",r);

      strcpy(p,"aaaaaaaaaaaaaaaaa");

      strcpy(q,"bbbbbbbbbbbbbbbbb");

      strcpy(r,"ccccccccccccccccc");

      free(p);

      free(q);

      sleep(0);

      malloc(0x2000);

      sleep(0);                                                               

     return 0;

        } 

此时fd_nextsize和bk_nextsize有效

0x602000 PREV_INUSE {

  prev_size = 0, 

  size = 4113, 

  fd = 0x604020, 

  bk = 0x7ffff7dd2198 <main_arena+1656>, 

  fd_nextsize = 0x602000, 

  bk_nextsize = 0x602000

}

未malloc(2000)当前的bins链

fastbins

0x20: 0x0

0x30: 0x0

0x40: 0x0

0x50: 0x0

0x60: 0x0

0x70: 0x0

0x80: 0x0

unsortedbin

all: 0x604020 —? 0x602000 —? 0x7ffff7dd1b78 (main_arena+88) ?— 0x604020 /* ' @`' */

smallbins

empty

largebins

empty

malloc(0x2000)的bins链

fastbins

0x20: 0x0

0x30: 0x0

0x40: 0x0

0x50: 0x0

0x60: 0x0

0x70: 0x0

0x80: 0x0

unsortedbin

all: 0x0

smallbins

empty

largebins

0x1000: 0x602000 —? 0x604020 —? 0x7ffff7dd2198 (main_arena+1656) ?— 0x602000

对于新malloc的堆块大小,有这几种情况

0-0x999

0x1000-0x1008

0x1009以上

当size小于0x80的时候,free后会进入到fastbin

fastbins

0x20: 0x0

0x30: 0x0

0x40: 0x0

0x50: 0x0

0x60: 0x0

0x70: 0x6020e0 —? 0x602000 ?— 0x0   //p , q都进入fastbin

0x80: 0x0

unsortedbin

all: 0x0

smallbins

empty

largebins

empty

当malloc(0x60)的新chunk时,会首先从后free的0x6020e0中分配空间,分配之后,0x6020e0退出fastbin

0x70: 0x602000 ?— 0x0

源代码三

#include<stdio.h>

#include<stdlib.h>

#include<malloc.h>

#include<unistd.h>

#include<string.h>

#include<sys/types.h>

#include<pthread.h>

void* threadFunc(void* arg)

{

  int size = 0x200;

  sleep(0);

  void *q = malloc(size);

  printf("%p\n",q);

  sleep(0);

  free(q);

  sleep(0);

}

int main(int argc,char *argv[])

{

    int size = 0x100;

  void *p = malloc(size);

  free(p);

  pthread_t t1;

  void *s;

  int ret;

  ret = pthread_create(&t1,NULL,threadFunc,NULL);

    ret = pthread_join(t1,&s);

  return 0;

}

子线程的堆空间

pwndbg> c

Continuing.

0x7ffff00008c0        ==>第一个堆块

pwndbg>vmmap

 0x602000           0x623000 rw-p    21000 0      [heap]

    0x7ffff0000000     0x7ffff0021000 rw-p    21000 0 

    0x7ffff0021000     0x7ffff4000000 ---p  3fdf000 0     

   0x7ffff6fef000     0x7ffff6ff0000 ---p     1000 0 

查看内存布局

pwndbg> x/20gz 0x7ffff00008c0 -0x10

0x7ffff00008b0:  0x0000000000000000  0x0000000000000215   NO_MAIN_ARENA & PREV_INUSE = 5

0x7ffff00008c0:  0x0000000000000000  0x0000000000000000

0x7ffff00008d0:  0x0000000000000000  0x0000000000000000

0x7ffff00008e0:  0x0000000000000000  0x0000000000000000

偏移查看arena结构

pwndbg> x/100gz 0x7ffff00008c0 -0x10 + 0x200

0x7ffff0000ab0:  0x0000000000000000  0x0000000000000000

0x7ffff0000ac0:  0x0000000000000000  0x0000000000000415    ==>第二个堆块,分配了0x410的空间

0x7ffff0000ad0:  0x3066666666377830  0x000a306338303030     ==>printf的堆块

0x7ffff0000ae0:  0x0000000000000000  0x0000000000000000

pwndbg> x/s 0x7ffff0000ad0

0x7ffff0000ad0:  "0x7ffff00008c0\n"

pwndbg> x/20gz 0x7ffff00008c0 -0x10 + 0x200 + 0x420

0x7ffff0000ed0:  0x0000000000000000  0x0000000000020131     ==>子线程的top_chunk

0x7ffff0000ee0:  0x0000000000000000  0x0000000000000000

free掉q之后NO_MAIN_ARENA置0

pwndbg> x/20gz 0x7ffff00008c0 -0x10 

0x7ffff00008b0: 0x0000000000000000  0x0000000000000211

0x7ffff00008c0: 0x00007ffff0000078  0x00007ffff0000078      ==> 类似于主线程的main_arena + 88

pwndbg> x/20gz 0x00007ffff0000078

0x7ffff0000078: 0x00007ffff0000ed0  0x0000000000000000    ==> 子线程的top_chunk

0x7ffff0000088: 0x00007ffff00008b0  0x00007ffff00008b0    ==> 子线程的第一个堆块

0x7ffff0000098: 0x00007ffff0000088  0x00007ffff0000088 

0x7ffff00000a8: 0x00007ffff0000098  0x00007ffff0000098    

0x7ffff00000b8: 0x00007ffff00000a8  0x00007ffff00000a8

0x7ffff00000c8: 0x00007ffff00000b8  0x00007ffff00000b8

0x7ffff00000d8: 0x00007ffff00000c8  0x00007ffff00000c8

0x7ffff00000e8: 0x00007ffff00000d8  0x00007ffff00000d8

0x7ffff00000f8: 0x00007ffff00000e8  0x00007ffff00000e8

0x7ffff0000108: 0x00007ffff00000f8  0x00007ffff00000f8

//此这里可以leak main_arena的结构

实验总结

main_arena为主线程的arena

在第一次调用malloc之后,会用brk调用生成堆,并生成top_chunk之后分配的堆,都会从top_chunk上切割当top_chunk不够用时,会再次通过brk系统调用申请内存副线程的arena通过mmap获得,并也会生成top_chunk

好了,到这儿,二进制安全之堆溢出(系列)——堆基础 & 结构就更完了!!








二进制安全之堆溢出(系列)——堆基础 & 结构(四)的评论 (共 条)

分享到微博请遵守国家法律