security - test - sql injection url




Wie funktioniert die SQL-Injection aus dem XKCD-Comic "Bobby Tables"? (8)

Einfach zu sehen:

(Quelle: https://xkcd.com/327/ )

Was macht diese SQL?

Robert'); DROP TABLE STUDENTS; --

Ich weiß sowohl ' als auch" -- sind für Kommentare, aber wird das Wort DROP nicht kommentiert, da es Teil derselben Zeile ist?


TL; DR

-- The application accepts input, in this case 'Nancy', without attempting to
-- sanitize the input, such as by escaping special characters
school=> INSERT INTO students VALUES ('Nancy');
INSERT 0 1

-- SQL injection occurs when input into a database command is manipulated to
-- cause the database server to execute arbitrary SQL
school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
INSERT 0 1
DROP TABLE

-- The student records are now gone - it could have been even worse!
school=> SELECT * FROM students;
ERROR:  relation "students" does not exist
LINE 1: SELECT * FROM students;
                      ^

Dies lässt den Schülertisch fallen. Um zu verdeutlichen, was gerade passiert, versuchen wir es mit einer einfachen Tabelle, die nur das Namensfeld enthält und fügen Sie eine einzelne Zeile hinzu (getestet mit PostgreSQL 9.1.2):

school=> CREATE TABLE students (name TEXT PRIMARY KEY);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "students_pkey" for table "students"
CREATE TABLE
school=> INSERT INTO students VALUES ('John');
INSERT 0 1

Nehmen wir an, die Anwendung verwendet die folgende SQL, um Daten in die Tabelle einzufügen:

INSERT INTO students VALUES ('foobar');

Ersetzen Sie foobar durch den tatsächlichen Namen des Schülers. Eine normale Einfügeoperation würde folgendermaßen aussehen:

--                            Input:   Nancy
school=> INSERT INTO students VALUES ('Nancy');
INSERT 0 1

Wenn wir die Tabelle abfragen, bekommen wir folgendes:

school=> SELECT * FROM students;
 name
-------
 John
 Nancy
(2 rows)

Was passiert, wenn wir den Namen von Little Bobby Tables in die Tabelle einfügen?

--                            Input:   Robert'); DROP TABLE students; --
school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
INSERT 0 1
DROP TABLE

Die SQL-Injektion hier ist das Ergebnis des Namens des Studenten, der die Anweisung beendet und einen separaten DROP TABLE Befehl enthält; Die zwei Bindestriche am Ende der Eingabe sollen jeden übrig gebliebenen Code auskommentieren, der sonst einen Fehler verursachen würde. Die letzte Zeile der Ausgabe bestätigt, dass der Datenbankserver die Tabelle gelöscht hat.

Es ist wichtig zu beachten, dass die Anwendung während der INSERT Operation die Eingabe nicht auf Sonderzeichen prüft und daher beliebige Eingaben in den SQL-Befehl eingeben kann. Dies bedeutet, dass ein böswilliger Benutzer in ein Feld, das normalerweise für Benutzereingaben vorgesehen ist, spezielle Symbole wie Anführungszeichen zusammen mit beliebigem SQL-Code einfügen kann, damit das Datenbanksystem es ausführt, daher SQL "injection" .

Das Ergebnis?

school=> SELECT * FROM students;
ERROR:  relation "students" does not exist
LINE 1: SELECT * FROM students;
                      ^

SQL Injection ist die Datenbank, die einer Sicherheitslücke in einem Betriebssystem oder einer Anwendung entspricht. Die möglichen Auswirkungen eines erfolgreichen SQL-Injection-Angriffs sind nicht zu unterschätzen. Je nach Konfiguration des Datenbanksystems und der Anwendung kann der Angreifer Datenverluste verursachen (wie in diesem Fall), unberechtigten Zugriff auf Daten erlangen oder sogar ausführen beliebiger Code auf dem Host-Rechner selbst.

Wie im XKCD-Comic erwähnt, besteht eine Möglichkeit zum Schutz vor SQL-Injection-Angriffen darin, Datenbankeingaben zu bereinigen, z. B. durch das Leeren von Sonderzeichen, sodass sie den zugrunde liegenden SQL-Befehl nicht ändern können und daher keinen beliebigen SQL-Code ausführen können. Wenn Sie parametrisierte Abfragen verwenden, z. B. mithilfe von SqlParameter in ADO.NET, wird die Eingabe automatisch für Sie SqlParameter .


Das '); beendet die Abfrage, es startet keinen Kommentar. Dann löscht es die Schüler-Tabelle und kommentiert den Rest der Abfrage, die ausgeführt werden sollte.


Der Verfasser der Datenbank hat wahrscheinlich ein

sql = "SELECT * FROM STUDENTS WHERE (STUDENT_NAME = '" + student_name + "') AND other stuff";
execute(sql);

Wenn student_name der angegebene ist, wird die Auswahl mit dem Namen "Robert" ausgeführt und die Tabelle wird gelöscht. Der Teil "-" ändert den Rest der angegebenen Abfrage in einen Kommentar.


Ein einfaches Anführungszeichen ist der Anfang und das Ende eines Strings. Ein Semikolon ist das Ende einer Anweisung. Also wenn sie eine Auswahl wie diese machen würden:

Select *
From Students
Where (Name = '<NameGetsInsertedHere>')

Die SQL würde werden:

Select *
From Students
Where (Name = 'Robert'); DROP TABLE STUDENTS; --')
--             ^-------------------------------^

Auf einigen Systemen würde die select zuerst ausgeführt, gefolgt von der Anweisung drop ! Die Nachricht lautet: VERBINDEN SIE WERTE NICHT IN IHR SQL. Verwenden Sie stattdessen Parameter!


Nehmen wir an, der Name wurde in einer Variablen namens $Name . Sie führen dann diese Abfrage aus:

INSERT INTO Students VALUES ( '$Name' )

Was Sie bekommen, ist:

INSERT INTO Students VALUES ( 'Robert' );  DROP TABLE STUDENTS; --' )

Das -- kommentiert nur den Rest der Zeile.


Nein, ' ist kein Kommentar in SQL, sondern ein Trennzeichen.

Mama hat vermutet, dass der Datenbankprogrammierer eine Anfrage gestellt hat, die wie folgt aussieht:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('$firstName', '$lastName');

(Zum Beispiel) um den neuen Studenten hinzuzufügen, wobei der $xxx Variableninhalt direkt aus einem HTML-Formular entnommen wurde, ohne das Format zu überprüfen oder Sonderzeichen zu umgehen.

Also wenn $firstName Robert'); DROP TABLE students; -- enthält Robert'); DROP TABLE students; -- Robert'); DROP TABLE students; -- Robert'); DROP TABLE students; -- Das Datenbankprogramm führt die folgende Anfrage direkt in der DB aus:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('Robert'); DROP TABLE students; --', 'XKCD');

