Mittwoch, 8. Februar 2012 |
Das Einschleusen von Shell-Befehlen, die sog. OS Command Injection, ist das Thema dieser Folge. Derartige Schwachstellen können in jeder Webanwendung vorkommen, die Benutzereingaben ungeprüft für Betriebssystem-Aufrufe verwendet.
Im allgemeinen stellen die vorhandenen APIs der Webserver-Plattformen alle nötigen Funktionen für die Interaktion mit dem Betriebssystem des Servers zur Verfügung. Egal ob Zugriffe auf das Dateisystem, die Kommunikation mit anderen Prozessen, die Kommunikation über das Netzwerk oder sonstige Funktionalitäten des Betriebssystems, für fast alle Zwecke gibt es passende Funktionen in den APIs. Trotzdem gibt es immer wieder Situationen, in denen der direkte Aufruf von Befehlen des Betriebssystems dem indirekten Aufruf über die APIs vorgezogen wird. Zum Beispiel, weil der direkte Aufruf schneller oder flexibler ist, oder weil er für einen bestimmten Zweck einfacher als ein API-Aufruf zu realisieren ist. Werden dabei Benutzereingaben an den Shell-Befehl durchgereicht, kann ein Angreifer dadurch unter Umständen eigene Befehle einschleusen.
Die für den Aufruf der Systembefehle verwendeten Funktionen, z.B.
exec in PHP oder wscript.shell in ASP, enthalten
keinerlei Einschränkungen für die aufzurufenden Befehle und/oder
die verwendeten Parameter. Sie reichen die Daten lediglich an das
Betriebssystem weiter.
Ein klassisches Beispiel für eine Command-Injection-Schwachstelle ist
das CGI-Programm finger.cgi, z.B. in folgender Form:
#!/usr/local/bin/perl
# finger.cgi - an unsafe finger gateway
require 'cgi-lib.pl';
print &PrintHeader;
if (&ReadParse(*in)) {
print "<pre>\n";
print `/usr/bin/finger $in{'username'}`;
print "</pre>\n";
}
else {
print "<html> <head>\n";
print "<title>Finger Gateway</title>\n";
print "</head>\n<body>\n";
print "<h1>Finger Gateway</h1>\n";
print "<form method=POST>\n";
print "<p>User@Host: <input type=text name=\"username\">\n";
print "<p><input type=submit>\n";
print "</form>\n";
print "</body> </html>\n";
}
Das sieht erst mal ganz harmlos aus. Wird als username ein Benutzername
eingegeben, ist es das auch: Das Skript ruft /usr/bin/finger mit dem
Benutzernamen als Parameter auf und gibt das Ergebnis aus. Aber was
passiert, wenn statt eines Benutzernamens z.B.
foo; /bin/rm -r /
eingegeben wird? Das Skript ruft
/usr/bin/finger foo; /bin/rm -rf /
auf, und da ein ; zwei Befehlsaufrufe trennt, wird erst
/usr/bin/finger foo
ausgeführt und das Ergebnis ausgegeben und danach
/bin/rm -rf /
ausgeführt und damit alles gelöscht, was der Benutzer, mit dessen
Rechten das Skript läuft, löschen darf. Statt eines
; können auch andere Metazeichen zur Manipulation des
Parameters verwendet werden, z.B. das Pipe-Symbol ¦ zur
Verknüpfung zweier Befehle.
Diese Schwachstelle ist uralt, sie stammt noch aus den Anfangszeiten des WWW, doch aktuelle Entsprechungen gibt es immer wieder, oft im Zusammenhang mit Kontaktformularen, die für den Versand einer E-Mail ein externes Programm aufrufen.
Das folgende Skript gibt den Inhalt eines ausgewählten Logfiles aus:
<%
Set oScript = Server.CreateObject("WSCRIPT.SHELL")
Set oFileSys = Server.CreateObject("Scripting.FileSystemObject")
myCMD = "type c:\inetpub\wwwroot\log\" & Request.Form("FileName")
myTempFile = "c:\" & oFileSys.GetTempName()
Call oScript.Run("cmd.exe /c" & myCMD & ">" & myTempFile, 0, True)
Set oFile = oFileSys.OpenTextFile(myTempFile, 1, False, 0)
%>
Korrekt verwendet, wird der von Benutzer gelieferte Parameter
FileName in den Befehlsaufruf eingesetzt, der Befehl
aufgerufen und das Ergebnis ausgegeben. Wie im Perl-Beispiel kann ein
Angreifer auch hier Shell-Metazeichen verwenden, um den vorgegebenen Befehl
zu manipulieren und eigene Befehle einzufügen. Das
&-Zeichen verkettet mehrere Befehle miteinander. Bei der
Eingabe von z.B.
last5.log & dir c:\
wird auch das Verzeichnis von Laufwerk c: ausgegeben.
Bereits beim Sammeln der Informationen über die Webanwendung wurden die Parameter ermittelt, mit denen erkennbar auf das Betriebssystem zugegriffen wird, z.B. bei Zugriffen auf das Dateisystem oder dem Aufruf externer Programme. Diese Parameter werden nun daraufhin untersucht, ob darüber zusätzliche Befehle eingeschleust werden können. Generell kommt jeder Parameter in jeder Funktion der Webanwendung als möglicher Angriffspunkt in Frage, und bei einer gründlichen Untersuchung der Webanwendung sollten alle geprüft werden. Für den Anfang reicht aber eine Prüfung der Parameter, die eindeutig für Aufrufe von Systembefehlen verwendet werden.
Die verschiedenen Kommandointerpreter verwenden die Shell-Metazeichen nicht einheitlich, und da nicht mit Sicherheit bekannt ist, welcher Kommandointerpreter am Ende den Befehl ausführt, müssen beim Test generell alle Möglichkeiten betrachtet werden. Wie schon bei Dateisystemzugriffen ist es durchaus möglich, das z.B. der Webserver unter Linux läuft, aber ein Programm auf einem Windows-Server aufgerufen wird (siehe About Security #180).
In der nächsten Folge geht es weiter um die Suche nach Command-Injection-Schwachstellen.
Wenn Sie Fragen oder Themenvorschläge haben, können Sie diese gerne an die angegebene E-Mail-Adresse senden oder im Security-Forum einbringen!