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

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


Cet article traite d'une vulnérabilité SQL liée à la pénétration dans le corps d'une requête.

L'essence de la vulnérabilité

Considérez le travail du système le plus simple avec une interface Web qui permet aux utilisateurs d’enregistrer aussi les informations de changement les concernant. De tels systèmes sont l’un des plus répandus sur le net. Cela peut également inclure un livre d'or, un chat, une galerie de photos et un service postal.

La requête générée à la base de données est forcée pour que le nom d'utilisateur et le mot de passe soient entrés 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 fournit les informations trouvées sur l'utilisateur, que le script PHP dessine sous forme HTML et donne également à l'utilisateur.

Analysons 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, le nom d'utilisateur et le mot de passe entrés par l'utilisateur sont contenus dans les variables $ userLogin et $ userPassword . Le contenu de ces variables est inclus dans la demande de filtrage des informations sur cet utilisateur particulier. Le filtre est défini à l'aide de l'option where de la commande select SQL. Dans ce cas, la requête se présente comme suit : sélectionnez * dans la table utilisateur login = '$ userLogin' et password = '$ userPassword' où table_utilisateur est le nom de la table contenant les informations nécessaires. Si les variables de connexion du mot de passe contiennent également les valeurs de 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 si dans la base de données, il n'y a pas d'enregistrement dans lequel l'identifiant est égal à vanya, le mot de passe est vasya , jusqu'à la demande, il n'enverra aucune ligne à partir de la base de données et le script ne produira rien. Ainsi, le système donné ne donne accès qu'aux informations de l'utilisateur qui dispose d'un mot de passe et d'une connexion sans erreur.

Il semblerait qu'un tel système ne contienne aucun défaut. En pratique, 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. Cependant, voyons ce qui se passe si le mot de passe est personnel, l'utilisateur saisi contient un guillemet. Laissez-le posséder la valeur de vas'ya , alors que la demande ressemblera à: select * from userTable login = 'vanya' et password = 'vas'ya' . Lors de l'exécution d'une telle requête, une erreur va certainement se produire, car la citation du mot de passe a fermé la citation d'ouverture de la requête et la fin du mot de passe ya ' restait «à bloquer» en dehors de l'expression conditionnelle.

Et si vous insérez une telle ligne sous la forme d'un mot de passe: 'ou 1 = 1' , la requête deviendra la suivante: . Mais l'expression logique deviendra identiquement correcte, également en objection à cette requête, SQL retournera la base de données complète d'utilisateurs 8-).

Ainsi, en utilisant le caractère apostrophe, nous pouvons également insérer le corps de la requête SQL afin que la condition vérifiée soit vraie. Si nous sommes intéressés par un utilisateur spécifique vanya , alors pour obtenir des informations à son sujet, il est autorisé d'utiliser la chaîne de mot de passe suivante: 'ou login =' vanya . Cela fera la demande: sélectionnez * à partir de userTable login = 'vanya' et password = '' ou login = 'vanya' . Vous comprenez donc que nous recevrons des informations sur vanya .

