Samstag, 31. Juli 2010


Topthema

Donnerstag, 4. September 2008 | Topthema

About Security #171: Schwachstellen-Suche: SQL-Injection mit UNION (2)

(Link zum Artikel: http://www.entwickler.de/entwicklerde/kolumnen/044990)

Die Verwendung des in About Security #170 vorgestellten UNION-Operators ist an zwei Voraussetzungen geknüpft. Welche das sind und wie ein Angreifer erreichen kann, dass sie erfüllt sind, erfahren Sie in dieser Folge.

Voraussetzungen

Bei der Verwendung des UNION-Operators müssen zwei Voraussetzungen erfüllt sein:

  1. Um überhaupt mit einer weiteren Abfrage auf Daten zugreifen zu können, muss der Angreifer die Namen der Datenbanktabelle und ihrer Spalten kennen. Die verraten ihm die Fehlermeldungen der Datenbank oder ein Angriff auf die Systemtabellen, in denen diese Informationen gespeichert sind (siehe unten).
  2. Die Ergebnisse alle Abfragen müssen die gleiche Struktur, d.h. die gleiche Anzahl Spalten mit den gleichen oder kompatiblen Datentypen in der gleichen Reihenfolge, haben.
Struktur der Abfrage ermitteln

N E U ! Security aktuell
Täglich aktuelle Security-Infos!

Die Struktur der Abfrage erfährt er oft durch die Fehlermeldungen der Datenbank: Immer, wenn ein Angriffsversuch fehl schlägt, sagt die ihm, woran er gescheitert ist. Aber auch wenn die Datenbank-Fehlermeldungen von der Webanwendung abgefangen werden, ist er nicht hilflos. Zum einen kann er erkennen, ob ein Angriff erfolgreich war: Die zusätzlichen Informationen erscheinen automatisch in der Ausgabe. Zum anderen gibt es zwei Punkte, die ihm den Angriff erleichtern:

  • Die Datentypen in den verknüpften Abfragen müssen nicht identisch, sondern nur kompatibel, d.h. in den richtigen Datentyp umwandelbar sein. Wie bereits zu sehen war, werden Zahlen bei Bedarf automatisch in Strings umgewandelt. Außerdem kann der Wert NULL in jeden beliebigen Datentyp umgewandelt werden. Ist der Datentyp einer Spalte nicht bekannt, kann dafür in der SELECT-Anweisung immer NULL eingegeben werden, ohne zu einem Fehler zu führen.
  • Meist reicht es, in der originalen Abfrage ein Feld mit Datentyp String zu identifizieren. Danach können beliebige SQL-Abfragen eingeschleust werden, die eine einzelne Spalte mit String-Werten zurückgeben. Der Angreifer kann dann systematisch eine Spalte nach der anderen lesen, er ist nicht darauf angewiesen, alle Spalten auf einmal abzufragen.
Spaltenanzahl ermitteln

Um die Anzahl der zurückgelieferten Spalten zu ermitteln, kann der Angreifer ausnutzen, dass NULL in jeden beliebigen Datentyp umgewandelt werden kann. Er gibt so lange Abfragen mit unterschiedlicher Spaltenanzahl ein, bis die Abfrage ausgeführt wird:

nix' UNION SELECT NULL--
nix' UNION SELECT NULL, NULL--
nix' UNION SELECT NULL, NULL, NULL--
...

Auch wenn keine Datenbank-Fehlermeldungen ausgegeben werden, erkennt er, wenn die Abfrage erfolgreich ausgeführt wurde: Das Ergebnis enthält eine zusätzliche Zeile, in der das Wort NULL oder ein leerer String steht. Die zuletzt eingegebene Abfrage enthielt dann die korrekte Spaltenzahl.

Alternativ kann eine 'ORDER BY'-Klausel in die originale Abfrage eingeschleust und der Index der Spalte solange erhöht werden, bis es einen Fehler ergibt:

nix' ORDER BY 1--
nix' ORDER BY 2--
nix' ORDER BY 3--
...

Durch den eingeschleusten Code ändert sich in den ersten Fällen nur die Reihenfolge der Zeilen im Ergebnis. Kommt es zu einem Fehler, wurde eine ungültige Spaltennummer angegeben, die tatsächliche Anzahl an Spalten ist also um 1 geringer.

Spalte mit Datentyp String suchen

Wurde die korrekte Anzahl der Spalten ermittelt, sucht der Angreifer nach einer Spalte, deren Datentyp String ist. Dafür wird wieder eine Reihe von Abfragen nach NULL verwendet, nur dass diesmal der Reihe nach für eine Spalte ein String eingegeben wird. Für eine Abfrage mit drei Spalten ergibt das folgende Abfragen:

nix' UNION SELECT 'geschafft', NULL, NULL--
nix' UNION SELECT NULL, 'geschafft', NULL--
nix' UNION SELECT NULL, NULL, 'geschafft'--
About Security: Die komplette Serie

Wird die Anfrage ausgeführt, erscheint in der Ausgabe eine zusätzliche Zeile mit dem Wert 'geschafft' darin. Über die so ermittelte Spalte können dann die Daten aus der Datenbank gelesen werden. Um zu testen, ob ein Angriff wirklich funktioniert, kann z.B. die Version der Datenbank abgefragt werden. Hat die Abfrage drei Spalten, von denen die zweite Strings enthält, gibt folgende SQL-Injection unter MySQL und MS-SQL die Datenbankversion aus:

nix' UNION SELECT NULL, @@version, NULL--

Nachdem die Datenbankversion bekannt ist, kann nach bekannten Schwachstellen darin gesucht werden. Meist macht der Angreifer aber mit dem Lesen von Informationen aus der Datenbank weiter.

Datenbanksystem ermitteln

Die verschiedenen Datenbanksysteme verwenden alle etwas unterschiedliche SQL-Dialekte, sodass der Angreifer für manche Angriffe erst einmal wissen muss, mit welchem System er es denn zu tun hat. Eine einfache Methode, um die verschiedene Datenbanken zu unterscheiden, ist deren Art, Strings miteinander zu verbinden:

Oracle: 'ver'¦¦'binden'
MS-SQL: 'ver'+'binden'
MySQL:  'ver' 'binden' (zwischen beiden Teilen befindet sich ein Leerzeichen)

Die Version, die zum richtigen Ergebnis führt, identifiziert dann die Datenbank. Danach kann der Angreifer dann datenbankspezifische Anweisungen nutzen oder deren Systemtabellen ausspionieren. Darin sind z.B. auch die vom Benutzer definierten Tabellen und Spalten gespeichert - eine Information, die der Angreifer für den Zugriff auf diese Tabellen benötigt.

Um SQL-Injection zu verhindern, werden die Benutzereingaben geprüft und gefiltert. Welche Möglichkeiten es dafür gibt und wie ein Angreifer die Filter eventuell austricksen kann, erfahren Sie in der nächsten Folge.

Wenn Sie Fragen oder Themenvorschläge haben, können Sie diese gerne an die angegebene E-Mail-Adresse senden oder im Security-Forum einbringen!

Carsten Eilers

About Security - Übersicht zum aktuellen Thema:

Kommentare

Folgende Links könnten Sie auch interessieren