SQL-Injections – eine Analyse an PHP & MySQL [UPDATE]
Den vollständigen 1. Teil des Dokumentes unter Creative Common-Lizenz als PDF-Datei herunterladen:
SQL-Injection-Angriffe beschreiben das Injizieren von SQL-Code [Wika] in eine Anwendung, sodass dieser von der Datenbank ausgeführt wird. Das geschieht typischerweise durch eine entsprechend manipulierte Nutzereingabe. Wird diese ungeprüft in eine SQL-Abfrage eingefügt, so können enthaltene SQL-Befehle die Datenbank in nicht vorhergesehener Weise manipulieren.
3.2.1 Gefahreneinschätzung
Dynamische PHP-Anwendungen beziehen ihre Daten meist aus zwei Quellen:
- Dateisystem und
- Datenbanken.
Die Verwendung von Daten aus Dateien ist für SQL-Angriffe nicht anfällig und wird hier nicht weiter behandelt. Setzt die Anwendung allerdings auf eine Datenbank zur Datenverwaltung, so kann je nach Anwendungsfall beispielsweise folgendes durch einen erfolgreichen SQL-Angriff erreicht werden:
- Hinzufügen, Ändern, Löschen von Datensätzen, Tabellen, Datenbanken,
- Auslesen und Stehlen von Datensätzen und
- Erzeugen von Dateien auf dem Dateisystem der Anwendung.
Durch das Hinzufügen oder Ändern von Datensätzen in einer Tabelle mit Zugangsdaten für eine Webanwendung kann sich der Angreifer selbst gehobene Rechte selbst zuweisen oder den bestehenden Nutzern Rechte entziehen. Ist es dem Angreifer möglich, Dateien zu erzeugen, so kann er gezielt Webseiten in der Anwendung ersetzen und so Nutzer oder Systemdaten ausspionieren.
3.2.2 Angriffsvektoren
Auch bei dieser Angriffsart dringt der Schadcode durch die Nutzereingabe in die Anwendung ein. Dabei versucht der Angreifer eigenen SQL-Code in vorhandene Datenbankabfragen einzufügen und so neue SQL-Befehle zu erzeugen. Es werden dabei typische Programmcode-Schwächen ausgenutzt, die teils durch die Programmiersprache PHP gegeben sind und teils durch weit verbreitete, unvollständige Programmieranleitungen in der Literatur und im Internet vorgegeben werden. Dabei entstehen die Schwachstellen hauptsächlich aus Fehlern in der Programmierung:
- Werteübergabe ohne umschließende Hochkommas,
- eine fehlende Typenprüfung der Werte,
- eine fehlende Längenprüfung der Werte und
- die fehlende Maskierung von Sonderzeichen.
Der eingeschleuste SQL-Code kann vom Angreifer auch derart platziert werden, dass er seine Wirkung zeitverzögert entfaltet. Ein Angriffsbeispiel auf eine Anwendung, die eine Liste der Nutzernamen erstellt, könnte wie folgt aussehen: ein Angreifer könnte den Nutzernamen manipulieren, sodass dieser zusätzlich SQL-Code führt. Verwendet die Anwendung den Nutzernamen innerhalb einer ungesicherten SQL-Abfrage, so wird der Code eingefügt und ausgeführt. Das Besondere an einem solchen Angriff ist demnach, dass der Augenblick der Infizierung der Anwendung meist in zeitlicher Entfernung von deren Ausführung liegt. Darüber hinaus zielt der Angriff auf keinen bestimmten Nutzer sondern kann potentiell von jedem zur Ausführung gebracht werden.
Der kompromittierende SQL-Code kann dabei aus unterschiedlichen Quellen stammen:
- Nutzereingaben,
- Cookie-Werten,
- Session-Werten und
- anderen Datenbank-Daten.
3.2.3 Angriffsformen
Der Angreifer versucht bestehende SQL-Anfragen durch geeignete, eigene SQL-Abfragen zu ändern. Durch das Einfügen geeigneter SQL-Befehle kann er:
- Logische Verknüpfungen ändern,
- Teilabfragen entfernen,
- zusätzliche Abfragen erzeugen,
- den Datenbankprozess beeinflussen und
- verräterische Fehlermeldungen erzeugen.
Logische Verknüpfungen ändern
Abbildung 13: Ein für SQL-Angriffe anfälliges Skript
Dieser Code nimmt die Daten einer Eingabemaske mit „Nutzername“ und „Passwort“ entgegen und prüft in einer Datenbank nach dem Vorkommen dieser Kombination. Wird der Nutzer gefunden und passt das angegebene Passwort, so ist der Nutzer legitimiert.
Die Datenbankabfrage besteht aus einem festen Teil (SELECT * FROM users WHERE user=“ AND password=“) und aus zwei Variablen, die eingesetzt werden. Das funktioniert solange wie beabsichtigt, bis ein Angreifer folgende Eingaben macht:
Die Abfrage, die an MySQL übermittelt wird lautet nach der Injizierung des Schadcodes1 :
Diese neu entstandene SQL-Abfrage wird von MySQL logisch ausgewertet. Dabei wird zuerst die OR-Verknüpfung ausgeführt und anschließend die AND-Verknüpfung. Es ergibt sich folgende SQL-Abfrage:
Das Ergebnis der OR-Verknüpfung ist WAHR, denn ‚a’=’a‘ ist WAHR. Es ergibt sich:
Die Abfrage lautet also:
Sie ist WAHR, sofern ein Nutzer „admin“ existiert und sie liefert dessen Datensatz. Da meist im folgenden PHP-Code nur noch geprüft wird, ob die Datenbank als Antwort NULL (Nutzer oder Passwort sind falsch.) oder aber einen Datensatz (Nutzer und Passwort sind gültig.) zurückgibt, ist der Angreifer, auch ohne ein gültiges Passwort, authentifiziert.
Teilabfragen entfernen
Teile der SQL-Abfrage können durch Einfügen von Kommentarzeichen sogar komplett aus der Ausführung entfernt werden.
Abbildung 14: Abfrage von Pressenachrichten
Diese Abfrage zeigt auf der Webseite eines Unternehmens aktuelle Pressenachrichten an. Dabei können von einer Redaktion bereits fertiggestellte Meldungen für den Webseitenbesucher unsichtbar bleiben, bis sie beispielsweise nach Absprache mit der PR-Abteilung werbewirksam freigegeben werden. Dazu wird jeder Datensatz in der Datenbank mit der Eigenschaft „freigabe“ belegt. Durch die in Abbildung 14 gezeigte SQL-Abfrage wird sichergestellt, dass nur freigegebene Nachrichten sichtbar sind. Darüber hinaus hat der Nutzer die Möglichkeit, sich über ein Auswahlmenü nur Pressemeldungen eines gewünschten Datums anzeigen zu lassen.
Abbildung 15: Auswahlmenü des Datums in HTML
Ein Angreifer könnte versuchen, andere Werte als in dem Auswahlmenü vorgegeben an das Skript zu senden. Falls er bereits vermutet, dass die Datumsangaben direkt in eine SQL-Abfrage eingefügt werden, könnte er folgende Anfrage an das Skript senden:
Wird das Datum ungeprüft übernommen, ändert sich durch diese Eingabe die Datenbankabfrage wie folgt:
Abbildung 16: SQL-Teilabfrage mit Injizierung im „datum“-Feld
Die Zeichengruppe (/*) bedeutet in der MySQL-Syntax einen Kommentar-Anfang. Daher wird der folgende SQL-Code nicht weiter beachtet. Es ergibt sich aus der Sicht des Datenbankservers die Abfrage:
Damit wurde der Parameter „freigabe“ aus der ursprünglichen SQL-Abfrage entfernt. Somit hat ein neugieriger Nutzer Zugriff auf Pressemeldungen, die noch nicht für die Öffentlichkeit bestimmt waren. Bei brisanten Meldungen kann eine solche unbeabsichtigte Enthüllung etwaigen Konkurrenten einen Vorsprung geben.
Zusätzliche Abfragen
Die MySQL-Datenbank unterstützt nativ keine multiple queries. Das heißt, dass eine abgesetzte Datenbank-Abfrage eine einzige Aktion ausführen kann. Jedoch unterstützt MySQL das SQL-Kommando UNION [MySb], mit dem sich, über die ursprüngliche Abfrage hinaus, zusätzliche Datensätze der Antwort hinzufügen lassen. Dazu muss der Angreifer die ursprüngliche Struktur der Datenbank näher kennen. Ist die angegriffene Anwendung frei verfügbar, so kann er den SQL-Code analysieren. Ansonsten versucht er sich diese Informationen über einen Umweg zu beschaffen.
Abbildung 17: SQL-Abfrage für Pressenachrichten
Je nach eingegebener Kennung ($id) wird bei der regulären Verwendung die jeweilige Pressemeldung angezeigt. Ein Angreifer kann mit einem UNION-Befehl die MySQL-eigene Nutzertabelle auslesen, da diese in Standard-MySQL-Installationen leicht zu erraten ist. Dazu gibt er als Wert der Kennung ($id) folgende SQL-Abfrage ein:
Wird dieser Wert ungefiltert übernommen, so entsteht folgende Abfrage :
Diese zeigt zwar keine Pressemeldungen an, dafür aber die Liste der Datenbanknutzer, inklusive der kodierten Passwörter. Mit Hilfe einer „Rainbow-Table“2 lassen sich manche Passwörter wieder nach Klartext umwandeln.
Datenbankprozess beeinflussen
MySQL bietet mit dem Befehl BENCHMARK die Möglichkeit zu ermitteln, wie schnell eine SQL-Anfrage ausgeführt wird [MySa]. Dazu wird eine zu testende Abfrage bestimmte Male wiederholt. Je nach auszuführender Testanfrage ist der MySQL-Server mehr oder weniger mit dieser Aufgabe beschäftigt. Diese Eigenschaft kann sich ein Angreifer zunutze machen, um den Server fast vollständig durch eine sinnlose aber rechenintensive Aufgabe zum Erliegen zu bringen.
Abbildung 18: SQL-Abfrage für Pressenachrichten
Der Angreifer injiziert folgenden Code:
Es entsteht aus der Sicht des Datenbankservers die Abfrage3:
Zu der ersten SELECT-Anfrage fügt der Angreifer eine UNION-Anfrage an. Diese ist jedoch nicht dazu bestimmt, zusätzliche Daten aus der Datenbank zu lesen, sondern allein um einen BENCHMARK-Befehl abzusetzen. Dieser ist angewiesen, eine Million Mal den MD54-Hash des Zeichens „A“ zu erstellen. Durch die Rechenzeit, die das tausendmalige Erzeugen eines MD5-Hashes in Anspruch nimmt, ist der MySQL-Server unter Umständen nicht mehr für andere Nutzer oder Prozesse verfügbar. Startet der Angreifer mehrere solche Angriffe zeitgleich, kann es zum kompletten Stillstand des Datenbankservers kommen. Zwar gelangen durch diesen Angriff keine Daten nach Außen, jedoch wird die Funktionalität derart beeinträchtigt, dass durch die Nichtverfügbarkeit des Servers resultierende Ausfälle durchaus beträchtliche Schäden verursachen können.
Fußnoten
- Es wird vorausgesetzt, dass die PHP-Einstellung „magic_quotes_gpc“ ausgeschaltet ist.
- Es wird vorausgesetzt, dass die PHP-Einstellung „magic_quotes_gpc“ ausgeschaltet ist.
- „Rainbow-Tabelle“ sind Listen oft verwendeter Passwörter und der dazugehörigen Kodierungen nach mehreren Methoden. Ein kodiertes Passwort kann damit abgeglichen werden, um das Passwort in Klartext zu gewinnen. [Wikb]
- MD5 ist eine kryptographische Hashfunktion. [Wikd]
Literaturverzeichnis
[Wika] | Wikipedia „SQL“ http://de.wikipedia.org/wiki/SQL [letzter Besuch: 20.02.2008] |
[MySa] | MySQL 5.1 Referenzhandbuch „Informationsfunktionen“ http://dev.mysql.com/doc/refman/5.1/de/information-functions.html [letzter Besuch: 26.02.2008] |
[MySb] | MySQL 5.1 Referenzhandbuch „UNION“ http://dev.mysql.com/doc/refman/5.1/de/union.html [letzter Besuch: 26.02.2008] |
[Wikb] | Wikipedia „Rainbow Table“ http://de.wikipedia.org/wiki/Rainbow_Table [letzter Besuch: 25.02.2008] |
[Wikd] | Wikipedia „Message-Digest Algorithm 5“ http://de.wikipedia.org/wiki/Message-Digest_Algorithm_5 [letzter Besuch: 29.03.2008] |
Diese Arbeit wird im Rahmen der „Creative Commons“-Lizenz zur Verfügung gestellt.
Sie dürfen:
- das Werk vervielfältigen, verbreiten und öffentlich zugänglich machen
- Bearbeitungen des Werkes anfertigen
Zu den folgenden Bedingungen:
- Namensnennung. Sie müssen den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen (wodurch aber nicht der Eindruck entstehen darf, Sie oder die Nutzung des Werkes durch Sie würden entlohnt).
- Keine kommerzielle Nutzung. Dieses Werk darf nicht für kommerzielle Zwecke verwendet werden.
Vollständiger Lizenztext: http://creativecommons.org/licenses/by-nc/3.0/deed.de
Hallo,
wirklich guter Artikel. Kann es sein das im Punkt „Zusätzliche Abfragen“ ein Fehler in den Beispielen ist? Zwei mit UNION verknüpfte sql statements brauchen ja die gleiche Anzahl an Spalten dort sind Sie jedoch unterschiedlich (einmal 2 und einmal 3)
Danke, du hast natürlich Recht!
Hallo,
Danke für die TOP Seiten und Informationen zu den diversen Angriffsmethoden. Mir als Neuling im Bereich PHP/MySQL ist es eine gute Unterstützung, um eine möglichst sauber Validierung zu generieren.
Das sseq-lib werden ich mir ansehen, es scheint interessant zu sein.