Mittwoch, 7. Januar 2009 |
Nach der Beschreibung von Directory-Traversal-Schwachstellen sowie der Suche danach geht es in dieser Folge um die Verhinderung von Directory-Traversal-Angriffen.
Manipulationen am Dateisystem verhindert man am einfachsten, indem man keine vom Benutzer manipulierbaren Parameter für Zugriffe aufs Dateisystem verwendet: Werden für den Aufruf von Dateisystemfunktionen keine vom Client gelieferten Parameter als Bestandteil von Pfad und/oder Dateinamen verwendet, kann die Funktion auch nicht auf eine andere Datei umgelenkt werden.
Als Beispiel soll ein Skript dienen, das eine Bilddatei anzeigt. Die anzuzeigende Datei wird dabei über einen URL-Parameter definiert:
http://www.server.example/anwendung/zeigeBild.php?bild=irgendwas.gif
Ist keine Zugriffskontrolle oder besondere Präsentation des Bilds notwendig, kann die Bilddatei auch direkt verlinkt werden:
http://www.server.example/daten/bilder/irgendwas.gif
Manchmal ist die direkte Ausgabe nicht möglich oder erwünscht, z.B. weil eine Zugriffskontrolle notwendig ist oder weitere Informationen angezeigt werden sollen. Dann kann eine Liste zulässiger Dateinamen erstellt und die einzelnen Dateien daraus über einen eindeutigen Identifier, z.B. eine Indexnummer, ausgewählt werden:
http://www.server.example/anwendung/zeigeBild.php?bild=123
Requests mit ungültiger Indexnummer können verworfen werden, ein Angriff ist nicht mehr möglich.
Entsprechendes gilt für alle Fälle, in denen nur eine bestimmte Menge fest vorgegebener Dateien zur Auswahl steht. Ein berühmt-berüchtigtes Beispiel ist (vor allem in PHP-Skripten) eine Datei mit den Sprachanpassungen nach dem Muster
http://www.server.example/anwendung/machwas.php?sprache=deutsch
http://www.server.example/anwendung/machwas.php?sprache=englisch
...
wobei die Sprachanpassung dann nach dem Muster
include("pfad/zum/sprachverzeichnis".$sprache.".inc");
oder
include($sprache.".inc");
erfolgt.
Es besteht keinerlei Notwendigkeit, hier mit dem vom Benutzer gelieferten
Parameter auf das Dateisystem zuzugreifen. Stattdessen kann der Parameter
verwendet werden, um über z.B. eine if- oder
switch-Anweisung die entsprechende Datei auszuwählen.
if ($sprache = 'deutsch') {
include(deutsch.inc)
}
elsif($sprache = 'englisch') {
include(englisch.inc)
}
...
In manchen Fällen lassen sich Dateisystemaufrufe mit vom Benutzer manipulierbaren Parametern nicht vermeiden. Dann müssen die verwendeten Parameter sehr gründlich geprüft werden, um Directory-Traversal-Angriffe zu verhindern. Im folgenden werden einige Schutzmaßnahmen beschrieben, die einzeln oder miteinander kombiniert eingesetzt werden können. Je mehr Schutzmaßnahmen eingesetzt werden, desto besser.
Nachdem die Benutzereingabe dekodiert und kanonisiert wurde, wird darin
nach den Directory-Traversal-Sequenzen ../ und
..\ sowie nach Nullbytes gesucht. Wird etwas gefunden, wird
die Eingabe verworfen und nicht weiter bearbeitet. Jeder Versuch, die
Eingabe zu bereinigen, ist ein überflüssiges Risiko,
weil auch nach der Bereinigung noch eine Directory-Traversal-Sequenz
enthalten sein könnte (siehe About Security
#181).
Außerdem wurde gerade sehr wahrscheinlich ein Angriff festgestellt, und den
muss man nicht unterstützen.
Ebenso wird auch die Dateiendung geprüft: Nur Endungen, die auf einer
vorgegebenen Liste zulässiger Endungen enthalten sind, werden
akzeptiert, alle anderen Eingaben verworfen. Dabei ist besonders auf evtl.
vorhandene doppelte Endungen zu achten. Wenn die Anwendung
irgendwas.php.gif als .gif erkennt, muss das beim
späteren Zugriff auf das Dateisystem nicht zwingend genau so sein.
Alle akzeptierten Eingaben werden vor ihrer Verwendung mit Hilfe der
Dateisystem-API daraufhin geprüft, ob wirklich auf eine Datei im
vorgegebenen Verzeichnis zugegriffen wird. In Java kann dazu ein
java.io.File-Objekt mit dem vom Benutzer gelieferten
Dateinamen instantiiert und danach die Methode
getCanonicalPath() darauf angewendet werden. Beginnt der
zurückgelieferte String nicht mit dem Namen des Startverzeichnisses,
stimmt etwas nicht und die Eingabe wird verworfen. In ASP.NET erfüllt
die Methode System.Io.Path.GetFullPath() den gleichen Zweck.
Sollte trotz alles Vorsicht einmal ein Directory-Traversal-Angriff gelingen, kann die Verwendung einer chrooted Umgebung den Schaden begrenzen. Das chrooted Verzeichnis stellt dann für die Dateizugriffe das Wurzelverzeichnis dar, darüber hinaus führende Directory-Traversal-Sequenzen werden ignoriert.
Zu guter Letzt sollten alle erkannten und abgewehrten Angriffe protokolliert und entsprechend darauf reagiert werden. Je nach den jeweiligen Umständen wird dann die Session des Angreifers beendet, der entsprechende Benutzer gesperrt und/oder der Administrator informiert, der dann ggf. weitere Maßnahmen ergreifen kann.
Damit ist das Thema "Directory Traversal" abgeschlossen. In der nächsten Folge geht es um eine damit verwandte Schwachstelle: Das Einbinden entfernter Dateien in PHP-Skripten, die sog. Remote File Inclusion, RFI.
Wenn Sie Fragen oder Themenvorschläge haben, können Sie diese gerne an die angegebene E-Mail-Adresse senden oder im Security-Forum einbringen!