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

Certaines vulnérabilités des ressources Web utilisant SQL


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

L'essence de la vulnérabilité

Envisagez le fonctionnement d'un système simple avec une interface WEB, qui permet aux utilisateurs de sauvegarder également pour changer les informations les concernant. Ces systèmes sont l’un des plus courants du réseau. Il peut également s'agir d'un livre d'or, d'un salon de discussion, d'une galerie de photos et d'un service postal.

La requête générée dans la base de données doit obligatoirement avoir le login de l'utilisateur ainsi que le mot de passe entré par l'utilisateur. Pour ces champs, la base de données doit trouver l'entrée correspondante dans la table. Une fois la requête terminée, la base de données affiche les informations relatives à l'utilisateur, que le script PHP crée sous la forme HTML, également à l'utilisateur.

Regardons un fragment de script PHP assez typique qui utilise la 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 ["fullname"];
echo $ row ["email"];
echo $ row ["password"];
}
mysql_free_result ($ result);
?>

Comme nous l’observons, le login également le mot de passe saisi par l’utilisateur est contenu dans les variables $ userLogin aussi $ userPassword . Le contenu de ces variables est inséré dans la requête pour filtrer les informations relatives à cet utilisateur. Le filtre est spécifié en utilisant l'option where de la commande SQL select . Dans ce cas, la requête ressemble à ceci: select * from userTable login = '$ userLogin' et password = '$ userPassword' où userTable est le nom de la table contenant les informations requises. Si le changement du nom de connexion du mot de passe contient également les valeurs vanya , puis vasya, respectivement, la requête envoyée par la base de données prendra la forme suivante: select * from userTable login = 'vanya' et password = 'vasya' . Il est clair que s'il y a une entrée dans la base de données où le login est vanya, alors le mot de passe est vasya , jusqu'à ce que la requête n'envoie pas une seule ligne de la base, et le script ne renverra rien. Ainsi, le système ci-dessus permet d’accéder aux informations uniquement à l’utilisateur qui dispose d’un mot de passe sans erreur et qui s’identifie également.

Il semblerait qu'un tel système ne comporte pas de défauts. Dans la classe elle-même, ce n'est pas le cas. La logique des programmes qui ont créé l'exemple ci-dessus suppose que la connexion saisie par l'utilisateur est également un mot de passe qui sera contenu dans des guillemets simples codés en dur dans le corps de la requête. Cependant, voyons ce qui se passe si le mot de passe lui-même, saisi par l'utilisateur, contient un guillemet. Laissez-le posséder la valeur de vas'ya , alors que la requête ressemblera à ceci: select * from userTable login = 'vanya' et password = 'vas'ya' . Lors de l'exécution d'une telle demande, il y aura certainement une erreur, car la citation du mot de passe a fermé la citation initiale de la requête, et la fin du mot de passe est restée 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 :: select * from userTable login = 'vanya' et password = '' ou 1 = 1 '' également sans erreur de syntaxe . Mais l'expression logique sera identiquement vraie, même dans une objection à cette requête, SQL émettra l'intégralité de la base de données utilisateur 8-).

Ainsi, en utilisant le symbole de l'apostrophe, nous pouvons également faire en sorte que la condition vérifiée soit vraie dans le corps de la requête SQL. Si un utilisateur particulier de vanya nous intéresse, alors pour recevoir des informations à son sujet, il est autorisé à utiliser une telle ligne de mot de passe: 'ou login =' vanya . La requête devient: select * from userTable login = 'vanya' et password = '' ou login = 'vanya' . Comme vous le comprenez, nous recevrons 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. Comme MySQL est utilisé dans de tels systèmes, il est possible non seulement de modifier l'expression conditionnelle dans la commande select, mais aussi d'aller au-delà de cette commande et d'exécuter une autre commande de base de données. Parce que MySQL autorise plusieurs commandes dans une requête, séparées ; , alors nous pouvons exécuter n'importe laquelle de ces commandes en tapant le code suivant dans le champ mot de passe: '; <Commande SQL> à quel endroit la commande <SQL> est autorisée à spécifier une commande valide. Ainsi, par exemple, un tel code: '; drop table 'userTable détruit simplement la table userTable de la base de données.

Utilisation pratique de la vulnérabilité

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

