CGI Security / Sichere CGI-Skripten - Eine Einführung
Wolfgang Wiese (www.xwolf.de, xwolf@xwolf.de), April 2000[1. Allgemeines] [2. Klassifikation von CGI-Programmen] [3. Analyse fremder Programme] [4. Analyse lokaler Programme] [5. Referenzen]
Analyse fremder Programme
Um sicher programmieren zu können, muß man wissen, was unsicher ist und was nicht,
und man sollte mindestens halbwegs eine Ahnung haben, wie jemand versuchen könnte, das
Skript auszutricksen und für die eigenen Zwecke zu mißbrauchen.
Anstelle jetzt die üblichen Phrasen zu zitieren, wie man programmieren sollte
und was zu beachten ist, gehen wir das Problem von der anderen Richtung her an:
Wie stelle ich Sicherheitslücken in einem CGI-Programm fest?
Im Folgendem werd ich anhand dieses Ansatzes und von Beispielen beschreiben, wie
vorzugehen ist. Ich möchte aber betonen, das dies keine Anleitung zum Hacken
sein soll. Vielmehr ist es so, daß niemand sich wirklich Systemadministrator
oder Webmaster nennen sollte, der/die nicht diese grundsätzlichen
und einfachen Möglichkeiten kennt und entsprechend berücksichtigt.
Gehen Sie immer von dem Grundsatz aus, daß wenn es Lücken im Sicherheitskonzept
gibt, diese früher oder später auch gefunden werden. Als SysAdmin
haben Sie deswegen nur 2 Möglichkeiten: Entweder Sie beseitigen alle Sicherheitslücken,
inklusive derer, die Sie noch garnicht kennen, oder Sie hacken Ihr eigenes Skript bevor
es jemand anders tut.
Oberflächlicher Check
Als SysAdmin eines Hosts mit mehreren Benutzern kann man nicht immer wissen, was diese
gerade mal wieder programmiert haben und wo sie es ggf. hingetan haben. Wenn einer
der Benutzer oder ein Seitenbesucher ein Problem hat, dann wird in der Regel
nur die URL als Info gegeben. Bevor man also dran geht und lokal ins Skript reinschaut,
kann man schonmal ueber die URL schauen, was los ist.
Angenommen auf der betreffenden Seite findet sich ein Formular mit folgendem HTML-Code:
...
<form method=post action=xxxxmail.cgi>
E-Mail: <input type=text name=email><br>
Name: <input type=text name=name><br>
Telefon: <input type=text name=telefon><br>
Kommentar: <input type=text name=kommentar><br>
<input type=submit name=submit value=Ok>
</form>
...
Durch den Kontext des Formulares erfahren wir außerdem, daß der Autor der
Webseite hier eine Feedback-Seite aufgebaut hat und einfach um ein kurzes einzeiliges Kommentar
bittet.
Ohne das wir erst versuchen uns das Skript zu besorgen und zu wissen was es macht,
sehen wir, das in den Eingabefeldern email und telefon
erwartet wird, daß dort zum einen eine gültige E-Mail-Adresse, zum anderen eine gültige
Telefonnummer mit den entsprechenden Syntaxi eingegeben wird.
Bei name und kommentar wird lediglich ein
String erwartet, der sieht man vom Namen ab, eine beliebige Syntax haben könnte. Da nicht zu erwarten ist,
daß jemand bei einem einfachen Feedback-Kommentar Namen und Kommentar nutzt um irgentwelche
Operationen auszuführen, ignorieren wir diese Felder erstmal.
Weiterhin ist anzunehmen, daß das Skript richtig funktioniert, wenn es nur Werte bekam, wie
sie vom Programmierer erwartet wurden. (Wenn dem nicht so ist, ist das Skript einfach falsch und
unsere Aufgabe als SysAdmin besteht darin, daß Programm zu sperren und
den Programmierer zurück zur Werkbank zu schicken.)
Nachdem wir das Skript einmal mit richtigen Werten getestet haben, sehen wir, daß das Skript
uns eine E-Mail zusendete, worin sich für den Feedback bedankt wurde.
Was haben wir erfahren? -Das das Skript zumindest die von uns eingegebene E-Mail-Adresse benutzte um damit eine
Systemoperation zu starten!
Eine gültige E-Mail sieht aus wie eines der folgenden Beispiele:
bla@fasel.fu, bla.fasel@blubber.de, fo@bar.fasel.fu, bla.fasel@bar.fasel.fu, ...
Eine E-Mail-Adresse kann aus den Zeichen [a-zA-Z0-9\.\-\@] aufgebaut sein und muß einen gültigen Servernamen hinter dem @ aufweisen. Mehrere Punkte oder Bindestriche dürfen nicht aufeinander folgen und das @ darf nur einmal vorkommen. (Siehe auch: RFC821)
Das obige Programm wird im schlechtesten Fall die E-Mail-Adresse überhaupt nicht auf ihre Syntax überprüfen. Aber nehmen wir ruhig an, der Programmierer hat folgenden in Perl häufig verwendeten Ausdruck zur Syntaxprüfung eingebaut:
...
if ($email !~ m/.*\@.*\..*/i) {
print "Content-type: text/html\n\n"
print "Die E-Mail-Adresse hatte eine falsche Syntax.\n";
exit;
}
...
Hier, wie bei den meisten Formmail-Programmen, wird aber nur geprüft, ob in dem als E-Mail-Adresse
übergebenen String auch vom Format her eine solche vorhanden ist. Es wird nicht geprüft, ob
dort nicht Sachen drin sind, die da nichts zu suchen habe.
Was passiert also wenn wir z.B. folgendes als E-Mail-Adresse angeben:
...
if ($email !~ m/.*\@.*\..*/i) {
print "Content-type: text/html\n\n"
print "Die E-Mail-Adresse hatte eine falsche Syntax.\n";
exit;
}
open(MAIL,"/usr/sbin/sendmail $email");
print MAIL "From: anfaenger\@dumpfbacke.org\n";
...
dann passiert folgendes: Das Skript wird zuerst die nette Dankesmail schicken und dann das Systemkommando ausführen, welches wir mitgegeben haben, nämlich uns die Passwort-Datei schicken. Natürlich ist dies noch ein harmloses Beispiel, auch wenn es meiner Meinung nach schon den Straftatbestand der Erschleichung von fremden Daten erfüllt (Paragraph 202a StGB). Weit kritischer wird es, wenn jemand Systemkommandos wie rm -Rf oder /usr/bin/term -display irgentwo:0.0 ausführen kann. In diesem Fall können und sollen die Paragraphen 303a StGB (Datenveränderung) und/oder Paragraph 303b StGB (Computersabotage) greifen.
Glauben Sie nicht, niemand würde über diese oder andere bekannte Sicherheitslücken versuchen auf Ihr System zuzugreifen! Überzeugen Sie sich selbst, indem Sie ein grep zum Beispiel nach dem String /etc/passwd auf Ihre access.log-Datei machen. Hier ein kleiner Auszug, was Sie möglicherweise auch bei sich finden werden:
62.158.247.*** - - [18/Mar/2000:17:09:04 +0100] "GET //etc/passwd HTTP/1.0" 404 164 "-" 62.158.247.***- - [18/Mar/2000:17:09:27 +0100] "GET ../../../../../../etc/passwd HTTP/1.0" 400 164 "-" "-" ... 62.158.181.*** - - [17/Apr/2000:03:02:36 +0200] "GET /cgi-bin/htsearch?exclude=%60/etc/passwd%60 HTTP/1.0" 404 169 "-" ... 62.156.17.*** - - [24/Apr/2000:15:48:16 +0200] "GET /cgi-bin/htsearch?exclude=%60/etc/passwd%60 HTTP/1.1" 404 181 "-" ... 62.157.56.*** - - [25/Apr/2000:15:39:51 +0200] "GET /cgi-bin/htsearch?exclude=%60/etc/passwd%60 HTTP/1.1" 404 181 "-" ...
(Bei dem von mir betreuten Server bewirkt übrigens jeder Versuch dieser Art eine sofortige automatische Mail an den Sicherheitsverantwortlichen. Nebenbei waren obige Versuche das rumspielen von Skript-Kiddies, die nichtmal in der Lage waren, ihre Dialins zu maskieren. Bei einem schlechtgelaunten Sicherheitsverantwortlichen hätten diese Versuche zu einer Anzeige geführt und dies wiederum zu einer Beschlagnahme des PC's durch die Polizei zur Untersuchung der Festplatte...)
Torture-Skripten
Eine andere, wenn auch etwas brutale, Methode unsichere Parameter herauszubekommen, ist der Einsatz eines Torture-Skriptes. Dabei handelt es sich um ein Skript, das dem zu prüfenden Programm mehrere Hundert Anfragen mit unterschiedlichen zufällig erzeugten Strings übergibt und die Reaktion des Programmes speichert.
In seinem Buch "Web Security" gibt Lincoln Stein
ein Beispiel wie ein Torture-Skript aussehen kann. Im Prinzip ist die Erstellung eines solchen
Skriptes für einen guten Perlprogrammierer eine Sache von wenigen Minuten. Und anstelle das
man wie bei Stein das Skript mit rein zufälligen Strings traktiert, wäre es auch nicht sonderlich
schwer, das Skript so zu modifizieren, daß es ausgewählte Parameter benutzt, die
dann nur Zufallsstrings aus einer bestimmten Familie an Zeichenkombinationen ergeben.
So würde man bei obigem Skript angeben, das die Parameter name, email, kommentar, telefonnummer
nutzbar sind, wobei der Parameter email vom Typ einer E-Mail ist und
telefon vom Typ einer Zahl, zzgl. den Zeichen "+", "-" und "/".
Das Skript würde dann gezielt versuchen, die ihm nun bekannten Daten zu nutzen und
die üblichen Sicherheitsprobleme auszuspielen, es würde nicht seine Zeit mit dem Senden
von zufääligen Strings vom Typ [a-zA-z0-9] verschwenden
bei einem Parameter, wo klar ist, daß dort der Teststring als E-Mail-Adresse getarnt werden
muß.
Bisher waren wir nur beim Analysieren ohne das wir wirklich den Programmcode gesehen haben.
Wenn wir der SysAdmin sind, sollte es auch keine Probleme machen, wenn wir die obigen Beispiele durchtesten
um zu sehen, ob wir wirklich Zugriff zum System erhalten. Sind wir jedoch nicht der SysAdmin des betroffenen
Systems sollten wir das Testen entweder ganz unlassen, wurden wir nicht dazu aufgefordert, oder
nur so vorgehen, daß der Fehler aufgedeckt wird, ohne das wir einen Schaden anrichten.
Im folgenden Kapitel werden wir versuchen, Informationen über das bisher unbekannte Skript
über das Netz zu erhalten.
Informationen aus dem Netz holen
Programmierer sind faule Menschen. Wenn es keinen -für den Programmierer!- guten Grund gibt, wird er/sie in der Regel kein Programm neu schreiben, welches es schon gibt. Scott Adams, der Autor von Dilbert drückt es seiner kurzgefassten Evolutionstheorie so aus:
Nicht anders läßt es sich erklären, daß die meisten CGI-Skripten kostenlose Kopien sind, die man aus irgenteinem Archiv heruntergeladen hat.
Wenn man nach Informationen zu einem CGI-Skript sucht, dann gibt es mehrere Möglichkeiten. Zum einen
kann man die besagten Archive, wie z.B. The CGI-Resource Archiv
durchsuchen. Zum anderen tut es auch eine normale Suchmaschine, jedoch hat dies meist den Nachteil, daß man
dort oft nur von Links zu anderen Seiten, die das CGI auch einsetzen, erschlagen wird, jedoch den Download-Link
leicht übersieht. Eine andere gute Quelle betreffend Sicherheitsprobleme bzgl. CGI-Skripten sind
diverse Security-Listen, wie z.B. BugTraq.
Für das oben angegebene Skript, dessen Namen wir aus dem Wert von <form action=""> erhielten,
findet sich dann auch über The CGI-Resource Archiv ein entsprechender Eintrag
der zum Autor und zu einem Download des Skriptes führt.
Wenn wir zudem auch noch Informationen über die Unsicherheit des Skripten finden, dann sind
wir als SysAdmins aus dem Schneider: Wir brauchen selbst nichts mehr zu machen (außer ggf. die
Versionsnummer zu kontrollieren) als das Skript zu löschen und denjenigen der es auf dem Server
installierte den Kopf abzureißen...
(Anmerkung: Sollte es Ihr Vorgesetzter oder
Ihr Ehepartner gewesen sein, überlegen Sie sich was anderes!)
Finden sich keine Hinweise bzgl. der Sicherheit, sondern nur das Skript, dann sollten Sie es sich ggf. nun laden und dann lokal analysieren, indem Sie sich den Code anschauen. In dem folgenden Kapitel 4 gehen wir darauf genauer ein.
[1. Allgemeines] [2. Klassifikation von CGI-Programmen] [3. Analyse fremder Programme] [4. Analyse lokaler Programme] [5. Referenzen]
Info
$Id: cgisec3.shtml,v 1.4 2004/03/08 22:09:09 xwolf Exp $
© 1996 - 2004 by xwolf -
xwolf ist eingetragene Marke beim Deutschen Patent- und Markenamt (Nr. 301 04 380)