dh. Es wird die Insert-Anweisung vorzeitig beenden, den vom Cracker gewünschten bösartigen Code ausführen und dann den Rest des Codes auskommentieren.

Mmm, ich bin zu langsam, ich sehe schon 8 Antworten vor mir in der orangenen Band ... :-) Ein beliebtes Thema, so scheint es.


So funktioniert es: Nehmen wir an, der Administrator sucht nach Studentenakten

Robert'); DROP TABLE STUDENTS; --

Da das Administratorkonto über hohe Berechtigungen verfügt, ist das Löschen der Tabelle aus diesem Konto möglich.

Der Code zum Abrufen des Benutzernamens von der Anfrage ist

Jetzt wäre die Abfrage in etwa so (um die Schüler-Tabelle zu durchsuchen)

String query="Select * from student where username='"+student_name+"'";

statement.executeQuery(query); //Rest of the code follows

Die resultierende Abfrage wird

Select * from student where username='Robert'); DROP TABLE STUDENTS; --

Da die Benutzereingabe nicht bereinigt ist, wurde die obige Abfrage in 2 Teile manipuliert

Select * from student where username='Robert'); 

DROP TABLE STUDENTS; --

Der Doppelstrich (-) wird nur den verbleibenden Teil der Abfrage auskommentieren.

Dies ist gefährlich, da es die Kennwortauthentifizierung aufheben kann, falls vorhanden

Der erste wird die normale Suche durchführen.

Der zweite Schüler wird den Tischschüler fallen lassen, wenn der Account ausreichende Privilegien hat (im Allgemeinen wird der Schuladministrator eine solche Anfrage ausführen und die oben erwähnten Privilegien haben).


Wie alle anderen schon darauf hingewiesen haben, '); schließt die ursprüngliche Aussage und dann folgt eine zweite Aussage. Die meisten Frameworks, einschließlich Sprachen wie PHP, haben mittlerweile Standard-Sicherheitseinstellungen, die nicht mehrere Anweisungen in einer SQL-Zeichenfolge zulassen. In PHP können Sie beispielsweise mehrere Anweisungen in einer einzigen SQL-Zeichenfolge mysqli_multi_query indem Sie die Funktion mysqli_multi_query verwenden.

Sie können jedoch eine vorhandene SQL-Anweisung über SQL-Injection bearbeiten, ohne eine zweite Anweisung hinzufügen zu müssen. Nehmen wir an, Sie haben ein Login-System, das einen Benutzernamen und ein Passwort mit dieser einfachen Auswahl überprüft:

$query="SELECT * FROM users WHERE username='" . $_REQUEST['user'] . "' and (password='".$_REQUEST['pass']."')";
$result=mysql_query($query);

Wenn Sie peter als Benutzernamen und secret als Passwort angeben, würde die resultierende SQL-Zeichenfolge wie folgt aussehen:

SELECT * FROM users WHERE username='peter' and (password='secret')

Alles ist gut. Stellen Sie sich vor, Sie geben diese Zeichenfolge als Passwort an:

' OR '1'='1

Dann wäre die resultierende SQL-Zeichenfolge wie folgt:

SELECT * FROM users WHERE username='peter' and (password='' OR '1'='1')

Damit können Sie sich bei jedem Konto anmelden, ohne das Passwort zu kennen. Sie müssen also nicht in der Lage sein, zwei Anweisungen zu verwenden, um SQL-Injection zu verwenden, obwohl Sie mehr destruktive Dinge tun können, wenn Sie mehrere Anweisungen liefern können.





sql-injection