Table of Contents
Description
Cet article explique comment exploiter les vulnérabilités d'injection SQL lorsque la base de données principale est MS Access. En particulier, l'article se concentre sur la façon d'exploiter les injection SQL aveugles. Après une introduction initiale sur les fonctions typiques qui sont utiles pour exploiter une vulnérabilité d'injection SQL, une méthode pour exploiter les Injection SQL aveugles sera abordée.
Test boîte noire
Test standard
En premier lieu, voyons un exemple typique d'erreur SQL qui peut être retournée lors d'un test:
Fatal error: Uncaught exception 'com_exception' with message 'Source: Microsoft JET Database Engine
Cela signifie que peut-être nous testons une application avec un backend de données MS Access.
Malheureusement, MS Access ne prend pas en charge tous les caractères de commentaire dans la requête SQL, il n'est donc pas possible d'utiliser l'astuce d'insérer les caractères /* ou # ou - pour tronquer la requête. D'autre part, nous pouvons heureusement contourner cette limite avec le caractère NULL. Si nous insérons le caractère %00 à un certain endroit dans la requête, tous les caractères restants après l'NULL sont ignorés. Cela arrive parce que, en interne, les chaînes sont terminée par NULL. Cependant, le caractère NULL peut parfois causer des problèmes. On peut remarquer qu'il y a une autre valeur qui peut être utilisée afin de tronquer la requête. Le caractère 0x16 (%16au format URL encodé) ou 22 en décimal. Donc, si nous avons la requête suivante:
SELECT [username],[password] FROM users WHERE [username]='$myUsername' AND [password]='$myPassword'
nous pouvons tronquer la requête avec de deux manières suivantes:
http://www.example.com/index.php?user=admin'%00&pass=foo http://www.example.com/index.php?user=admin'%16&pass=foo
Enumération des Attributs
Afin d'énumérer les attributs d'une requête, il est possible d'utiliser la même méthode utilisée pour le serveur de base de données MS SQL. En bref, nous pouvons obtenir le nom des attributs de messages d'erreur. Par exemple, si nous connaissons l'existence d'un paramètre, car nous l'avons obtenu par un message d'erreur en raison du caractère ', nous pouvons également connaître le nom des autres attributs de la requête suivante:
' GROUP BY Id%00
Dans le message d'erreur reçu, nous pouvons voir que le nom de l'attribut suivant est affiché. Nous pouvons itérer la méthode jusqu'à ce que nous obtenions le nom de tous les attributs. Si nous ne connaissons pas le nom d'au moins un attribut, nous pouvons insérer un nom de colonne fictive, et, comme par magie, on obtient le nom du premier attribut.
Obtention des tables de schéma de base de données
Il existe différentes tables dans MS Access qui peuvent être utilisée pour obtenir le nom d'une table dans une base de données particulière. Dans la configuration par défaut ces tables ne sont pas accessibles, cependant il est possible d'essayer. Les noms de ces tables sont les suivantes:
MsysObjects MsysACEs MsysAccessXML
Par exemple, si une vulnérabilité d'injection SQL union existe, vous pouvez utiliser la requête suivante:
' UNION SELECT Name FROM MSysObjects WHERE Type = 1%00
Ce sont les principales voies que vous pouvez utiliser pour exploiter une vulnérabilité d'injection SQL sur MS Access.
Il y a aussi quelques fonctions qui peuvent être utiles pour exploiter des requêtes personnalisées. Certaines de ces fonctions sont les suivantes:
ASC: Obtenir la valeur ASCII d'un caractère transmis en entrée
CHR: Retourne le caractère de la valeur ASCII transmis en entrée
LEN: Retourne la longueur de la chaîne passée en paramètre
IIF: Fonction d'évaluation conditionnelle, par exemple la déclaration suivante IIF (1 = 1, 'a', 'b') retourne » 'a'
MID: Fonction permettant d'extraire une sous-chaîne, par exemple la déclaration suivante ('abc', 1,1) retour 'a'
TOP: Fonction permettant de spécifier le nombre maximum de résultats que la requête doit retourner à partir du haut. Par exemple TOP 1 retournera seulement 1 rangée.
LAST: Fonction permettant de sélectionner uniquement la dernière ligne d'un ensemble de lignes. Par exemple, la requête suivante SELECT LAST(*) FROM utilisateurs ne renverra que la dernière ligne du résultat.
Certaines de ces fonctions seront utilisées pour exploiter une injection SQL aveugle comme nous le verrons dans le paragraphe suivant. Pour d'autres fonctions s'il vous plaît se référer aux manuels de références.
Injection SQL aveugle
Les tests de vulnérabilités d'injection SQL aveugles sont en aucun cas les types les plus fréquents que vous trouverez. Généralement, vous trouverez une injection SQL dans un paramètre si aucune requête d'union est possible. En outre, le plus souvent, il n'y a aucune chance d'exécuter des commandes shell ou de lire / écrire un fichier. Tout ce que vous pouvez faire est de déduire le résultat de votre requête. Pour notre test, nous prenons l'exemple suivant:
http://www.example.com/index.php?myId=[sql]
où le paramètre id est utilisé dans la requête suivante:
SELECT * FROM orders WHERE [id]=$myId
Pour notre test, nous allons considérer le paramètre myId vulnérable à l'injection SQL aveugle. Nous voulons extraire le contenu de la table users, en particulier, de la colonne nom d'utilisateur (nous avons déjà vu comment obtenir le nom des attributs grâce aux messages d'erreur et autres techniques). Il est supposé que le lecteur connaît déjà la théorie de l'attaque par injection SQL aveugle, donc nous allons directement montrer quelques exemples. Une requête typique qui peut être utilisée pour déduire le premier caractère du nom d'utilisateur de la énième ligne (10 dans l'exemple) est la suivante:
http://www.example.com/index.php?id=IIF((select%20mid(last(username),1,1)%20from%20(select%20top%2010%20username%20from%20users))='a',0,'ko')
Si le premier caractère est 'a', cette requête va renvoyer un 0 (une «réponse vraie »), sinon une chaîne de caractères «ko». Maintenant, nous allons expliquer pourquoi nous avons utilisé cette requête particulière. La première chose à remarquer est que, avec les fonctions l'IFF, MID et LAST, nous avons extrait le premier caractère du nom d'utilisateur de la ligne sélectionnée. Malheureusement, la requête initiale renvoie un jeu d'enregistrements et non un seul enregistrement, nous ne pouvons pas utiliser cette méthode directement. Il faut d'abord sélectionner une seule ligne. Nous pouvons utiliser la fonction TOP, mais il ne fonctionne qu'avec la première rangée. Pour sélectionner les autres requêtes, nous devons utiliser une astuce. Nous voulons déduire le nom d'utilisateur le numéro 10 affilée. Premièrement, nous utilisons la fonction HAUT pour sélectionner les dix premières lignes avec la requête:
SELECT TOP 10 username FROM users
Ensuite, nous extrayons de cet ensemble la dernière ligne avec la dernière fonction. Une fois que nous avons une seule ligne et exactement la ligne que nous voulons, nous pouvons utiliser les fonctions IFF, MID et LAST d'en déduire la valeur de l'identifiant. Il peut être intéressant de noter l'utilisation de la fonction IFF. Dans notre exemple, nous utilisons IFF pour retourner un nombre ou une chaîne. Avec cette astuce, nous pouvons distinguer quand nous avons une réponse vraie ou non. C'est parce que id est de type numérique, si on le compare à une chaîne, on obtient une erreur SQL, sinon avec la valeur 0, nous n'avons pas d'erreur. Bien sûr, si le paramètre est de type chaîne de caractères, nous pouvons utiliser des valeurs différentes. Par exemple, nous pouvons avoir la requête suivante:
http://www.example.com/index.php?id='%20AND%201=0%20OR%20'a'=IIF((select%20mid(last(username),1,1)%20from%20(select%20top%2010%20username%20from%20users))='a','a','b')%00
qui renvoie une requête qui est toujours vrai si le premier caractère est 'a' ou une requête qui est toujours fausse dans d'autre cas.
Cette méthode nous permet de déduire la valeur de l'identifiant. Pour déterminer quand nous avons obtenu la valeur totale, nous avons deux choix:
Nous essayons toutes les valeurs possibles, quand aucune n'est valide, alors nous avons la valeur complète. Nous pouvons déduire la longueur de la valeur (si c'est une valeur de chaîne, nous pouvons utiliser la fonction LEN) et arrêter quand nous avons trouvé tous les caractères.
Astuces :
Parfois, nous sommes bloqués par une fonction de filtrage. Ici, nous voyons quelques astuces pour contourner ces filtres.
Délimiteur alternatif
Certains filtres enlèvent l'espace de la chaîne entrée. Nous pouvons contourner ces filtres en utilisant les valeurs suivantes comme séparateur au lieu de l'espace blanc:
9 a c d 20 2b 2d 3d
Par exemple, nous pouvons exécuter la requête suivante:
http://www.example.com/index.php?username=foo%27%09or%09%271%27%09=%09%271
pour contourner un formulaire de connexion
