CTFLearn: SimpleBOF
This challenge is an amazing introduction to Buffer Overflows. Try to do it without looking anything up, just by experimenting with how the buffer changes depending on your input. Having the visualization is so helpful.
Binary Challenge
I suck at pwn/RE. This was my first BOF ever. 😮
They include the code, and have a really nice visualization of the stack which is really nice.
Walking through the code we have the following variables, which can be seen in the stack visualization in the order they are allocated (except for buff and padding).
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.
We can see the variables:
buff is at the top of the stack, it occupies 32 bytes, which are all set to 0.
padding is after buffer, it occupies 16 bytes which are all set to ff
secret is seen after, occupying 8 bytes, in reverse order in the visualization.
notsecret is last, also occupying 8 bytes.
The rest of the vuln() function makes it obvious what we are supposed to do with the buffer.
printf("Input some text: ");
gets(buff); // This is a vulnerable call!
// 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);
}
We need to overflow the buffer buff, and the buffer padding which follows it in order to write to the addresses in the stack after it, and overwrite value of secret to be 0x6716c66
Since we know the length of the buffer is 32 bytes lets see what happens when we write 33 bytes to it.
crazyeights@es-base:~$ python3 -c 'print("A"*33)'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
We can see the buffer buff now extends into padding, with the first 2 bytes being overwritten.
The character A is equal to 0x41 in hex, which appears in the visualization.
What happens when we write 48 bytes to the buffer (size of buff + size of padding)?
We overwrite the first byte of the secret, which follows padding in the stack, is it because of the newline character or because of the null terminator at the end of the string? I am not sure.
We know that a stack is LIFO (Last in First Out) which is why things appear backwards, so when we want overwrite the secret to match 0x6716c66
we want to start at the end.
We also know what we write to the buffer in ascii appears as hex in the stack, so convert 66 from hex we get f. When we write f at the end of the string of 48 A’s we get:
The 66 is highlighted to show it is correct. Now we repeat the for the rest of 0x6716c66
and we get:
f = 66
l = 6c
a = 61
g = 67
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAflag
so we must be on the right track.
Testing it out:
We can now see that the buffer matches 0x6716c66
in the stack, and we have received the flag.
This challenge was pretty awesome. Although I solved it and didn’t find it particularly hard, I have no idea how to do a BOF without this nice visual, and I still suck at pwn. 😐
FIN. 🥳