(Update 05/2019: Made a note that this method is now patched in glibc>=2.29
)
The “House of Force” is a glibc
heap overflow exploitation technique first named in the archived email “Malloc Maleficarum” by Phantasmal Phantasmagoria, and subsequently a PoC surfaced online in the Phrack magazine.
Vector
The House of Force technique overwrites the top chunk of the heap in order to fabricate a memory allocation that will return an arbitrary memory region. By tampering the size of top chunk to a very large value and allocating a chunk with an attacker-controlled size, the top chunk can be set to a desired arbitrary memory location so that the next allocation from the top chunk will produce a chunk at the desired memory location. This results in a write-what-where condition which the exploit developer may leverage to achieve arbitrary code execution.
Requirements
There are some requirements that the adversary must meet:
- A heap overflow vulnerability must exist in the application.
- The
top
chunkmchunk_size
field must be reachable by the heap overflow. - The ability to invoke the memory allocator for an arbitrarily-sized chunk twice, and be able to write arbitrary data to it.
- The ability to leak the address of the
libc
base (in an ASLR-enabled system)
Example
(Refer to the vulnerable C menu-style application and the exploit script)
The vulnerable code begins with one memory allocation. Using the heap overflow vulnerability, we write into the allocated memory space and overflow into the top chunk. The mchunk_size
field of the top chunk will be overwritten with an arbitrarily large value (e.g. 0xffffffffffffffff
). Since we require control over allocation sizes, we can exploit this by requesting allocations with incredibly large sizes so that our allocations will end up in locations of our own choosing.
The first step in exploiting a heap overflow would be to leak some libc
address. We have a memory address conveniently planted in the PoC which gives us the address of __malloc_hook
, from which we may easily calculate the address of any desired libc
function (since we also know the version of libc
used). This leak gives for a more reliable exploit in the face of ASLR and PIC. Additionally, the stack is unused and no shellcode is injected, so stack canaries/protection and DEP are moot here.
For arbitrary code execution, we overwrite the .got.plt
entry of __malloc_hook
with system
. We can also calculate the position of the /bin/sh
string in libc
using the leaked address. Now that we have changed the .got.plt
entry, every time malloc()
is invoked, system
will be called instead of __malloc_hook
and the first argument to system
will be the first argument to malloc()
.
def exploit_house_of_force(ps, leaked_addr, system_addr, binsh_addr, interactive=False):
# Allocate a chunk
first_slot = ps.alloc(256)
# Overwrite mchunk_size field of the top chunk
ps.write(first_slot, "\xff"*(256 + 2*PTR_BYTES))
# Allocate a chunk large enough so that it ends before __malloc_hook,
# referencing the leaked libc address minus the 256-byte chunk that
# we allocated earlier.
second_slot = ps.alloc(leaked_addr - 2*PTR_BYTES - (slots[0] + 256 + PTR_BYTES))
# Allocate another chunk
last_slot = ps.alloc(256)
# Write data into the last chunk, which should overwrite __malloc_hook
ps.write(last_slot, p64(system_addr))
# Invoke malloc with /bin/sh string
return ps.try_spawn_shell(binsh_addr, interactive)
Note
An mchunk_size
field check for the top chunk was implemented in glibc>=2.29
by making sure it is sane (no more than the arena heap size), effectively killing this exploit mechanism.
victim = av->top;
size = chunksize (victim);
if (__glibc_unlikely (size > av->system_mem))
malloc_printerr ("malloc(): corrupted top size");