CVE-2018-14728 – SSRF
Einführung
Der CVE-2018-14728, beschreibt eine SSRF Sicherheitslücke in einer Upload-Funktion im Open-Source-Projekt Responsive FileManager. Über diese war es möglich, auf interne Daten wie zum Beispiel Passwörter zuzugreifen, auf die ein Benutzer keinen Zugriff haben sollte.
Der Responsive FileManager ist ein Datei-Verwaltungssystem, welches sowohl alleinstehend als auch als Plug-in verwendet werden kann. Hierbei bietet das Programm eine Vielzahl an hilfreichen Funktionen wie beispielsweise automatische Vorschaubilderstellung und Kompatibilität für Multi-Nutzer.
Sicherheitslücke
Im Responsive FileManager ist es möglich, eine Datei von der eigenen Festplatte hochzuladen oder diese über eine URL auf den FileManager herunterzuladen. Hierbei baut der FileManager eine Verbindung mit dem Server auf und lädt die betroffene Datei von dort herunter. Die Sicherheitslücke wird durch unzureichende Überprüfung der URL-Eingabe ermöglicht.
Über das User-Interface des Programms lässt sich eine solche URL eingeben und absenden. Hierdurch wird der Code der Datei upload.php
ausgeführt. In dieser Datei des Open-Source-Codes befindet sich die Implementierung der Upload-Funktion.
Codeanalyse
Die relevanten Zeilen aus der upload.php
Datei, sind mit einer kurzen Erläuterung versehen:
Zeile | Code
71 | if(isset($_POST['url'])){
Wenn eine URL-Eingabe für den Upload gesetzt ist, wird diese im Parameter url
übergeben. Der PHP-Code überprüft, ob diese url
gesetzt ist, d.h. ob der Wert ungleich null ist.
Zeile | Code
72 | $temp = tempnam('/tmp','RF');
73 | $ch = curl_init($_POST['url']);
74 | $fp = fopen($temp, 'wb');
Wenn ein Wert gesetzt wurde, wird eine temporäre Datei erstellt und zum Beschreiben geöffnet. Anschließend wird eine cURL-Session initialisiert. Dies ist eine Funktion der libcurl-Bibliothek, die es ermöglicht Verbindungen über unterschiedliche Protokolle zu einem Server herzustellen. Über die initialisierte Session ist es in diesem Fall beispielsweise möglich, einen Webserver zu erreichen und eine Datei herunterzuladen.
Zeile | Code
75 | curl_setopt($ch, CURLOPT_FILE, $fp);
76 | curl_setopt($ch, CURLOPT_HEADER, 0);
77 | curl_exec($ch);
78 | curl_close($ch);
79 | fclose($fp);
Mithilfe der curl Funktionen werden zusätzliche Parameter für die Session hinzugefügt. Anschließend wird die Verbindung durchgeführt, die Datei beschrieben und mit ihrem neuen Inhalt gespeichert.
Angriffsmöglichkeiten
Die Sicherheitslücke entsteht in diesem Fall dadurch, dass vor dem Erstellen einer temporären Datei keine weitere Überprüfung der URL durchgeführt wird und es somit für Angreifer ein Leichtes ist, modifizierte Anfragen zu senden. Dadurch ist es möglich, auf beliebige Dateien auf dem Server zuzugreifen:
curl 'http://localhost/filemanager/upload.php' --data 'fldr=&url=file:///etc/passwd'
Sowie entsprechende Aufrufe zu weiteren Geräten im Netzwerk durchzuführen:
curl 'http://localhost/filemanager/upload.php' --data 'fldr=&url=gopher://127.0.0.1:25/openstack'
Behebung
Der Versuch zur Behebung der Schwachstelle erfolgte durch das Erzwingen eines Musters für die URL. Durch dieses Muster sollen Aufrufe, die nicht den erlaubten Werten entsprechen, blockiert und nicht zur Ausführung gebracht werden.
Zeile | Code
71 | if(isset($_POST['url']) && strlen($_POST['url']) < 2000) {
Neben der Behebung der SSRF-Sicherheitslücke wurde auch der Schutz vor DOS-Attacken verbessert, indem die URL-Länge auf 2000 Zeichen beschränkt wurde.
Zeile | Code
72 | $url= $_POST['url'];
73 | $urlPattern= '/^(http|https):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(?::\d{1,5})?(?:$|[?\/#])/i';
In einem String wird ein Pattern festgelegt, dass nach Regeln der PCRE-Bibliothek definiert ist und mit dem später die eingegebene URL überprüft wird. Die PCRE-Bibliothek sucht nach Mustern, die nach der Semantik regulärer Ausdrücke gebildet werden, und überprüft diese auf Gültigkeit.
Zeile | Code
75 | if(!preg_match($urlPattern, $url)) {
…
92 | } else{
93 | thrownewException('Is not a valid URL.');
94 | }
Anschließend wird die URL überprüft, um festzustellen ob sie nach Muster des Patterns gültig ist. Ansonsten wird eine Fehlermeldung ausgegeben, die darauf hinweist, dass die URL ungültig ist.
Probleme mit der Behebung
Nach der Implementierung dieser Lösung wurde jedoch ersichtlich, dass diese weiterhin Lücken hinterließ, über welche es weiterhin möglich war, SSRF-Angriffe durchzuführen. Dies hatte zur Folge, dass das Pattern überarbeitet wurde, bis folgendes Ergebnis zum aktuellen Standpunkt implementiert wurde:
$urlPattern= '/^(https?:\/\/)?([\da-z\.-]+\.[a-z\.]{2,6}|[\d\.]+)([\/?=&#]{1}[\da-z\.-]+)*[\/\?]?$/i';
Mithilfe dieser Änderung werden weitere Möglichkeiten für Angriffe ausgeschlossen und die Sicherheit erhöht. Dies wird erreicht, indem beispielsweise keine führende 1
erlaubt wird und somit lokale Netzwerkadressen geschützt werden.
Dies sorgt dafür, dass das Pattern sicher ist, jedoch bestehen weiterhin Möglichkeiten, dieses Pattern zu umgehen, wie beispielsweise eine DNS-Weiterleitung auf eine lokale IP-Adresse. Eine mögliche Lösung könnte erreicht werden, indem vor Ausführung des Patterns die DNS-Adresse aufgelöst wird und anschließend der Abgleich über diese erfolgt.
Referenzen
- CVE-2018-14728, aufgerufen am 06.11.2021
- Issue in GitHub, aufgerufen am 06.11.2021
- GitHub Projekt, aufgerufen am 06.11.2021
- Responsive FileManager, aufgerufen am 11.11.2021