Was tut chroot?
Mit der Funktion chroot() kann ein Programm sein Wurzelverzeichnis (/) wechseln. Nach dem Aufruf kann es nicht mehr auf Dateien außerhalb des neuen Baumes zugreifen (man spricht hier auch von chroot jail).
Mit dem Befehl chroot kann man einen Befehl mit einem neuen Wurzelverzeichnis starten. Das ist z.B. sinnvoll, wenn man von einer Rettungsdiskette in einem gemounteten System arbeiten will.
Achtung: chroot kann nur vom Benutzer root aufgerufen werden.
Beispiel:
mount /dev/hda5 /mnt/rootplatte chroot /mnt/rootplatte /bin/bash -i
chroot wird gerne verwendet, um kritische Programme vom übrigen Filesystem zu isolieren. Wenn an z.B. den Nameserver als chroot laufen läßt, befindet sich ein eventueller Eindringling im Gefängnis (jail), aus dem er kaum ausbrechen kann - natürlich installiert man in diesem jail nur Dinge, die der Nameserver selbst braucht; andere Programme haben dort nichts verloren. In der Gefängniszelle sind ja auch keine Schlosserwerkzeuge vorhanden...
Chroot einrichten
Nehmen wir an, wir wollten den DNS-Server 'named' chrooted installieren. Im folgenden wird das normale Dateisystem als 'n/' und das jail als 'j/' bezeichnet.
- Schritt-1: Wir erzeugen ein Verzeichnis für j/ in n/, z.B. /var/dnsj. Das wird dann zu j/.
- Schritt-2: Wir lesen in der Doku nach, welche Files named braucht - z.B. /etc/named.conf. Diese Files kopieren wir von n/ nach j/. Natürlich muss unterhalb von j/ die Verzeichnisstruktur wie unter n/ eingerichtet werden - z.B. j/etc. Natürlich müssen wir in j/ auch diejenigen user und groups einrichten, die named braucht.
- Schritt-3: Wir prüfen, welche Libraries named braucht. Das geht mit 'ldd /path/named'. Diese Libraries kopieren wir nach j/ - die Verzeichnisstruktur muss erhalten bleiben. Soweit ist alles noch einfach. Leider reicht das meistens nicht. Gewöhnlich benötigen Programme auch noch andere Dateien, die mit ldd nicht angezeigt werden. Die müssen wir durch Testen finden. Dafür benötigen wir 'strace'. Also 'ldd /path/strace' und strace samt Libraries nach /j kopieren - wenn alles fertig ist, wird das natürlich wieder gelöscht. Ebenso benötigen wir vorübergehend eine Shell - named selbst braucht keine. Also nochmal das Ganze mit 'bash'; wir kopieren diese nach/j/bin (wenn in j/ eine shell benötigt wird - bei sshd z.B. - sollte man eine Krankenkassenshell nehmen, ash eignet sich da). Jetzt kann es losgehen.
- Schritt-4: Wir gehen als root mit 'chroot /var/dnsj /bin/bash' ins Gefängnis - man beachte, dass sich das Argument von chroot bereits auf j/ bezieht! Jetzt haben wir eine Shell in j/.
- Schritt-5: Wir testen named mit '/bin/strace /bin/named'. Keine Angst, man muss dafür nicht Experte für strace sein. Uns interessieren lediglich Fehlermeldungen wie 'no such file' oder 'cannot open device'; den Rest kann man im Normalfall ignorieren. Am besten geht man schrittweise vor, um Probleme mit Folgefehlern zu umgehen. Bei der ersten Meldung schauen wir nach, ob das angeklagte Teil in n/ existiert. Wenn ja, kopieren wir es nach j/, wenn nein, ignorieren wir die Meldung erstmal. Hinweis: Beim Kopieren aus /dev wird die -a Option benötigt; manchmal geht es auch mit -l. Es kann auch sein, dass strace Dateirechte anmeckert - dann setzen wir sie. Wenn wir einen Schritt gemacht haben, starten wir wieder. Dies wiederholen wir, bis alle diese Fehlermeldungen verschwunden sind. Im Zweifelsfall machen wir zum Vergleich einen strace mit in n/.
- Schritt-6: Jetzt sollte named in j/ starten. Wir testen das Laufzeitverhalten - notfalls auch mit strace.
- Schritt-7: Wenn es läuft, alles auf readonly setzen, was keine Schreibrechte braucht.
- Schritt-8: In /etc/init.d/ die Startprozedur für named ändern, damit wirklich der chroot-named beim Booten gestartet wird. Es schadet nichts, den ursprünglichen named umzubennen, damit er nicht aus Versehen gestartet werden kann.
Das wars, das heißt, es war es nicht, weil wir noch strace und bash aus j/ entfernen müssen.
System betreten
Möchte man ein System betreten, um bspw. GRUB zu installieren, so verwendet man folgenden Code (als root):
mount /dev/sda1 /mnt mount -o bind /dev /mnt/dev mount -o bind /dev/shm /mnt/dev/shm mount -o bind /proc /mnt/proc mount -o bind /sys /mnt/sys chroot /mnt
Das Binden von /dev auf /mnt/dev ist notwendig, da bspw. update-grub sonst auf die Gerätedateien sda, sda1 usw. keinen Zugriff hat.
Updates
Bei der Aktualisierung des Systems muss man das ganze leider wiederholen. Meistens ist das einfacher, da sich nur Teile ändern.
Überwachung
Ein Gefängnis muss bewacht werden. Das Minimum sollten 3 Prozeduren sein: backup, restore, test. Beim Backup erzeugt man Md5-Summmen der schreibgeschützten Dateien, die man mit test via Cronjob nachprüft. Was man im Falle eines Einbruchs tut, hängt natürlich vom Einzelfall ab.
Alternative
Bei modernen System, wo Plattenspeicher reichlich vorhanden ist, ist es einfacher (und sicherer), einen Vserver zu installieren, auf dem dann das gewünschte Programm läuft. Etwaige Updates laufen dann unabhängig vom übrigen System, was eine erhebliche Erleichterung ist.
Offene Fragen
Sollte man nicht im chroot nen user anlegen? Man will es ja nicht unbedingt als UID 0 laufen lassen, da ja nicht jeder kernel-patches hat, die chroots einschränken. Vielleicht will ja jemand ne Kurzanleitung dazu schreiben? Mir selbst ist es bisher noch nicht gelungen, einen Service im chroot UND unter einer anderen UID als 0 laufen zu lassen. -- RomanKreisel
Als Root kann ich als Einbrecher mir alles mögliche in die chroot mounten. Das wars dann mit Sicherheit.
Manche Services (ssh, manchmal Apache, o.Ä.) benötigen einfach root Rechte. Die meisten andern Services lassen sich zum sofortigen ablegen ihrer Rechte bringen schöne Beispiele wären Bind, squid oder exim. Hierbei sollte es ausreichen eine /etc/passwd anzulegen und dem Service über die Konfiguration zu sagen, welchen Benutzer er nehmen soll. -- HelmutGrohne 2005-01-03 14:56:55
- Mit den oben genannten Prozeduren kann man Dateiänderungen im jail prüfen. Was kann man sonst noch tun, um Eindringlinge zu entdecken?
- Wir machen bei ssh alle 5 Minuten einen Test auf Dateiänderung. Bei Änderungen machen wir einen tcpdump für 200 Pakete, um möglicherweise die Ip des Hackers aufzuzeichenen. Dann killen wir ssh, machen einen Dump des jails, stellen das Original wieder her und starten ssh neu: natürlich schicken wir eine Mail an den Admin. Hat jemand bessere/zusätzliche Ideen?
- Und wenn der Besitzer des jails die Dateien ändert?
- Wie prüfe ich am einfachsten ob sich Dateien verändert haben?
- Prüfsummen ablegen per crc32, mdm5, etc