Blogpost vom 04. September 2020
Pentesting mit sqlmap verhindert SQL Injections
Ein professionelles Pentesting weiß nicht nur, Sicherheitslücken im Code auf die Schliche zu kommen, sondern auch, wie man sie schließen kann. Ein Tool aus dem Pentesting-Werkzeugkasten ist sqlmap, das dabei hilft, SQL Injections unschädlich zu machen.
Von allen Angriffsvektoren auf Webanwendungen listet Akamai die SQL Injection mit mehr als 65 % als den häufigsten. Für die Studie wurden im Zeitraum 2017 bis 2019 etwas weniger als 4 Milliarden Logs herangezogen. Die OWASP, welche die Top 10 der riskantesten Lücken herausgibt, listet sie sogar direkt unter Platz 1. Obwohl die Lücke schon seit mehr als 20 Jahren bekannt ist, ist sie offenbar nicht klein zu kriegen.
Auch Java-Anwendungen sind von SQL Injections nicht ausgenommen, wie die aktuell gelisteten Vorfälle zeigen. Aber auch in über JDBC und JPA umgesetzten Anwendungen schleicht sich die gefährliche Lücke ein, die diese Angriffe erst möglich macht.
Dieser Beitrag zeigt, wie wir im Pentesting eine Software Stück für Stück prüfen können, wenn bedauerlicherweise eine Lücke für SQL Injections bekannt geworden ist. Das Tool dafür heißt sqlmap und wird auch bei echten Hacker-Angriffen häufig eingesetzt.
Identifikation der Lücke
Wer zunächst sehen will, welche Seiten anfällig für SQL Injections sind, kann sich auf der Seite Google Dorks bedienen. Eine aktuelle Liste bestimmter Prüfungen für SQL Injections findet man, wenn man nach Google Dorks SQL Injection sucht.
Der offensichtlichste Fall ist der, dass eine SQL-Fehlermeldung direkt an die Webseite zurückgeliefert wird. Wir können einen solchen Fehler selbst erzeugen, indem wir ein unbedachtes Single Quote an den Get-Request anhängen:
[Bild errorsql.png]
Für einen Angreifer ist das ein klarer Hinweis auf die Lücke. Trotz dieses offensichtlichen Fehlers sind eine Menge solcher Seiten im Internet zu finden.
Matthias Altmann
IT-Security Experte
Ein Beispiel für SQL Injections
inurl:"gallery.php?id="
Hinter dem Kürzel „id“ stehen oft Primary Keys (Identifikationsnummern von Einträgen in einer Tabelle) einer Datenbank. Begeben wir uns nun einmal testweise in die Rolle des Angreifers und subtrahieren hier 2 Zahlen, beispielsweise
gallery.php?id=3-2
Wenn dieser Eingriff ein Ergebnis auswirft (in unserem Fall wäre das die 1) und wir die gleiche Seite sehen, wie wenn wir sie direkt mit id=1 aufrufen würden, ist hier sehr wahrscheinlich auch eine SQL Injection (kurz SQLi) vorhanden.
Viele Anwendungen nutzen bestimmte Header, um den richtigen Inhalt anzuzeigen. Eine einfache Variante, das zu zeigen, ist es, den Request mit einem Proxy wie OWASP ZAP oder Portswigger Burp abzufangen, in eine Datei zu speichern und dann als Basis für einen Testangriff zu verwenden.
sqlmap schließt die Lücke
Nun kommt sqlmap ins Spiel. sqlmap basiert auf Python und ist deswegen plattformunabhängig. Man kann es als zip-Datei installieren, je nach Betriebssystem per apt oder brew. Wer immer die aktuellste Version haben will, kann eine automatische Aktualisierung anstoßen:
sqlmap --update --answers='zipball=Y'
Zunächst müssen wir jetzt den Request abfangen, in dem wir eine SQLi vermuten – den können wir uns z. B. mit den Entwicklertools des Browsers anzeigen lassen. Diesem geben wir nun das sqlmap-Tool mit:
sqlmap -r req.txt -p id -b
Beim Pentesting prüfen wir so, ob eine Lücke da ist und wenn ja, ob sie ausnutzbar ist. Ist das der Fall, wird uns das Tool die Datenbank samt Version zurückgeben. Dann können wir loslegen, weitere Fragen zu stellen. Zum Beispiel, welcher Nutzer für die Datenbank verwendet wird.
Tipp: Dabei bietet es sich an, die Fragen nicht in jedem Durchgang erneut zu beantworten, sondern dafür –batch oder –answers zu verwenden. –batch nimmt die Standardantworten, –answers legt benutzerdefinierte Antworten fest. Lautet die Frage z. B.
got a 301 redirect … Do you want to follow? [Y/n]
so setzt
–answers=“follow=Y“
den Redirect auf True. Der Aufruf zum Erfragen des aktuellen Nutzers kann dann so ausgeführt werden:
sqlmap -r req.txt -p id --batch --current-user
Als nächstes können beliebige Daten von der Anwendung gezogen werden. Rein theoretisch könnten wir uns *sämtliche* Daten der Datenbank ziehen. Das ist aber oft nur wenig sinnvoll, da nicht bekannt ist, wie groß die Datenbank ist und ob noch weitere Stolpersteine auftreten werden. Gezielt können aber folgende Fragen gestellt werden:
- Welche Datenbanken sind auf dem System?
- Welche Tabellen finden sich in der zuvor gefundenen Datenbank?
- Welche Spalten finden sich in welcher Tabelle?
- Wie sehen die Inhalte einer spezifischen Tabelle aus?
- Wenn wir die Antwort etwas schneller haben wollen, können wir mit Threads spielen:
sqlmap -r req.txt -p id --batch -D spezifische_DB -T spezifische_Tabelle --dump --threads=15
Lesen von Dateien
Die Daten liegen nun auf dem Server des Pentesters bzw. Angreifers. Was gravierend sein kann, wenn man etwa an Kreditkarteninformationen oder andere sensible Informationen denkt. Dem Angreifer ist es aber oftmals auch wichtig, längerfristig Zugriff zu behalten. Dafür verwendet er u. a. diese Möglichkeiten:
Mittels
sqlmap -r req.txt -p id –batch –privileges
wird bestimmt, welche Privilegien der aktuelle Nutzer hat. Ist das FILE-Recht dabei, kann der Pentester/Angreifer Dateien auslesen und schreiben. Stimmen die Betriebssystemrechte, kann auf diese Weise der gesamte Code heruntergeladen werden.
Wenn der Code ausgelesen ist, kann auch bestimmt werden, mit welchem Algorithmus die Passwörter in der Datenbank abgelegt werden sollen. Der Angreifer nimmt sich dazu eine Wörterliste und schreibt sich ein Stück, mit dem er diese Wörterliste durch exakt den gleichen Algorithmus laufen lässt. Am Ende sucht er mit den passenden Befehlen die Ergebnisse in der Datenbank. Je nach Passwortkomplexität erntet er so die ersten Zugänge in die Webanwendung.
Schreiben von Dateien
Sein nächster und letzter Schritt ist dann das Schreiben auf dem Server. Hierfür sind gewisse Vorbedingungen notwendig, wie das genannte FILE-Recht, aber auch Schreibrechte auf dem Betriebsystem.
Nun ist er nicht mehr weit davon entfernt, in den Server einzudringen. Das gilt insbesondere dann, wenn Webanwendung und Datenbank auf dem gleichen Server liegen, wie etwa bei Standard-LAMP-Anwendungen. Mittels
sqlmap -r req.txt -p id –batch –os-cmd=COMMAND
kann ein Befehl auf dem Server ausgeführt bzw. Remote Code Execution durchgeführt werden. Ist das FILE-Recht mit der zuvor genannten Prüfung der Privilegien bestätigt und es funktioniert trotzdem nicht, kann es sein, dass der Angreifer/Tester noch mit –web-root die Document Root anpassen muss.
Hat der Angreifer erst einmal Schreibrechte auf die Document Root, kann er sich den Code so umgestalten wie er möchte. Ein Angriffsmuster ist es beispielsweise, die eingegebenen Credentials bei jedem Login mitzuloggen – und zwar im Klartext, also noch *bevor* sie in irgendwelche Hash-Algorithmen gepackt werden, damit man sich das Cracken der Hashes sparen kann.
Was sqlmap nicht kann
Aber sqlmap hat auch seine Grenzen. Folgende Angriffe sind damit auch beim Pentesting schwierig zu detektieren:
Bei einer Second Order SQL Injection spiegelt sich das Ergebnis nicht direkt in der HTTP Response, sondern erst später wider. Zwar hat sqlmap hierfür einen Parameter –second-order, dem man die URL zur Analyse mitgeben kann, das Tool erkennt die Lücken aber nicht von sich aus.
Bei der Out-of-Band SQL Injection erfolgt die Informationsgewinnung nicht wie üblich über den HTTP-Kanal, sondern über einen anderen Kanal wie etwa DNS. sqlmap kann das zwar auch, indem man mittels
–dns-domain=server
den vom Angreifer kontrollierten DNS-Server mitgibt. Allerdings muss man dafür einen eigenen DNS-Server besitzen, um an diese Informationen heranzukommen, was sich nicht immer einfach gestaltet.
Out-of-Band SQLi, auch OAST SQLi genannt, ist übrigens der heilige Gral der SQLi, weil hier sämtliche Fehler, die ein Programmierer so um die Schwachstelle herum machen kann, unwichtig sind. Worauf es ankommt, ist die SQLi-Lücke an sich. Das heißt, selbst wenn es überhaupt keine Rückmeldung eines SQL-Statements von der Anwendung gibt, sprich
- keine Fehlermeldung,
- keine unterschiedlichen HTTP-Response-Codes,
- keinerlei Möglichkeit zwischen einem wahren und einem falschen SQL-Statement zu unterscheiden,
- nicht einmal eine synchrone Verarbeitung, da asynchrone Threads verwendet werden, es also keine zeitliche Unterschiede gibt, die beispielsweise mit einer SQL-SLEEP-Anweisung hervorgerufen werden können,
dann kann die Methode Out-of-Band trotzdem greifen, da SQL-Queries abgesendet werden und URLs aufrufen, die vom Angreifer gesteuert werden. Und die Rückmeldung über einen Kanal erfolgt vollkommen legitim über DNS-Abfragen. Denn hierfür reicht dann eine DNS-Anfrage mit einer Subdomain, die Informationen aus der Datenbank überträgt.
Was also tun?
Eine Möglichkeit, das auch ohne sqlmap zu zu prüfen, ist das im Webapplication Proxy Portswigger Burp Pro befindliche Werkzeug Collaborator. Hierzu wird es in nächster Zeit einen gesonderten Blogbeitrag geben.
Zusammenfassung
Um die Gefahr von SQL Injections zu mindern, ist ein professionelles Pentesting das A und O. Außerdem sollten wir Datenbank und Anwendungsserver immer voneinander trennen und der Datenbank nur einen Nutzer zuweisen, der seinerseits nur die Privilegien besitzt, die absolut notwendig sind. Ferner lohnt es sich zu prüfen, ob man HTTP-Anfragen aus der Datenbank heraus blockt, um so auch OAST SQLi zu blocken.
Wenn wir diese grundlegenden Prinzipien beachten, können wir das Risiko von SQL Injections substanziell minimieren.