Les SQL truncations : Une faille méconnue, mais très efficace

Par Geluchat, ven. 30 janvier 2015, dans la catégorie Journal de geluchat

Failles Web, SQL, Tutoriel

Aujourd'hui, j'ai le plaisir de vous présenter le premier article du site, il concernera les SQL truncations. Il est très probable que vous n'en ayez jamais entendu parler car les failles liées à SQL sont noyées par les SQL injections et les bypass en tout genre.

Alors, une SQL truncation, ça ressemble à quoi? Et bien, ça n'est pas très difficile à appréhender.

Prenons l'exemple du script SQL suivant:

CREATE TABLE TEST_DAILYSECURITY(
    id int NOT NULL AUTO_INCREMENT,
    login VARCHAR(12),
    password CHAR(32),
    PRIMARY KEY (id)
);
INSERT INTO TEST_DAILYSECURITY VALUES(default,'admin                       x','mdp');

Avec un select de la table, on obtient:

SELECT login, password FROM TEST_DAILYSECURITY;
+---------+------------+
| login   | password   |
+---------+------------+
| admin   | mdp        |
+---------+------------+
1 row in set (0.00 sec)

Le résultat est sans appel, le login a été tronqué par mysql.

Mais pourquoi? Pour les plus observateurs, vous aurez remarqué que le champ login est un varchar de 12 caractères, donc mysql ne réfléchit pas, il enregistre dans l'espace qu'on lui a réservé, d’où la troncation du login.

Remarque : MySQL efface les espaces derrière pour une raison d'optimisation de stockage.

Maintenant, à quoi ça sert?

Les exemples d'exploitation de cette faille sont multiples:

SELECT id FROM TEST_DAILYSECURITY WHERE login='admin' AND password='$_POST[password]';

Suivi d'un test d'un type mysql_num_rows > 0 , l'utilisateur aurait accès au panel d’administration.

    $db = mysql_connect('localhost', 'root', '');
    mysql_select_db('TEST_DAILYSECURITYDB',$db);

    if(isset($_POST['password']))
    {
       $sql = "SELECT id FROM TEST_DAILYSECURITY WHERE login='admin' AND password='".mysql_real_escape_string($_POST['password'])."'";
       $req = mysql_query($sql) or die('Erreur SQL !'.$sql.''.mysql_error());

       if(mysql_num_rows($req)> 0 ) // Si la requête retourne au moins un résultat, on accède à la zone administrateur
       {
          // ZONE ADMIN
          echo 'Bienvenue Administrateur';
       }
       else
       {
          header('Location: '.$_SERVER['HTTP_REFERER']);
          exit(0);
       }
    }
    else
    {
       echo '<form action="" method="POST">
               Password: <input type="password" name="password"></ br>
               <input type="submit" name="Se Connecter">
             </form>';
    }
    mysql_close();
    INSERT INTO TEST_DAILYSECURITY VALUES(default,'$_POST[login]','$_POST[password]');
    -- Si le login est supérieur à 12 il sera tronqué
    INSERT INTO AUTRE TABLE_AVEC_IDUSER VALUES(default,(SELECT id FROM TEST_DAILYSECURITY WHERE login='$_POST[login]'));
    -- Cette table contiendrait des données incorrectes, je vous laisse imaginer si c'était la table gérant les privilèges utilisateurs...

On a donc pu voir que les SQL truncations sont très dangereuses et fortement méconnues. A savoir que la faille fonctionne aussi sous PDO.

La solution, pour patcher cette faille, est très simple:

if(isset($_POST['login']) && strlen($_POST['login'])>12)
{
    echo "Veuillez rentrer un login inférieur à 12 caractères";
}
else
{
  // Vérification connexion administrateur et formulaire de connexion
}

Voila, c'est déjà terminé, n'hésitez pas à rejoindre mon Twitter pour avoir des news sur le site et mon point de vue sur l'actualité de la sécurité informatique.

Geluchat.