This page has been robot translated, sorry for typos if any. Original content here.

Quelques vulnérabilités dans les ressources Web utilisant SQL


La note traite de la vulnérabilité SQL associée à la pénétration dans le corps de la requête.

L'essence de la vulnérabilité

Considérez le travail du système le plus simple avec une interface Web, ce qui permet aux utilisateurs de sauvegarder également des informations les concernant. Ces systèmes sont parmi les plus courants du réseau. Il peut également exister un livre d'or, une discussion en ligne, une galerie de photos et un service de courrier électronique.

La requête générée à la base de données est obligée d'avoir un identifiant ainsi que le mot de passe entré par l'utilisateur. Sur la base de ces champs, la base de données devrait trouver l'enregistrement correspondant dans la table. Une fois la demande terminée, la base de données renvoie les informations trouvées sur l'utilisateur, que le script PHP établit comme HTML, donne également à l'utilisateur.

Prenons un fragment assez typique d'un script PHP utilisant une requête SQL pour accéder à la base de données:

<? php
$ result = mysql_db_query ("database", "select * from userTable où login =" $ userLogin "et password =" $ userPassword "");
while ($ row = mysql_fetch_array ($ result)) {
echo $ row ["nom complet"];
echo $ row ["email"];
echo $ row ["mot de passe"];
}
mysql_free_result ($ result);
?>

Comme nous le constatons, l'identifiant est également le mot de passe saisi par l'utilisateur contenu dans les variables $ userLogin et $ userPassword . Le contenu de ces variables est inséré dans la demande de filtrage des informations sur cet utilisateur. Le filtre est spécifié à l'aide de l'option where de la commande select SQL. Dans ce cas, la requête ressemble à ceci: sélectionnez * à partir de la table utilisateur login = '$ userLogin' et mot de passe = '$ utilisateurPassword' où tableTable est le nom de la table contenant les informations requises. Si les variables login et password contiennent également les valeurs vanya et vasya , la requête envoyée à la base de données ressemblera à ceci: select * from userTable login = 'vanya' et password = 'vasya' . Il est clair que s'il existe une entrée dans la base de données dans laquelle l'identifiant est vanya, mais que le mot de passe est vasya , jusqu'à la demande, il n'enverra pas une seule ligne à partir de la base de données et le script ne produira rien. Ainsi, le système ci-dessus ne donne accès aux informations qu'à un utilisateur disposant d'un mot de passe et d'une connexion sans erreur.

Il semblerait qu'un tel système ne contient pas de défauts. Dans la leçon elle-même, ce n'est pas le cas. La logique des programmeurs qui ont créé l'exemple ci-dessus implique que le nom d'utilisateur et le mot de passe entrés par l'utilisateur soient contenus entre guillemets simples et codés en dur dans le corps de la demande. Voyons cependant ce qui se passe si le mot de passe saisi par l'utilisateur contient lui-même un guillemet. Confiez- lui la valeur vas'ya , tandis que la demande prendra la forme suivante: sélectionnez * à partir de la table utilisateur login = 'vanya' et mot de passe = 'vas'ya' . Lors de l'exécution d'une telle requête, une erreur va certainement se produire, car le guillemet du mot de passe ferme le guillemet d'ouverture de la requête, ainsi la fin du mot de passe ya ' est resté "suspendu" en dehors de l'expression conditionnelle.

Et si vous insérez la ligne suivante comme mot de passe: 'ou 1 = 1' , la requête deviendra la suivante: select * from userTable login = 'vanya' et password = '' ou 1 = 1 '' n'auront pas non plus d'erreur de syntaxe . Mais l'expression logique deviendra identiquement vraie, également en opposition à cette requête, SQL retournera la base de données utilisateur complète 8-).

Ainsi, en utilisant le symbole apostrophe, nous pouvons également pénétrer dans le corps de la requête SQL pour rendre la condition vérifiée vraie. Si nous sommes intéressés par un utilisateur particulier vanya , pour obtenir des informations à son sujet, il est autorisé d'utiliser la ligne de mot de passe suivante: 'ou login =' vanya . La demande devient: select * from userTable login = 'vanya' et password = '' ou login = 'vanya' . Comme vous le savez, nous obtenons des informations sur vanya .

La vulnérabilité décrite des services basés sur SQL ne se limite pas à la réception non autorisée d'informations. MySQL étant généralement utilisé dans de tels systèmes, il est possible non seulement de modifier l'expression conditionnelle dans la commande select, mais également d'aller au-delà de cette commande et d'exécuter une autre commande de base de données. Depuis MySQL permet plusieurs commandes dans une seule requête, séparés ; , alors nous pouvons exécuter n’importe laquelle de ces commandes en entrant le code suivant dans le champ mot de passe: '; <Commande SQL> à quel endroit en tant que commande <sql>, il est permis de spécifier toute commande valide. Ainsi, par exemple, un tel code: '; drop table 'userTable va simplement détruire la table userTable de la base de données.

Utilisation pratique de la vulnérabilité

Malgré sa simplicité, l'utilisation pratique des erreurs de requête SQL est très difficile.

