Was ist ein sicheres CGI
Welche Rechte hat ein CGI Prozess
Systembefehle über CGIs ausführen
Wie verhindere ich den Missbrauch von Pipes
Sendmail - Ein mögliches Risiko
Weiterführendes
Was ist ein sicheres CGI
In diesem Artikel soll nicht von einem sicheren CGI im Sinne von Absturzsicherheit die Rede sein. Vielmehr geht es hier darum wie ein Eindringen von böswilligen Hackern in das System über etwaige Sicherheitslücken in einem fehlerhaften CGI verhindert wird. Sicherheitslöcher in eigenen verwendeten CGIs verhindern, erkennen und ggf. beseitigen, dafür trägt in erster Linie der Webmaster selbst die Verantwortung. Diese Verantwortung erstreckt sich nicht nur auf das eigene Web sondern auf den gesamten Server - darüber sollte sich jeder Webmaster im Klaren sein! Denn auf einem Server ist ja nicht nur das eigene Web gehostet sondern Einige bis Viele... Mit einem sicheren CGI im Sinne dieses Artikels hat ein böswilliger Cracker keine Chance in das System einzudringen, Daten zu klauen oder anderweitigen Schaden zu verursachen.
Welche Rechte hat ein CGI Prozess
Das hängt von der Konfiguration des Webservers ab! Von einigen Providern
weiß ich dass sie den Apache als Root (Root ist der Superuser unter LINUX -
der darf Alles) laufen lassen, das bringt gewisse Vorteile in der Administration,
mit Rootrechten darf der Apache beispielsweise in einem jeden Homepageverzeichnis
die Logfiles schreiben was andererseits einen erhöhten Verwaltungsaufwand
erfordern würde, wenn das nicht so wäre. Dagegen ist ja auch nichts
einzuwenden... aber: Jeder CGI - Prozess welcher als Kindprozess des HTTP -
Daemons Apache gestartet wird sollte nicht als Root laufen und genau das
liegt in den Händen des Providers! Lassen wir also ein CGI unter group
(das ist die Regel) oder other laufen, aus diesem Grunde sollten auch die
Ausführungsrechte eines CGIs auf owner/group/other: ausführen
gesetzt werden.
Systembefehle über CGIs ausführen
Mit dem vorangegangenen Abschnitt wurde deutlich gemacht, dass ein CGI
unter der Benutzergruppe group/other üblicherweise auf dem
Server läuft und damit auch die Berechtigungen besitzt welche diese
administrativen Benutzergruppen haben. Nehmen wir einmal an, Sie haben
ein CGI geschrieben welches einen <input name=string> ganz
einfach an das System übergibt mit $ergebnis = qx|string|
und Sie geben $ergebnis im Browser aus... das funktioniert doch
toll, nicht wahr? Indes: Es ist nicht das was Sie haben wollen denn
jeder könnte hier ja eingeben rm * und alle Scripte
sind weg. Deswegen wird wohl niemand erlauben Systembefehle welche ein
Jeder im Browser eingeben kann per CGI ausführen zu dürfen...
Und nun haben Sie sich ein CGI downgeloadet womit über den Browser ein
ping Kommando abgesetzt werden kann, coole Sache! Aber versäumen
Sie bitte nicht, das Script mal etwas näher in Augenschein zu nehmen!
Schauen Sie in die Unterfunktionen nach Konstrukten wie $v = `kommando`
oder system(kommando) oder qx/kommando/ oder
open PIPE, "| kommando" ... ! Ups, das sind da Systembefehle!
Ja was könnte denn passieren? Nun, über ein Pipe kann jeder ein
weiteres Kommando an den Eingabestring dranhängen, wobei es völlig
uninteressant ist ob der Parameter zum Ersteren Kommando einen Sinn macht!
Zum Verständnis: Geben Sie mal auf der Kommandozeile ein
Sie erhalten Datenträger nicht gefunden oder so. Logisch, denn Laufwerke haben nur einen einzigen Buchstaben. Aber nun geben Sie mal ein:
... Jupp! Sie sehen das Ergebnis von dir c:! Und nun erinnern Sie sich wieder an das ping Script, da steht
|
$pingergebnis = qx(ping -c 5 $eingabestring);
|
Wobei das $pingergebnis später im Browser angezeigt werden soll. Ein frecher Hacker denkt jedoch nicht im entferntesten daran irgendeine IP in seinen Browser einzugeben, er gibt ein:
... und sieht das komplette Directory Listing des Verzeichnisses /cgi-bin/! Natürlich könnte er auch noch andere Kommandos absetzen. Aber schauen wir was da wirklich abläuft, beim PERL Interpreter kommt nämlich das hier an:
|
$pingergebnis = qx(ping -c 5 denkste | ls -la);
|
Somit steht in $pingergebnis die Ausgabe von ls -la (List Dir Longformat
versteckte Dateien). Genau das hätten Sie vermeiden können, wenn Sie
den Eingabestring geprüft hätten ob da wirklich nur eine IP eingegeben
wurde und weiter nichts.
Wie verhindere ich den Missbrauch von Pipes
Wenn sich Systembefehle in einem CGI nicht vermeiden lassen checken Sie den
Inputstring welcher als Parameter an den Systembefehl übergeben wird
sorgsam ab! Dabei ist es manchmal einfacher einen String auf erlaubte Zeichen
zu prüfen als auf das Vorhandensein von unerlaubten Zeichen. Um im o.g.
Beispiel zu bleiben sollte eine IP an das ping Kommando übergeben
werden und weiter nichts. Prüfen Sie in diesem Falle einfach ob eine IP -
Addresse eingegeben wurde:
# Eine IP auf Syntax prüfen like 127.0.0.1
sub isip{
my $ip = $_[0];
# ersteinmal prüfen, ob Punkte im String enthalten sind
if (not ($ip =~ /\./)) { return 0;}
# prüfen ob keine anderen Zeichen als Digits oder Punkt
if ( $ip =~ /[^0-9\.]/ ){ return 0;}
# Das Splitting muss genau 4 Teile ergeben
my $val = my($a, $b, $c, $d) = split(/\./, $ip);
if( $val != 4 ){ return 0;}
# Range prüfen
if ( ($a <0 || $a >255) || ($b <0 || $b >255) || ($c <0 || $c >255) || ($d <0 || $d >255) ){
return 0;
}
# Alles 0 darf nicht sein
if ( ($a == 0) && ($b == 0) && ($c == 0) && ($d == 0) ){
return 0;
}
# Alles 255 darf auch nicht sein
if ( ($a == 255) && ($b == 255) && ($c == 255) && ($d == 255) ){
return 0;
}
# Alles OK
return 1;
}
|
Ein Modul was Ihnen genau diese Arbeit abnehmen kann ist das
web.pm welches neben vielen anderen interessanten Funktionen die
Methode isIP("ipstring") zur Verfügung stellt. Und hier noch ein
Beispiel zu einer Funktion welche prüft ob es sich beim eingegebenen
String um einen Domänen-Namen handelt:
sub chkstr{ my $s = shift; if( $s =~ /[^a-z0-9\.-]/i ){ return 0 } else { return 1 } } |
Diese Funktion gibt den Wert 1 zrück wenn das Argument ein syntaktisch gültiger Domänen-Name ist, wenn nicht ist der Rückgabewert 0.
Sendmail - Ein mögliches Risiko
Weithin bekannt und gern genutzt ist der Mail Transfer Agent sendmail
welcher i.d.R. unter /usr/sbin/sendmail vom Provider zur Verfügung
gestellt wird. Mit sendmail können Mails recht einfach an beliebige
eMail-Adressen geschickt werden ohne dass sich der Absender um die Zustellung
kümmern muss. Aber Vorsicht, denn üblicherweise wird für die
Verwendung von sendmail ein Handler auf ein Pipe geöffnet
und der Handler beschrieben. Sie sollten in jedem Falle auch hier alle Eingaben
des Benutzers in den Browser auf unerlaubte Zeichen prüfen.
Interessante Möglichkeiten bietet das Modul Net::SMTP womit sich
ein Systemcall von sendmail erübrigt. Mit diesem Modul wird eine
Mail nicht an einen Handler bzw. über ein Pipe an sendmail
übergeben sondern über den TCP Stack und Port 25 (SMTP Protokoll).
Wenn der SMTP Hostname bekannt ist wo sich der eMail Account des Empfängers
befindet, können Sie Mails mit Net::SMTP auch direkt dorthin schicken.
Diese Art der Mailzustellung bietet sich beispielsweise für Feedback Formulare
an, nämlich da wo der Empänger der Mail fest eingebaut ist.
Weiterführendes
Es liegt auf der Hand dass ein derartig umfangreiches Themengebiet nicht in einem
kleinen Artikel abgehandelt werden kann. Neben der Möglichkeit von
Sicherheitslücken in CGIs aufgrund ungefilterter Eingaben und deren
Übergabe an Systembefehle gibt es auch noch andere Punkte welche in
dieser Hinsicht beachtenswert sind (zum Beispiel das Erlauben von File Uploads).
Auf den Seiten von Wolfgang Wiese
finden Sie eine größere Abhandlung der gesamten Problematik CGI
Sicherheit. Und sollten Sie einen Verdacht haben, dass auf Ihrem Server
irgendwas nicht stimmt in Fragen Sicherheit, so wenden Sie sich vertrauensvoll
an Ihren Internet Service Provider.
|