Open Source im professionellen Einsatz

PHP: Dateien lassen sich per Upload-Feature überschreiben

PHP ist eine weit verbreitete serverseitige Skriptsprache für dynamische Webseiten. In PHPs Datei-Upload-Mechanismus ist eine Sicherheitslücke entdeckt worden, über die ein entfernter Angreifer Dateien mit Webserver-Rechten überschreiben kann.

Ein Datei-Upload lässt sich mit PHP einfach realisieren. Auf der Clientseite ist dafür ein HTML-Formular erforderlich:

<form enctype="multipart/form-data" action="hochladen.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="100000"/>
Datei-Auswahl: <input name="dateihandle" type="file"/><br/>
<input type="submit" value="Hochladen"/>
</form>

Das serverseitige Skript "hochladen.php" enthält die PHP-Befehle, die die entstehende temporäre Datei dauerhaft speichern:

$tmp_name = $_FILES['dateihandle']['tmp_name'];
$name = $_FILES['dateihandle']['name']; 

if(move_uploaded_file($tmp_name, $name)) {
    echo "Datei wurde hochgeladen.";
} else{
    echo "Fehler!";
}

Bei "$_FILES" handelt es sich um ein assoziatives Array in PHP, vergleichbar mit einem Dictionary in Smalltalk, Python, Objective-C, einer Map in C++, Java oder einem Hash in Perl und Ruby. Dieses Array speichert unter "$_FILES['dateihandle']" zahlreiche Informationen über die hochgeladene Datei. Beispielsweise enthält "['tmp_name']" Pfad und Namen der temporären Datei, wie sie im Filesystem des Servers zu finden ist. Dies ist meist eine Datei im temporären Verzeichnis "/tmp/", die nach Beendigung des PHP-Skripts sofort wieder gelöscht wird. Darum verschiebt der PHP-Code im obigen Beispiel die Datei auch via "move_uploaded_file" in einen anderen Ordner, denn sonst wäre der Upload vergebens. MIME-Typ und Dateigröße sind unter "['type']" und "['size']" in "$_FILES['dateihandle']" abgelegt.

Beim Dateiupload nach RFC 1867 ließ sich PHP einen Dateinamen mit '/' am Anfang unterschieben.

Die verschiedenen Einträge in "$_FILES" werden von PHP befüllt, und hier hat sich die Sicherheitslücke eingeschlichen. Die Schwachstelle wurde von Krzysztof Kotowicz entdeckt und befindet sich in der Datei "rfc1867.c". RFC 1867 wurde 1995 veröffentlicht und spezifiziert Datei-Uploads auf Basis von HTML-Formularen. Der Programmierfehler versteckt sich in der Funktion "SAPI_POST_HANDLER_FUNC()" und tritt beim Verarbeiten von Dateinamen im Rahmen der oben beschriebenen POST-Anfragen mit "multipart/form-data" auf. Der Angreifer kann die Lücke ausnutzen, um dem Dateinamen den Slash '/' voranzustellen. Je nachdem wie das PHP-Upload-Programm gestrickt ist, kann der Angreifer dadurch unter Umständen Dateien mit Webserver-Rechten in beliebige Verzeichnisse des Servers schreiben.

Ein einfacher Exploit in Form einer HTTP-Anfrage sähe folgendermaßen aus:

POST /upload/upload.php HTTP/1.0
host: 
content-type: multipart/form-data; boundary=----------exploit
content-length: 200

------------exploit
Content-Disposition: form-data; name="contents"; filename="/filename";
Content-Type: text/plain

data

------------exploit

Hierbei handelt es sich um eine HTTP-POST-Anfrage, in der "multipart/form-data" an den HTTP-Server übertragen wird. Die Daten selbst werden durch die Boundary "----------exploit" begrenzt und sind für die eigentliche Attacke irrelevant. Wichtig ist nur der Slash '/' am Anfang des Dateinamens, der von PHP nicht entfernt wird und dadurch als Namenseintrag im Array "$_FILES" landet. Dadurch wird die Datei, wenn der Name nicht vorher anders im Skript verarbeitet wird, direkt in das Root-Verzeichnis geschrieben. Der Fehler lässt sich recht einfach durch das Anpassen zweier If-Abfragen in "rfc1867.c" korrigieren, wodurch sichergestellt ist, dass kein '/'-Zeichen mehr ungesehen bleibt.

Betroffen sind die PHP-Versionen vor 5.3.7.

comments powered by Disqus

Ausgabe 11/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Stellenmarkt

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.