La vulnérabilité décrite des services SQL n'est en aucun cas limitée à la réception non autorisée d'informations. Dans la mesure où MySQL est 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 DB. 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 il est permis de spécifier une commande valide en tant que <commande SQL> . Donc, par exemple, le code suivant: '; drop table 'userTable va simplement détruire le 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 tête, nous examinons les problèmes suivants qui surviennent lors de l’utilisation de la vulnérabilité décrite:
  • Déterminer si SQL est utilisé dans le système.
  • Identifier l'existence d'une vulnérabilité. Clarification de la réaction du script aux erreurs.
  • Définition des noms de champs dans la table.
  • Identifiez 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. Cela est dû au fait que le flux d'erreur PHP en tant que position (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 si SQL est utilisé dans le système.

    Lors de l'examen d'un système particulier, vous devez d'abord déterminer s'il utilise SQL.
    Ce fait peut être révélé soit indirectement (en examinant les noms des fichiers utilisés, les références aux outils utilisés, etc.), soit directement - en provoquant la manifestation du code SQL. Si nous travaillons avec PHP, alors il n'y a qu'un seul moyen de déterminer de manière unique l'utilisation de SQL: provoquer une erreur dans son exécution. Cependant, si une erreur survient pendant l’exécution de la demande, le script PHP ne gère pas explicitement les erreurs de toute exécution. Le message d’erreur PHP sera alors envoyé directement à la page de l’utilisateur.
    La cause d'une erreur dans l'exécution d'une requête SQL dépend du périphérique particulier du système en question. Dans la plupart des cas, l'erreur est autorisée à appeler en entrant des données incorrectes dans le système.

    Identifier la présence d'une vulnérabilité. Clarification de 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 d’une 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 sont laissés vides, 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 en aucune façon le guillemet simple. Que manger le système contient une vulnérabilité.
    L'erreur de requête SQL ressemblera alors à ceci sur la page:

    Formulaire de saisie de données:


    Le résultat est 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 à aucun moment à quel moment la syntaxe SQL sera correcte, mais à quel moment elle ne le sera pas.
    2) Le script filtre la citation aussi parce que des erreurs ne surviennent pas. Dans ce cas, le système ne contient aucune vulnérabilité.
    3) Le système général n'utilise pas SQL.
    Dans les deux derniers cas, il est clair que l'exploration ultérieure de SQL n'a aucune signification.

    Définition des noms de champs dans la table.

    Pour obtenir des informations de la base de données avec des données spécifiques, nous devons déterminer les valeurs de certains champs de la demande (par exemple, définir le nom de connexion de l'utilisateur). Pourtant, pour cela, vous devez connaître le nom des champs correspondants. Découvrir directement ces noms n'est pas possible. Par conséquent, il est nécessaire de rechercher ces noms à l'aide de la méthode de recherche. Ces noms peuvent coïncider avec les noms des champs du formulaire envoyé au serveur, mais ils peuvent également ne pas coïncider. La bonne chose est que les noms des champs en tant que position sont également des variantes standard de leur écriture. Ainsi, par exemple, le nom du champ pour le nom d'utilisateur est susceptible d'être login ou utilisateur ou pseudo . Similaire au mot de passe: password soit pwd ou pass .
    Pour déterminer l'existence d'un champ spécifique, nous proposons une méthode peu sophistiquée: supposons que nous voulions vérifier si le champ pwd existe dans la table. Entrons dans n'importe quel champ de formulaire la chaîne suivante 'pwd =' . Si le champ pwd existe dans la table, alors SQL traite correctement la demande; s'il n'existe pas de tel champ, l'erreur d'exécution de SQL se reproduira. Ainsi, en substituant différentes valeurs aux noms de champs et 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 ne le sont pas.

    Identifiez les noms des tables existantes.

    Semblable à la méthode de recherche des noms de champs dans les tables, il est également permis 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 chaîne suivante dans le champ de formulaire avec le locuteur ', sélectionnez * depuis adminList . Si, par conséquent, l'erreur SQL ne démarre pas du tout, la table adminList existe. Pour que ce test soit correct, vous devez entrer cette chaîne dans le champ qui apparaît final dans la requête SQL. Cela est nécessaire pour éviter que l'erreur de syntaxe ne soit due à la "fin" restante de la demande d'origine, qui devient présente ultérieurement. Sélectionnez * dans adminList . Notez que si la vue de la demande appartient à une paire du champ de connexion et au mot de passe , le champ de mot de passe apparaîtra probablement en dernier 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 annoncé une vulnérabilité pour les propriétaires de sites. Le trou était réparé. Mais maintenant, nous avons vérifié le formulaire de chat une fois de plus. Plus trouvé toute cette vulnérabilité bla bla 8-).