Hallo Welt, hier ein für Aussenstehende etwas aus dem Zusammenhang gerissener Text über Linux-Sicherheit. Anlass war eine Diskussion, wie man sicher "Powerusern" erlauben kann, indirekt in ipchains einzelne Rechner zu sperren, konkret sollten Schülerrechner von Lehrern vom Internet abgeschnitten werden können, während z.B. keine Aufsicht im Raum ist. Hier also quasi eine E-Mail: Das Problem mit SetUid ist, dass ein SetUid immer mit den Rechten des Datei- besitzers statt des Aufrufers durchgeführt wird, und es erstaunlich viele Möglichkeiten gibt, in einem Programm eine Unsicherheit zu übersehen. Deshalb ist ja z.B. die Ausführung von SetUid-Shellskripten normalerweise gar nicht möglich. Wenn du unbedingt ein SetUid C-Programm schreiben willst, welches ein Skript startet, musst du im Prinzip alle Filehandles schliessen, die Umgebungs- Variablen aus dem Nichts neu anlegen, alle von der Kommandozeile übernommenen Werte kleinlich auf Plausibilität prüfen, testen ob nicht durch einen Bug der Aufrufer irgendwas macht was er nicht hätte dürfen (z.B. die Capabilities einschränken, Libraries laden, selbstdefinierte LANG/locale Dateien verwenden, das Programm debuggen, und so weiter. Alles Dinge die schon in letzter Zeit passiert sind, obwohl das mit den Libs bilde ich mir vielleicht auch ein). Kurz: Es gibt sehr viele Möglichkeiten für User, über fehlerhafte Setuids [*] beliebige Befehle als der User ausführen zu können dem das Setuid gehört. [*] ausserdem sind natürlich Server betroffen, die über Init oder Inetd gestartet werden. Man sollte Server wo immer möglich explizit mit den Rechten eines speziellen Users starten, der nicht viel kaputtmachen darf! Worauf ich raus will: Wenn immer ein Setuid nicht alles selber macht sondern andere Programme startet, ist das Potential für ein Sicherheitsloch gross. Für Ipchains-Zugriff musst du aber wohl wenigstens Ipchains starten, sonst wirds zu umständlich. Nimm auf keinen Fall system(), nimm execve() und bau ein eigenes Minimal-Environment auf und mach nicht so Dinge wie Kommandozeilenparameter direkt übernehmen oder nicht alle Filehandles auf definierte Werte zu setzen... Ich behaupte, es ist wesentlich besser, den sudo Mechanismus zu verwenden und die Aktionen als Root möglichst elementar zu halten (z.B. das was als Root gestartet wird, wird in sudoers nur als "freigeben [0-9][0-9]" erlaubt, wobei die Zahl die Nummer des freizugebenden Rechners ist. Das sudo-Programm selbst sollte nur für Poweruser ausführbar sein, und das Programm "freigeben" darf natürlich trotz sudo beliebig abgesichert programmiert werden, man weiss ja nie: Ein Bug in Kernel 2.2.1x < 2.2.16 erlaubte z.B. solche Dummheiten, wie als User dem su-Befehl den Aufruf setuid(zieluser) zu verbieten, und wenn su nicht den Bug erkannte, wurde aus su irgendwer immer su root, da ja su selber setuid root ist. Da jeder das Passwort für su sichselber kennt, war das ein dickes Sicherheitsloch. Bei mir sind prinzipiell alle (!) Setuid nur für Poweruser ausführbar (chown root.powerusers , chmod 4750) sofern es sich um Setuid root handelt. Bei Setgid Game bin ich natürlich nicht so pingelig, wer das hackt kann nur Highscores fälschen. Ausserdem habe ich nur noch ca. 10 SetUid root Progs, da viele Sachen wie mount meiner Meinung nach ruhig root vorbehalten sein können und kein SetUid brauchen (wozu gibts z.B. autofs?). SetUid findet man z.B. (setuid root) mit find / -perm +4000 -user root -type f -ls , soweit ich das jetzt auswendig sagen kann. Ich verschiebe alle Setuids in eine Partition (mit symlinks am alten Ort) und mounte die anderen mit nosuid, damit ich sie alle auf einem Haufen habe. Bei Updates schaue ich natürlich trotzdem nochmal, da ein setuid auf einer nosuid Partition irgendwie witzlos ist. Bei Linux ist abgesehen von so Gags[X] wie (bei Lilo) init=/bin/sh der Weg vom User zum Admin ganz klar abgegrenzt: Mehr Rechte gibts immer nur von einem Prozess der diese Rechte auch hat. Möglichkeiten dazu sind unsichere Setuid, für User schreibbare (...) Dateien auf die Programme mit höheren Rechten vertrauen, und last but not least Server, die den User-Daten zuviel vertrauen. Dabei kann Server auch X-Server heissen, weswegen ich bei X immer -nolisten tcp setze: Man kann den X-Server dann nur noch nach einem Login (z.B. per ssh) auf dem localhost zugreifen, was das Risiko verringert. X ist sowieso "evil": Ein grosses Programm, das komplett als root läuft. Aber dieses Opfer bringe ich dem Komfort natürlich, solange ein Rechner nicht rein als Server dient. [X] Gegenmassnahme: Bei lilo.conf fuer Linux restricted angeben und ein Passwort, damit man ohne Passwort zwar Linux starten kann, besondere Startmethoden wie "init=/bin/sh" aber nur mit Passwort erlaubt sind. Da das Passwort im Klartext am Anfang der Festplatte steht, hilft das natürlich nur, wenn ein eventuelles DOS/Win überhaupt nicht ohne Passwort erreichbar ist (sowieso besser, da es für DOS Programme gibt, die Daten auf Linuxpartitionen zugreifen können). Um auf deine Zugangsverwaltung zurückzukommen: NOCH sicherer als sudo könnte ein als root laufender Server sein, da der Benutzer dann nur noch die dem Server übermittelten Daten kontrollieren kann und sonst nix. Über tcpd ist so ein Server schnell gemacht, und man kann in hosts.* dem tcpd sagen, von welchen Rechnern aus der Zugriff erlaubt sein soll. Da man aber IP-Adressen fälschen kann und Netzwerke abhören und der tcpd nicht sicher wissen kann, WER den Server kontaktiert, schlage ich vor, Zugriffe nur von localhost (-> ggf. ssh dorthin vorher) zu erlauben und ausserdem ein (für sonst nichts verwendetes) Passwort abzufragen. Ehrlichgesagt ist aber wohl sudo einfacher handzuhaben, und beim Server schreiben kann man auch Fehler machen... ach ja, das Leben ist kompliziert :-). Wenn ich gerade bei kompliziert bin: Es ist zwar nicht bequem, aber ich habe alle Programme in /bin /sbin /lib und / mit chattr (-> lsattr) "immutable" gemacht und ein paar Dateien in /etc auch. Dann setze ich noch das "globale Capability Bounding Set" (/proc/sys/kernel/cap-bound) so, dass nicht mal root (genauer gesagt: kein Prozess, der von init gestartet wurde, also eben kein Prozess) das immutable wieder abschalten kann. Natürlich besteht die Möglichkeit, das cap-bound wieder auf unsicher zu schalten, aber meine Methode schützt gegen viele einfache Angriffe: begrenzt gegen "rm -rf /", gegen Angriffe der Art "chmod u+s /bin/sh", Angriffe der Art "echo hack::0:0:hacker:/root:/bin/bash", "chmod u+s /tmp/hack" (weil /tmp nicht setuid gemountet ist sondern nur ein readonly gemounteter oder mit immutable geschützter Bereich), und so weiter. Kurz gesagt: Eine Menge "vorgekauter" Hacks klappt nicht, und gerade "Skript Kiddies" können nicht selber denken sondern nur vorgekaut hacken :-). Ausserdem verwende ich ein Kernelmodul (eine verbesserte Version des SuSE SecuMod, leider ist die Version von SuSE sehr alt und recht nutzlos) für weitere Schutzfunktionen. Allerdings habe ich es recht lax eingestellt, da zu strenge Einstellungen das System so sicher machen wie ein System bei dem man den Prozessor ausbaut =8-).