Dans cette section, considérez les problèmes suivants qui surviennent lors de l'utilisation de la vulnérabilité décrite:
  • Déterminer l'utilisation de SQL dans le système.
  • Identifier l'existence d'une vulnérabilité. Elucidation de la réponse du script aux erreurs.
  • Définissez les noms des champs dans la table.
  • Définir les noms des tables existantes.

    Cette vulnérabilité est inhérente à toutes les requêtes SQL, quel que soit le script ou le programme à partir duquel elles sont appelées. Pourtant, nous considérerons des systèmes basés sur PHP. Cela est dû au fait que le flux d’erreur PHP en tant qu’emplacement (par défaut) est envoyé à l’utilisateur final. Bien que les applications Perl ou Exe n'informent généralement pas l'utilisateur de la nature des erreurs.

    Déterminer l'utilisation de SQL dans le système.

    Lors de la recherche d'un système particulier, vous devez d'abord savoir s'il utilise SQL.
    Ce fait peut être détecté soit indirectement (en examinant les noms des fichiers utilisés, les liens vers les outils utilisés, etc.), soit directement - en faisant en sorte que SQL fasse ses preuves. Si nous travaillons avec PHP, il n'y a qu'un seul outil pour identifier de manière unique l'utilisation de SQL - cela provoque une erreur dans son exécution. Si une erreur survient lors de l'exécution de la requête, cependant, le script PHP ne commet aucune erreur explicite, le message concernant l'erreur de PHP sera directement envoyé à la page de l'utilisateur.
    La façon de provoquer une erreur dans l'exécution d'une requête SQL dépend du système spécifique du système en question. Dans la plupart des cas, l'erreur peut être causée par la saisie de données incorrectes dans le système.

    Identifier l'existence d'une vulnérabilité. Elucidation de la réponse du script aux erreurs.

    Le moyen le plus simple de détecter la présence d'une vulnérabilité, mais aussi le fait d'utiliser SQL, est le suivant: Dans tout champ supposé impliqué dans la formation d'une requête SQL (par exemple, le champ Login ou Mot de passe ), entrez le caractère unique. Nous remplissons les champs restants avec les données correctes (ou laissez-le vide si cela est autorisé par le système). Après avoir envoyé les données du formulaire, nous examinons la réaction du système. Si, par conséquent, le script PHP nous donne l'erreur SQL, alors nous pouvons nous féliciter: le système utilise SQL et le script ne filtre pas les guillemets simples. Cela signifie que le système contient une vulnérabilité.
    Une erreur de requête SQL ressemblera alors à ceci sur la page:

    Formulaire de saisie:


    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 ce qui suit:
    1) Le système contient une vulnérabilité, mais le script PHP gère les erreurs. Dans ce cas, le système est autorisé à pirater, mais vous devrez agir "toucher", car nous ne saurons pas à quelle heure la syntaxe de SQL sera correcte, mais à quelle heure ce n'est pas le cas.
    2) Le script filtre également le guillemet, il n'y a donc pas d'erreur. Dans ce cas, le système ne contient aucune vulnérabilité.
    3) Le système n’utilise pas SQL de quelque manière que ce soit.
    Dans les deux derniers cas, il est clair que des recherches plus poussées sur SQL n’ont aucun sens.

    Définissez les noms des champs dans la table.

    Afin d'obtenir des informations de la base de données avec des données spécifiques, nous devons déterminer les valeurs de certains champs dans la requête (par exemple, pour définir la connexion de l'utilisateur). Cependant, vous devez connaître le nom des champs correspondants. Directement pour trouver ces noms n'est pas possible. Il est donc nécessaire de rechercher les noms donnés par une méthode de recherche. Ces noms peuvent coïncider avec les noms des champs du formulaire envoyé au serveur et ne peuvent en aucun cas coïncider. Une bonne leçon est que les noms des champs en tant que position sont standard et qu'il n'y a pas beaucoup de variantes pour les écrire. Par exemple, le nom du champ pour le nom d'utilisateur est susceptible d'être la connexion, soit utilisateur ou pseudo . Il est similaire pour le mot de passe: password soit pwd ou pass .
    Pour déterminer l'existence d'un champ spécifique, nous proposons une méthode simple: voulons vérifier s'il existe un champ pwd dans la table. Nous introduisons dans chaque champ de la forme une telle ligne 'pwd =' . Si le champ pwd existe dans la table, alors SQL traitera correctement la demande, s'il n'y en a pas, alors l'erreur d'exécution SQL réapparaîtra. Ainsi, en substituant des valeurs différentes aux noms de champs, en examinant également le résultat de la requête, nous pouvons déterminer quels champs existent dans la table, mais lesquels ne le sont 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. Voyons voir s'il y a une table adminList dans la base de données. Pour ce faire, nous saisissons dans le formulaire le formulaire '; sélectionnez * de adminList . Si, à la suite de l'erreur, SQL ne démarre pas du tout, la table adminList existe. Pour l'exactitude de ce test, il est nécessaire d'entrer cette ligne dans le champ qui apparaît dans la requête SQL finale. Cela est nécessaire pour garantir que l'erreur de syntaxe n'est pas due à la "queue" restante de la requête d'origine, qui sera présente ultérieurement select * à partir de adminList . Notez que si le formulaire de la demande appartient à une paire de champs Login , le mot de passe est également indiqué , le champ du mot de passe apparaîtra probablement dans la dernière requête.

    PS

    En utilisant cette vulnérabilité, le site http://www.bigmir.net (plus précisément sa galerie de photos aussi chat) a été piraté. Nous avons écrit sur la vulnérabilité des propriétaires de sites. Le trou était fixe. Mais maintenant, nous avons encore une fois vérifié le formulaire d'inscription du chat. Plus trouvé toute la vulnérabilité blah blah 8-).