Dans cette tête, nous examinons les problèmes suivants qui surviennent lors de l’utilisation de la vulnérabilité décrite:
  • Déterminer le fait d'utiliser SQL dans le système.
  • Identification de l'existence d'une vulnérabilité. Connaître la réaction du script aux erreurs.
  • Définir les noms de champs dans une table.
  • Définir les noms des tables existantes.

    La vulnérabilité considérée est inhérente à toutes les requêtes SQL, quel que soit le script ou le programme d'où elles sont appelées. Néanmoins, nous allons considérer les systèmes basés sur PHP. En effet, le flux d’erreurs PHP en tant que position (par défaut) est dirigé vers l’utilisateur final. Dans le même temps, les applications Perl ou Exe n'informent généralement pas l'utilisateur de la nature des erreurs.

    Déterminer le fait d'utiliser SQL dans le système.

    Lorsque vous recherchez un système spécifique, vous devez d’abord déterminer s’il utilise SQL.
    Ce fait peut être détecté soit indirectement (en regardant les noms des fichiers utilisés, des liens vers les outils utilisés, etc.), soit directement, ce qui obligera SQL à faire ses preuves. Si nous travaillons avec PHP, alors il n'y a qu'un seul moyen de déterminer sans ambiguïté l'utilisation de SQL - cela provoquera une erreur dans son exécution. Si une erreur survient lors de l’exécution de la demande, le script PHP ne traite clairement aucune erreur, le message d’erreur PHP sera envoyé directement à la page de l’utilisateur.
    Comment provoquer une erreur dans l’exécution d’une requête SQL dépend du périphérique du système en question. Dans la plupart des cas, une erreur peut être provoquée par la saisie de données incorrectes dans le système.

    Identification de l'existence d'une vulnérabilité. Connaître la réaction du script aux erreurs.

    Le moyen le plus simple de détecter la présence d’une vulnérabilité, mais également d’utiliser SQL, est le suivant: Dans tout champ supposé participer à la formation de la requête SQL (par exemple, le champ Login ou Mot de passe ), entrez un guillemet simple. Les champs restants sont remplis avec toutes les données valides (ou laissés en blanc si le système le permet). Après avoir envoyé ces formulaires, nous examinons la réaction du système. Si, par conséquent, le script PHP génère une erreur SQL, nous pouvons nous en féliciter: le système utilise SQL et le script ne filtre aucun guillemet. Ce système alimentaire contient une vulnérabilité.
    L'erreur de requête SQL ressemblera alors à ceci sur la page:

    Formulaire de saisie de données:


    En conséquence, une erreur de requête SQL:


    S'il n'y a pas de code d'erreur SQL sur la page, cela peut signifier que:
    1) Le système contient une vulnérabilité, mais le script PHP traite les erreurs. Dans ce cas, le système est autorisé à être piraté, mais vous devrez agir «au toucher», car nous ne saurons pas à quel moment la syntaxe SQL sera correcte, mais à quel moment.
    2) Le script filtre le guillemet également, par conséquent, les erreurs ne se produisent pas. Dans ce cas, le système ne contient aucune vulnérabilité.
    3) Le système général n'utilise aucunement SQL.
    Dans les deux derniers cas, il est clair que les recherches SQL ultérieures n’ont aucun sens.

    Définir les noms de champs dans une table.

    Pour obtenir des informations d'une base de données contenant des données spécifiques, nous devons déterminer les valeurs de certains champs de la demande (par exemple, définir le nom d'utilisateur). Cependant, pour cela, vous devez connaître le nom des champs correspondants. Il n'y a pas de possibilité directe de trouver ces noms. Par conséquent, vous devrez rechercher ces noms par force brute. Les noms de données peuvent coïncider avec les noms des champs du formulaire envoyé au serveur, ou ne pas coïncider de quelque manière que ce soit. C’est une bonne chose que les noms des champs en tant que position soient standard et qu’il n’y ait pas beaucoup d’options pour les écrire. Ainsi, par exemple, le nom du champ pour le nom d'utilisateur deviendra très probablement l' identifiant d' utilisateur ou le pseudonyme . Semblable pour mot de passe: mot de passe est mot de passe ou passe .
    Pour déterminer l’existence d’un champ spécifique, une méthode ingénieuse est proposée: vérifions si le champ pwd existe dans la table. Introduisez la chaîne 'pwd =' dans n'importe quel champ de formulaire. Si le champ pwd existe dans la table, alors SQL traitera correctement la requête, sinon l'erreur d'exécution se produira. Ainsi, en substituant différentes valeurs aux noms de champs tout en examinant également le résultat de la fin de la requête, nous pouvons déterminer quels champs existent dans la table, mais lesquels n'existent pas.

    Définir les noms des tables existantes.

    Semblable à la méthode de recherche des noms de champs dans les tables, il est également possible de rechercher les noms des tables existantes dans la base de données. Supposons que nous voulions savoir si la table adminList existe dans la base de données. Pour ce faire, entrez la ligne suivante dans le champ de formulaire «; sélectionnez * dans la liste adminList . Si, à la suite de l'erreur, SQL ne démarre pas du tout, la table adminList existe. Pour l'exactitude de ce test, vous devez entrer cette ligne dans le champ qui apparaît final dans la requête SQL. Cela est nécessaire pour éviter toute erreur de syntaxe due à la fin de la requête d'origine, qui sera présente ultérieurement. Sélectionnez * dans adminList . Notez que si une paire de champs de connexion et de mot de passe possède également la vue pour la demande, le champ de mot de passe sera probablement le dernier à apparaître dans la demande.

    PS

    En utilisant cette vulnérabilité, le site http://www.bigmir.net a été piraté (plus précisément, sa galerie de photos est aussi un chat). Nous avons signalé la vulnérabilité aux propriétaires du site. Le trou était réparé. Mais maintenant, nous avons à nouveau vérifié le formulaire d'inscription au chat. De plus, j'ai trouvé toute cette vulnérabilité bla bla 8-).