Original in fr Frédéric Raynal, Christophe Blaess, Christophe Grenier
fr to en Georges Tarbouriech
en to de Guido Socher
Christophe Blaess ist ein unabh�ngiger Raumfahrtingenieur. Er ist ein Linuxfan und arbeitet die meiste Zeit mit diesem System. Er koordiniert die �bersetzung der Man-pages die vom Linux Dokumentationsprojekt ver�ffentlicht werden.
Christophe Grenier ist Student im f�nften Semester an der ESIEA, wo er auch als Systemadministrator arbeitet. Er hat eine Leidenschaft f�r Computersicherheit.
Frédéric Raynal benutzt Linux, weil er mit Software, die keine Patente enth�lt, arbeiten m�chte. Er geht gerne ins Kino. Dancer in the Dark ist ein guter Film.
Dies ist der erste Artikel in einer Serie von Artikeln �ber Sicherheitsl�cher, die beim Entwickeln von Software entstehen k�nnen. Diese Artikel werden zeigen, wie man Sicherheitsprobleme vermeiden kann, indem man seine Programmiergewohnheiten ein wenig �ndert.
Im allgemeinen dauert es nicht l�nger als zwei Wochen, bis wieder ein Sicherheitsloch in einer gr��eren Anwendung auftaucht. Ein Sicherheitsloch, das es z.B dem auf dem Rechner eingeloggten Benutzern erlaubt, root zu werden. Trotz der hervorragenden Qualit�t der meisten dieser Applikationen scheint es immer sehr schwierig zu sein, sichere Programme zu schreiben. Ein sicheres Programm gibt einem Benutzer mit b�sen oder kriminellen Absichten keine M�glichkeit, sich zu Systemteilen Zugang zu verschaffen, zu denen er keinen Zugang haben soll. Die Verf�gbarkeit von Quellcode ist eine gute Sache und wird von vielen Programmierern sehr gesch�tzt, aber der kleinste Fehler in einem Programm wird damit sichtbar f�r jedermann. Diese Fehler werden oft zuf�llig gefunden und Leute, die nach solchen Fehlern suchen, haben nicht immer gute Absichten.
F�r einen Systemadministrator besteht die t�gliche Arbeit
darin, Newsgruppen und Webseiten, auf denen Sicherheitsl�cher
ver�ffentlicht werden, zu studieren und f�r die entsprechenden
Pakete einen Update einzuspielen. Der Programmierer kann durch die
Studie dieser Informationen viel lernen, speziell wenn er selbst
versucht, an seinem Rechner solche Sicherheitsl�cher
auszuprobieren. Egal wie schnell ein Sicherheitsproblem gefunden wird,
ist es immer besser, Sicherheitsprobleme von vornherein zu vermeiden.
Wir werden hier einige klassische Fehler besprechen, und zeigen
L�sungen f�r diese Probleme. Wir werden keine
Sicherheitsprobleme besprechen, die speziell in Netzwerken auftreten, da
diese meist Konfigurationsfehler sind. Systemfehler, die DOS
(Denial Of Service) Angriffe zulassen. Diese Probleme
betreffen den Systemadministrator oder den Kernelentwickler, aber
manchmal auch Applikationsprogrammierer. Speziell dann, wenn diese
Programme auf Daten zugreifen, die nicht unbedingt
vertrauensw�rdig sind. Typische Programme in dieser Klasse sind
pine
, acroread
, netscape
,
access
,... Einige von diesen Programmen erlaubten es,
Informationen auszuspionieren oder direkten Zugriff auf das System zu
erhalten. Es ist eine Tatsache, da� sicheres Programmieren
einfach jeden betrifft.
Diese Artikelserie zeigt Methoden, die benutzt werden k�nnen, um ein Unixsystem zu besch�digen. Wir h�tten diese Probleme einfach auflisten k�nnen, aber wir bevorzugen offene und klare Erkl�rungen, damit alle die Mechanismen verstehen. Nach dieser Serie solltest du in der Lage sein, Sicherheitsfehler zu beheben und zu vermeiden. F�r jedes Sicherheitsloch werden wir denselben Ansatz w�hlen. Wir erkl�ren, wie sie funktionieren und dann zeigen wir, wie man sie vermeidet.
Dieser erste Artikel erkl�rt grundlegende
Sicherheitsmechanismen. Wir zeigen, wie man Privilegien durch den
Mi�brauch von Set-UID und Set-GID erhalten kann. Als
n�chstes analysieren wir die bekannte C Funktion
system()
und zeigen die Sicherheitsl�cher, die es in
dieser Funktion gibt.
Wir werden h�ufig die Problematik anhand kleiner C Programme
aufzeigen, aber diese Problematiken lassen sich auf andere
Sprachen �bertragen: perl, java, shell scripts... Einige Probleme
sind spezifisch f�r eine Sprache, aber das ist nicht immer so, wie
wir anhand der Funktion system()
sehen werden.
Auf einem Unixsytem sind die Benutzer nicht alle gleich. Sie haben
nicht die gleichen Rechte und das gilt auch f�r Applikationen. Der
Zugriff auf das Dateisystem und die Peripherie einer Maschine unterliegt
einer strikten Identit�tskontrolle. Einige Benutzer d�rfen
empfindliche Operationen ausf�hren, um das System in gutem Zustand
zu halten, andere haben diese Rechte nicht. Eine Nummer, die als UID
(User Identifier) bezeichnet wird, wird f�r diese
Identit�tskontrolle benutzt. Um die Sache einfacher zu machen, gibt
es einen Namen, der dieser Nummer entspricht und die Assoziation
zwischen Namen und Nummer erfolgt �ber die Datei
/etc/passwd
.
Der Benutzer root, mit der UID 0, kann auf alles im System
zugreifen. Er kann nicht nur auf alle Dateien zugreifen, er kann auch
die physikalische Konfiguration einer Maschine �ndern. Er kann
Partitionen mounten, Netzwerk Interfaces aktivieren, IP Adressen
�ndern oder Systemaufrufe wie mmlock()
benutzen, um
auf den physikalischen Speicher zuzugreifen. In zuk�nftigen
Artikeln werden wir die M�glichkeiten studieren, die Posix.1e bietet,
um die Privilegien von Programmen, die mit root Rechten laufen,
zu limitieren. F�r den Augenblick nehmen wir jedoch an, da�
der Benutzer root alles kann.
Die Attacken, die wir besprechen, sind interne Attacken. Ein eingeloggter und authentifizierter Benutzer versucht, Privilegien zu erlangen, die er eigentlich nicht hat. Weiterhin gibt es Netzwerkangriffe, externe Angriffe, bei denen Leute versuchen, Verbindungen aufzubauen, die sie eigentlich nicht aufbauen d�rfen. Wenn man die Privilegien eines anderen Benutzers erhalten hat, bedeutet das, da� alles unter seinem Namen, seiner UID, gemacht wird und nicht unter der urspr�nglichen UID. Nat�rlich wird ein Angreifer versuchen, die ID von root zu erhalten, aber auch andere Benutzer sind von Interesse, weil man damit auf Informationen zugreifen kann, (news, mail, lp...) und man damit gesch�tzte Daten (Briefe, pers�nliche Dateien, etc) erhalten kann. Au�erdem werden sie benutzt, um illegale Aktivit�ten gegen�ber anderen zu verstecken.
Um die Privilegien, die f�r einen anderen Benutzer reserviert sind, zu nutzen, ohne als dieser Benutzer eingeloggt zu sein, mu� man zumindest die M�glichkeit haben, mit einer Applikation zu kommunizieren, die unter der UID des Opfers l�uft. Wenn eine Applikation --ein Proze�-- unter Linux l�uft, dann hat diese eine klar definierte Identit�t. Zun�chst hat ein Programm ein Attribut namens RUID (Real UID), die der UID (Benutzer Identit�t) des Benutzers entspricht, der das Programm gestartet hat. Diese Daten werden vom Kernel verwaltet und k�nnen sich normalerweise nicht �ndern. Es gibt noch ein weiteres Attribut, die EUID (Effective UID). Die EUID wird herangezogen, wenn der Kernel Zugriffsrechte regelt (beim �ffnen von Dateien, Benutzung spezieller Systemaufrufe ...).
Um eine Applikation mit einer Effective UID (bestimmte Privilegien),
die anders als die Real UID (Benutzer, der das Programm startete) laufen
zu lassen ist, mu� ein spezielles Zugriffsrechte-Bit namens Set-UID
(wird mit chmod gesetzt) gesetzt sein. Dieses Bit befindet sich in dem
Datei Permission Attribut. Es hat den oktalen Wert 4000. Das Set-UID
Bit wird als ein s
dargestellt, wenn man sich die
Zugriffsrechte mit dem Befehl ls
anzeigen l��t:
Der Befehl ">> ls -l /bin/su -rwsr-xr-x 1 root root 14124 Aug 18 1999 /bin/su >>
find / -type f -perm +4000
" zeigt alle
Applikationen im Dateisystem, die das Set-UID Bit gesetzt haben. Wenn
der Kernel ein Programm, das dieses Set-UID Bit gesetzt hat, startet,
dann benutzt er als EUID die UID des Benutzers, dem die Datei
geh�rt. Die RUID �ndert sich nicht und entspricht weiterhin
dem Benutzer, der das Programm startete. Der Befehl
/bin/su
benutzt z.B diese Eigenschaft. Jeder Benutzer kann
den Befehl /bin/su
starten, aber er l�uft mit der UID
des Eigent�mers (root). Es braucht wohl nicht weiter
betont zu werden, da� solch ein Programm sorgf�ltig programmiert
werden mu�.
Jeder Proze� hat auch eine effektive Group ID, EGID, und eine real
group ID , RGID. Das Set-GID (oktal 2000 ) regelt die
Gruppenzugriffsrechte, wenn ein Programm gestartet wird. Eine
merkw�rdige Kombination entsteht, wenn das Set-GID Bit gesetzt ist,
ohne da� die Datei ein execute Bit gesetzt hat. Dies ist eine
Konvention, die nichts mit den Privilegien einer Applikation zu tun hat,
sondern eine Datei, die mit der Funktion
fcntl(fd, F_SETLK, lock)
geblockt werden kann.
Normalerweise benutzen Applikationen diese Set-GID bit nicht. Einige
Spiele benutzen es z.B um Highscores systemweit zu speichern.
Es gibt verschiedene Typen von Angriffen gegen ein System. Heute werden wir die Mechanismen studieren, mit dem ein Angreifer einen beliebigen Befehl aus einer Applikation heraus starten kann. Dieser Befehl ist normalerweise die Shell, die dann unter der UID der Applikation l�uft. Eine zweite Art von Angriff ist ein buffer overflow. Dieser gibt dem Angreifer die M�glichkeit, beliebigen Maschinencode auszuf�hren. Ein dritter Typ eines Angriffs basiert auf race conditions. Es wird die Zeit genutzt, die zwischen dem Ausf�hren verschiedener Codest�cke vergeht. In dieser Zeit wird irgendein Teil des Systems ver�ndert (normalerweise eine Datei), w�hrend die Applikation denkt, es sei gleichgeblieben.
Die zwei ersten Arten von Angriffen versuchen, die Shell mit den
Privilegien des Eigent�mers eines Programmes auszuf�hren. Der
dritte Type hingegen versucht, Zugriff auf gesch�tzte Systemdateien
zu erhalten. Auch der Lesezugriff auf bestimmte Dateien wie z.B
/etc/shadow
ist ein Sicherheitsrisiko.
Die Ziele eines Angriffs auf die Systemsicherheit sind meist
Programme, die das Set-UID (oder Set-GID) Bit gesetzt haben. Das betrifft
auch andere Applikationen, die nicht unter der UID ihrer Benutzer
laufen. Die System daemons (Server Prozesse) repr�sentieren einen
gro�en Teil dieser Art von Programmen. Ein daemon wird
im allgemeinen beim Booten gestartet und l�uft im Hintergrund.
lpd
, z.B erlaubt es jedem Benutzer Dokumente an den Drucker
zu schicken. sendmail
empf�ngt und verschickt E-Mail,
oder apmd
, der das Bios nach dem Status der Batterie
befragt (l�uft meist auf Laptops). Einige daemons kommunizieren
auch mit externen Benutzern �ber das Netzwerk (Ftp, Http, Telnet...
). Ein Proze� namens inetd
verwaltet
Netzwerkverbindungen.
Zusammenfassend k�nnen wir feststellen, da� ein Programm angegriffen werden kann, sobald es mit einem Benutzer ungleich dem Benutzer der es gestartet hat, kommunizieren kann. Wenn es in der Natur des Designs eine Applikation liegt, so etwas zu tun, dann mu� man sehr sorgf�ltig programmieren.
Eine Applikation l�uft normalerweise mit einer EUID ungleich der RUID, um dem Benutzer gezielten Zugriff auf Privilegien zu geben, die er normalerweise nicht hat (Dateizugriff, reservierte Systemaufrufe). Im allgemeinen wird das jedoch nur punktuell ben�tigt, zum Beispiel beim �ffnen einer Datei, ansonsten ist die Applikation in der Lage, mit den Rechten des Benutzers, der sie gestartet hat, auszukommen. Man kann die EUID tempor�r mit dem Befehl seteuid �ndern:
int seteuid (uid_t uid);Eine Applikation kann immer den Wert der EUID so �ndern, da� er der RUID entspricht. In diesem Fall wird die alte UID gespeichert in einem Feld namens SUID (Saved UID). Es ist m�glich, die SUID zur�ckzuerhalten und als EUID zu benutzen. Nat�rlich kann ein Programm mit der EUID Null (root) sowohl die EUID als auch die RUID beliebig �ndern (Das Programm
/bin/su
funktioniert
so).
Um das Risiko eines Angriffs zu reduzieren wird vorgeschlagen, die EUID zu �ndern und die RUID zu benutzen, wenn gerade keine speziellen Privilegien gebraucht werden. Wenn Privilegien gebraucht werden, schreibt man die Saved UID wieder in die EUID. Hier ist ein Beispiel:
uid_t e_uid_initial; uid_t r_uid; int main (int argc, char * argv []) { /* Saves the different UIDs */ e_uid_initial = geteuid (); r_uid = getuid (); /* limits access rights to the ones of the * user launching the program */ seteuid (r_uid); ... privileged_function (); ... } void privileged_function (void) { /* Gets initial privileges back */ seteuid (e_uid_initial); ... /* Portion needing privileges */ ... /* Back to the rights of the runner */ seteuid (r_uid); }
Diese Strategie ist besser als die oft gesehene andersherum arbeitende Strategie, bei der die EUID tempor�r zur RUID gesetzt wird, bevor man "riskante" Programmst�cke ausf�hrt. Diese Reduzierung der Privilegien ist jedoch nutzlos gegen einen Buffer overflow Angriff. Das werden wir im n�chsten Artikel sehen. Bei einem Buffer overflow wird beliebiger Code ausgef�hrt und dieser kann die Anweisungen enthalten, um die EUID zu ver�ndern. Trotzdem hilft dieses nur punktuelle Setzen der Privilegien gegen das beliebige Ausf�hren einiger Befehle und gegen die meisten Race Conditions gut.
Eine Applikation mu� oft einen externen Befehl aufrufen. Ein
bekanntes Beispiel ist der Befehl mail
, um ein Mail zu
verschicken ( einen Alarm zu melden oder einfach Statistiken zu
schicken). Die einfachste L�sung, um das zu machen, ist die Library
Funktion system() zu benutzen:
int system (const char * command)
Diese Funktion ist sehr gef�hrlich: Sie ruft die Shell auf, um
einen Befehl, das in der Variable "command" spezifiziert wurde,
auszuf�hren. Das Verhalten der Shell h�ngt dabei von den
Vorlieben des Benutzers ab. Ein typisches Beispiel ist die
PATH
Umgebungsvariable. La� uns annehmen, da�
eine Applikation mail
aufruft. Dieses Programm schickt z.B
den Quellcode dem Benutzer, der es aufruft:
Nehmen wir weiterhin an, da� das Programm mit Set-UID root arbeitet:/* system1.c */ #include <stdio.h> #include <stdlib.h> int main (void) { if (system ("mail $USER < system1.c") != 0) perror ("system"); return (0); }
Beim Ausf�hren dieses Programmes wird die Shell (>> cc system1.c -o system1 >> su Password: [root] chown root.root system1 [root] chmod +s system1 [root] exit >> ls -l system1 -rwsrwsr-x 1 root root 11831 Oct 16 17:25 system1 >>
/bin/sh
) mit der Option -c
aufgerufen und
�bergibt den String der als Befehl ausgef�hrt werden soll.
Die Shell sucht dann die Verzeichnisse aus der Umgebungsvariable
PATH
ab, um eine ausf�hrbare Datei names
mail
zu finden. Der Benutzer braucht blo� die Variable
PATH
zu �ndern und der Befehl, den er ausf�hren
m�chte in mail
umbenennen und schon kann er irgendetwas ausf�hren:
Damit wird z.B versucht,>> export PATH=. >> ./system1
mail
im augenblicklichen
Verzeichnis zu finden. Jetzt schreiben wir einfach ein kleines Shell
Script und nennen es mail. Das Skript wird dann mit der EUID des
Dateieigent�mers der Applikation ausgef�hrt. Hier ist ein
Skript, das /bin/sh
ausf�hrt. Da stdin umgeleitet ist,
m��en wir uns die Eingabe zur�ck vom Terminal holen.
Unser Skript sieht damit so aus:
Hier ist das Ergebnis:#! /bin/sh # "mail" script running a shell # getting its standard input back. /bin/sh < /dev/tty
>> export PATH="." >> ./system1 bash# /usr/bin/whoami root bash#
Der erste L�sungsansatz besteht nat�rlich darin, immer
einen vollen Pfadnamen zu benutzen, z.B /bin/mail
. Damit
gibt es ein neues Problem. Die Applikation vertraut darauf, da�
mail
an einer bestimmten Stelle im System zu finden ist.
W�hrend /bin/mail
im allgemeinen in jedem System zu finden
ist, gibt es andere Programme wie z.B GhostScript, die in verschiedenen
Distributionen unterschiedlich installiert sind. Desweiteren gibt es
noch einen anderen Typ von Angriff bei einigen alten Shells, der auf er
Umgebungsvariable IFS
beruht. Die Shell benutzt sie, um die
Trennzeichen zwischen Befehl und Argument zu finden. Im allgemeinen
sind das Leerzeichen Tab und Return. Wenn der Benutzer /
hinzug�gt, dann wird der Befehl "/bin/mail
" als
"bin mail
" interpretiert.
Eine ausf�rbare Datei namens
bin
kann jetzt im augenblicklichen Verzeichnis
ausgef�hrt werden, wenn PATH
entsprechend gesetzt
ist.
Unter Linux ist die IFS
Umgebungsvariable kein Problem
mehr, da die bash sie mit Leerzeichen, Tab und Return beim Start
vervollst�ndigt. Das gleiche gilt f�r pdksh. Dennoch sollte
man sich nicht darauf verlassen, denn Applikation werden oft auf andere
Systeme portiert und diese Systeme k�nnen sich hier anders
verhalten.
Einige andere Umgebungvariablen k�nnen unerwartete Probleme
machen. Das Programm mail
erlaubt es z.B dem Benutze,r ein
anderes Programm auszuf�hren, w�hrend er eine Nachricht
schreibt. Das geht mit der Escapesequenz "~!
". Schreibt
der Benutzer den String "~!command
" am Anfang
einer Zeile, dann wir dieser ausgef�hrt. Das Program
/usr/bin/suidperl
zum Schreiben von Set-UID perl Scripten
rief /bin/mail
auf, wenn es irgendein Problem hatte, um
root eine Nachricht zu schicken. Da suidperl ein Set-UID root
Programm ist, wird alles mit root Rechten ausgef�hrt. In der
Nachricht an root steht der Name der fehlerhaften Datei. Jemand kann
eine Datei erzeugen mit einem Dateinamen, der carriage return gefolgt
von ~!command
enth�lt. Wenn ein suidperl
Programm �ber ein Problem stolpert, das mit dieser Datei
zusammenh�ngt, dann wird /bin/mail
aufgerufen und
mit der Escapesequenz aus dem Dateinamen gef�ttert.
Eigentlich sollte das kein Problem machen, da mail
keine Escapesequenzen akzeptiert, wenn es nicht innerhalb eines
Terminalfensters aufgerufen wird. Leider gibt es ein nicht
dokumentiertes Feature (vermutlich vom Debuggen �brig geblieben),
das es erlaubt, Escapesequenzen zu benutzen, sobald die Umgebungsvariable
interactive
gesetzt ist. Das Ergebnis? Ein leicht
ausbeutbares Sicherheitsloch innerhalb einer Applikation, die eigentlich
die Sicherheit eines Systems verbessern sollte. Der erste Fehler ist
ein zwischen zwei Programmen geteilter Fehler. /bin/mail
enth�lt ein nicht dokumentiertes Feature, das das Ausf�hren
von beliebigem Code erlaubt. Das zweite Problem ist, selbst wenn die
Entwickler des /usr/bin/suidperl
dieses Feature nicht
kannten, sollten sie nicht einfach alle Umgebungsvariablen
�bernehmen.
Linux ignoriert normalerwiese die Set-UID und Set-GID bits bei
Skripten. Siehe /usr/src/linux/fs/binfmt_script.c
und
/usr/src/linux/fs/exec.c
. Einige Tricks erlauben es, diesen
Mechanismus zu umgehen. /usr/bin/suidperl
benutzt solche
Tricks.
Es ist nicht immer einfach einen Ersatz f�r die Funktion
system()
zu finden. Die erste Variante ist, Systemaufrufe
wie execl()
oder execle()
zu benutzen. Das
Verhalten ist dann jedoch v�llig anders, da das externe Programm
nicht mehr als Subroutine (Unterprogramm) aufgerufen wird. Das externe Programm ersetzt
den augenblicklichen Prozess. Man mu� den Prozess dublizieren und
die Kommandozeilenargumente durchsuchen wie in dem folgenden Programm.
wird :if (system ("/bin/lpr -Plisting stats.txt") != 0) { perror ("Printing"); return (-1); }
Offensichtlich viel mehr Code. Unter einigen Umst�nden wird es sehr komplex. Zum Beispiel, falls man die Standardeingabe (stdin) umleiten m�chte. Wie zum Beispiel hier:pid_t pid; int status; if ((pid = fork()) < 0) { perror("fork"); return (-1); } if (pid == 0) { /* child process */ execl ("/bin/lpr", "lpr", "-Plisting", "stats.txt", NULL); perror ("execl"); exit (-1); } /* father process */ waitpid (pid, & status, 0); if ((! WIFEXITED (status)) || (WEXITSTATUS (status) != 0)) { perror ("Printing"); return (-1); }
Die Umleitung (system ("mail root < stat.txt");
<
) wird von der Shell erledigt. Man kann
das gleiche durch eine komplexe Verkn�pfung von
fork()
, open()
, dup2()
,
execl()
, etc. erreichen. In diesem Fall ist es eine
akzeptable L�sung, die system()
Funktion zu benutzen,
aber man mu� vorher die gesamte Umgebung konfigurieren.
Umgebungsvariablen werden unter Linux in Form eines Zeigers auf ein
Array abgespeichert: char ** environ
. Dieses Array endet
mit NULL. Die Strings haben die Form "NAME=value
".
Wir fangen damit an, die gesamte Umgebung zu l�schen. Wir benutzen die Gnu Erweiterung clearenv:
oder wir setzen den Pointerint clearenv (void);
einfach zu NULL. Als n�chstes werden die Umgebungsvariablen, die wir brauchen, initialisiert:extern char ** environ;
Vor einemint setenv (const char * name, const char * value, int remove) int putenv(const char *string)
system()
aufruf z.B so:
Falls n�tig, kann man sich den Inhalt einiger n�tzlicher Umgebungsvariablen merken, bevor man die gesamte Umgebung l�scht. Z.B.clearenv (); setenv ("PATH", "/bin:/usr/bin:/usr/local/bin", 1); setenv ("IFS", " \t\n", 1); system ("mail root < /tmp/msg.txt");
LANG
, TERM
, TZ
,
HOME
. Der Inhalt, die Form und die Gr��e dieser
Variablen mu� genauestens gepr�ft werden. Es ist wichtig,
da� man die gesamte Umgebung l�scht, bevor man einige
ben�tigte Variablen definiert. Das suidperl
Sicherheitsproblem w�re nicht aufgetatucht, wenn die Umgebung
korrekt gel�scht worden w�re.
Entsprechend geht man bei einer Netzwerkkonfiguration vor. Zun�chst verw�hrt man jeder Maschiene die Verbindung. Als n�chstes werden die ben�tigten Services aktiviert. Genauso geht man bei der Entwicklung einer Set-UID Applikation vor. Erst die gesamte Umgebung l�schen und dann einzlne Umgebungsvariablen setzen.
Das Verifizieren der Parameter wird gemacht, indem man die erwarteten Werte mit den erlaubten Formaten vergleicht. Macht man es anders und �berpr�ft nur auf m�gliche Fehler in den Parametern, so k�nnte es sein, da� man einen Fall vergessen hat.
Was bei system()
gef�hrlich ist, gilt
nat�rlich auch f�r verwandte Funktionen wie
popen()
, oder Aufrufe wie execlp()
und
execvp()
, die die PATH
Variable
ber�cksichtigen.
Um die Ergonomie eines Programmes zu verbessern, ist es eine einfache
M�glichkeit, ein Program konfigurierbar zu machen. Z.B. mit Hilfe
von Makros. Um Variablen oder generische Muster handzuhaben, gibt es eine
Funktion names wordexp()
. Man mu� mit ihr sehr
vorsichtig sein, da sie einen String wie
$(commande)
als externen Befehl ausf�hrt. Es
ist genug, den String "$(/bin/sh)
" einzugeben, um eine
Set-UID Shell zu erhalten. Um so etwas zu vermeiden, hat
wordexp()
ein Attribut namens WRDE_NOCMD
, das
die Sequenz $( )
deaktiviert.
Beim Aufruf von externen Kommandos mu� man vorsichtig sein,
damit man kein Kommando erwischt, das eine Escapesequenz zum
�ffnen einer Shell zul��t. Wie z.B vi
:!command
. Es ist schwierig, alle
aufzuf�hren. Einige Applikationen sind offensichtlich
(Texteditoren, Dateimanger...) andere sind schwieriger zu entdecken, wie
wir es bei /bin/mail
gesehen haben.
Dieser Artikel hat folgende Aspekte erl�utert :
Im n�chsten Artikel werden wir �ber Speicher sprechen. Wie er organisiert ist, Funktionsaufrufe .... und dann werden wir zu buffer overflows kommen und zeigen, wie man dieses Sicherheitsloch mit shellcode ausnutzen kann.