OverTheWire Wargames :: Natas :: Level 21
Level 21 > Level 22
Source, cleaned up.
<h1>natas21</h1>
<div id="content">
<p>
<b>Note: this website is colocated with <a href="http://natas21-experimenter.natas.labs.overthewire.org">http://natas21-experimenter.natas.labs.overthewire.org</a></b>
</p>
<?
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: natas22\n";
print "Password: <censored></pre>";
} else {
print "You are logged in as a regular user. Login as an admin to retrieve credentials for natas22.";
}
}
session_start();
print_credentials();
?>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
<h1>natas21 - CSS style experimenter</h1>
<div id="content">
<p>
<b>Note: this website is colocated with <a href="http://natas21.natas.labs.overthewire.org">http://natas21.natas.labs.overthewire.org</a></b>
</p>
<?
session_start();
// if update was submitted, store it
if(array_key_exists("submit", $_REQUEST)) {
foreach($_REQUEST as $key => $val) {
$_SESSION[$key] = $val;
}
}
if(array_key_exists("debug", $_GET)) {
print "[DEBUG] Session contents:<br>";
print_r($_SESSION);
}
// only allow these keys
$validkeys = array("align" => "center", "fontsize" => "100%", "bgcolor" => "yellow");
$form = "";
$form .= '<form action="index.php" method="POST">';
foreach($validkeys as $key => $defval) {
$val = $defval;
if(array_key_exists($key, $_SESSION)) {
$val = $_SESSION[$key];
} else {
$_SESSION[$key] = $val;
}
$form .= "$key: <input name='$key' value='$val' /><br>";
}
$form .= '<input type="submit" name="submit" value="Update" />';
$form .= '</form>';
$style = "background-color: ".$_SESSION["bgcolor"]."; text-align: ".$_SESSION["align"]."; font-size: ".$_SESSION["fontsize"].";";
$example = "<div style='$style'>Hello world!</div>";
?>
<p>Example:</p>
<?=$example?>
<p>Change example values here:</p>
<?=$form?>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
Interesting - this time the main page is nothing but a check that the admin
session variable is equal to 1. Given that there is a second page, it’s pretty safe to assume the vulnerability is there.
Indeed, here it is on the ‘experimenter’ page.
// if update was submitted, store it
if(array_key_exists("submit", $_REQUEST)) {
foreach($_REQUEST as $key => $val) {
$_SESSION[$key] = $val;
}
}
Later in the code there is some mumbo-jumbo about “allow only these keys” and a white-listed array, but the fact is the loop above sucks in everything from $_REQUEST
and dumps it in $_SESSION
.
I assume that since these pages are explicitly related, they share session variables. One primary purpose of session variables is to maintain state across different pages of a web application, so it’s reasonable to assume that if I can get the admin
variable into the ‘experimenter’ page, it will be there on a load of the main page.
Also, note the debug
option pulled out of $_GET
- might as well use that to monitor things.
First I’ll load the experimenter page with no cookies to get a clean session cookie…
Then, using the new session cookie, add an admin=1
to a POST of the experimenter page. The debug option shows the variable is successfully loaded into the session.
Finally, GET the main page.
Donezo. The same flow could easily have been accomplished using the local proxy to add the POST parameter, or by editing the form HTML using the browser’s developer tools.
chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