https://exploit-exercises.com/nebula/level09/
Call getflag
from the level09 account.
There’s a C setuid wrapper for some vulnerable PHP code…
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;
?>
From Wikipedia:
Looking up the preg_replace
function shows us that it is meant to replace the portion of the string matched by the regex in the first
input with the second input. It also allows backreferences, so things matched inside ()
in the regex can be essentially passed to the
second string as \\n
or $n
, where \\n
will contain the string matched by the n-th parenthesis. So what this does is matches
[email blahblahblah]
and passes the blahblahblah
to the spam
function. (Note: the \e
at the end of the preg_replace
string
tells PHP to evaluate the result of the second string, so rather than this becoming "spam(blahblahblah)"
, it would evaluate spam
of blahblahblah
.
That /e
flag will evaluate anything inside the second string. This means that if we can put in code to call getflag
in there, PHP
will evaluate it and call getflag
. So we need to put something like system(getflag)
in there. To do this, we can just have the text
in our email block look like [email {${system(getflag)}}]
(Note: got the wacky PHP syntax from other solutions). When we try that,
we get:
PHP Notice: Undefined variable: You have successfully executed getflag on a target account
We did it!