Das Network File System ist ein weit verbreitetes Protokoll, um in Unix- und Linux-Umgebungen auf Dateiserver zuzugreifen. Doch bei der Konfiguration lauern einige Fallstricke. Häufig sind Server und Clients unsicher konfiguriert und erlauben es Angreifern, auf nicht freigegebene Dateien zuzugreifen und ihre Rechte auszuweiten. Wir zeigen, wie Sie gängige Fehler vermeiden.
Mittlerweile ist das NFS-Protokoll in die meisten Betriebssysteme integriert. Häufig laufen NFS-Server unter Linux, doch gerade hier ist die Standardkonfiguration in vielen Fällen unsicher. Deshalb möchten wir aufzeigen, wie Sie NFS-Exporte unter Linux richtig einrichten. Einige der Empfehlungen lassen sich auch auf andere Betriebssysteme übertragen.
Unter Linux wird der NFS-Server in der Datei "/etc/exports" konfiguriert. Eine beispielhafte Konfiguration mit drei exportierten Verzeichnissen könnte folgendermaßen aussehen:
Jede Zeile enthält den Exportpfad und einen oder mehrere erlaubte Clients mit Optionen für den jeweiligen Client in Klammern. Ein Client lässt sich über eine IP-Adresse, ein Subnetz oder einen Host-Namen identifizieren. Ein Stern dient als Wildcard.
Mittlerweile ist das NFS-Protokoll in die meisten Betriebssysteme integriert. Häufig laufen NFS-Server unter Linux, doch gerade hier ist die Standardkonfiguration in vielen Fällen unsicher. Deshalb möchten wir aufzeigen, wie Sie NFS-Exporte unter Linux richtig einrichten. Einige der Empfehlungen lassen sich auch auf andere Betriebssysteme übertragen.
Unter Linux wird der NFS-Server in der Datei "/etc/exports" konfiguriert. Eine beispielhafte Konfiguration mit drei exportierten Verzeichnissen könnte folgendermaßen aussehen:
Jede Zeile enthält den Exportpfad und einen oder mehrere erlaubte Clients mit Optionen für den jeweiligen Client in Klammern. Ein Client lässt sich über eine IP-Adresse, ein Subnetz oder einen Host-Namen identifizieren. Ein Stern dient als Wildcard.
Authentifizierung der Clients
Eine wichtige Sicherheitsfunktion ist die Authentifizierung der Clients. Hierfür gibt es mehrere Methoden, die gängigsten sind "AUTH_SYS" und "RPCSEC_GSS". Unter Linux wird die Authentifizierung eines Exports mit der Option "sec" konfiguriert. Mögliche Werte sind "sys" für "AUTH_SYS", sowie "krb5", "krb5i" und "krb5p" für "RPCSEC_GSS". Mehrere Werte lassen sich durch Doppelpunkt getrennt angeben.
Standardmäßig kommt die Authentifizierungsmethode AUTH_SYS zum Einsatz. Dabei enthält jeder Request des Clients eine User-ID (UID) und eine Group-ID (GID). Der Server vertraut einfach darauf, dass diese Werte korrekt sind. Dadurch ist der Client für die Authentifizierung der Nutzer des Exports verantwortlich. Ein typischer Anwendungsfall aus der Anfangszeit von NFS waren Multi-User-Systeme, bei denen die Home-Verzeichnisse der User auf einem NFS-Export liegen. Der NFS-Client ist im Kernel integriert und stellt sicher, dass Nutzer nur auf ihre eigenen Dateien zugreifen können. Erlangt ein Angreifer jedoch Root-Rechte auf dem System oder schleust einen eigenen Rechner in das Netzwerk ein, kann er einfach beliebige IDs angeben und auf Dateien anderer Nutzer zugreifen.
Um solche Angriffe zu verhindern, wurde Kerberos eingeführt. Mit RPCSEC_GSS authentifizieren sich Client und Server gegenseitig über Kerberos 5. Dies ermöglicht es, neben der reinen Nutzerauthentifizierung, die mit der Option "krb5" aktiviert wird, den Netzwerkverkehr mit krb5i zu signieren und zusätzlich mit krb5p zu verschlüsseln. So verhindern Sie, dass Daten im Netzwerk manipuliert oder mitgelesen werden können.
Die Einrichtung von Kerberos ist allerdings relativ aufwendig, da hierfür mehrere Netzwerkdienste erforderlich sind und Sie alle Server und Clients entsprechend konfigurieren müssen. Aus diesem Grund hat RPCSEC_GSS im Linux-Umfeld kaum Verbreitung gefunden. In Windows-Umgebungen gestaltet sich dank Active Directory das Einrichten leichter, da alle benötigten Dienste bereits vorhanden sind.
Nachdem die Entwickler von NFS erkannt haben, dass Kerberos oft zu kompliziert ist, führten sie den neuen Standard RPC-with-TLS ein. Hierbei besteht eine TLS-Verbindung zwischen Client und Server und derzeit unterstützen Linux und FreeBSD diesen Standard experimentell. FreeBSD überprüft die Identität des Nutzers anhand des Clientzertifikats. Bei Linux kann ein Client mit gültigem Zertifikat aktuell seine UID noch fälschen. In Zukunft könnte RPC-with-TLS eine einfachere Alternative zu Kerberos werden.
Sichere und unsichere Ports
Da bei AUTH_SYS der Kernel die Zugriffskontrolle clientseitig durchführt, könnte der neugierige Nutzer eines Multi-User-Systems auf die Idee kommen, einen eigenen NFS-Client im Userspace laufen zu lassen, und so die Zugriffskontrolle des Kernels umgehen. Um dies zu verhindern, erlaubt der NFS-Server standardmäßig nur Verbindungen von Ports unter 1024. Auf den meisten Unix-Systemen sind diese Ports privilegiert und lassen sich nur mit Root-Rechten nutzen.
Mit der Option "insecure" ist es möglich, den Zugriff auf einen NFS-Export auch von unprivilegierten Ports zuzulassen. Clients, die sich über Kerberos authentifizieren, dürfen unabhängig von der "secure/insecure"-Option immer unprivilegierte Ports benutzen. Heutzutage hat diese Option in den meisten Fällen keinen großen Einfluss mehr auf die Sicherheit. Sobald ein Angreifer Root-Rechte auf einem Client erlangt, einen eigenen Rechner in das Netzwerk einschleust oder einfach Zugriff auf einen Windows- oder macOS-Rechner hat, bei denen es keine privilegierten Ports gibt, ist diese Schutzmaßnahme ausgehebelt.
Squashing und Rechteausweitung
Da AUTH_SYS die gängigste Authentifizierungsmethode ist und Clients deshalb beliebige UIDs und GIDs verwenden können, gibt es das sogenannte Squashing, um die nutzbaren UIDs und GIDs zu begrenzen. Verwendet ein Client eine nicht erlaubte ID, wird diese durch die in der Option "anonuid/anongid" angegebene ersetzt. Üblicherweise ist dies 65.534, die dem Nutzer "nobody" gehört. Es gibt drei Squashing-Stufen:
1. no_root_squash: Alle UIDs und GIDs sind erlaubt, inklusive 0 für root. Vor dieser Option wird zurecht gewarnt, da ein Angreifer einfach von einem Client ein setuid-Binary hochladen und sie dann auf anderen Clients oder dem Server aus einer unprivilegierten Shell heraus ausführen kann, um dort eine Root-Shell zu starten. In manchen Fällen ist diese Option allerdings unumgänglich, beispielsweise bei Clients ohne lokale Laufwerke, deren Betriebssystem in einem NFS-Export installiert ist.
2. root_squash: Alle UIDs und GIDs außer 0 sind erlaubt. Das ist die Standardoption. Auch wenn ein Angreifer hier nicht einfach ein setuid-Binary hochladen kann, die sofort eine Root-Shell startet, ist auch hier eine Rechteausweitung über Umwege möglich. Hierfür lädt ein Hacker ein setgid-Binary hoch, die eine Shell mit einer der vielen Systemgruppen startet, beispielsweise disk, sudo, docker oder shadow. Nach dem Ausführen einer setgid-Binary, die der Gruppe disk gehört, hat der Angreifer vollen Lese- und Schreibzugriff auf alle Festplatten.
3. all_squash: Nur anonuid und anongid sind erlaubt. Diese Option ist sinnvoll für Exporte, bei denen alle Nutzer auf alle Dateien Zugriff haben und es keine Rolle spielt, wem welche Datei gehört.
Um Clients effektiv vor Rechteausweitung zu schützen, reicht es nicht, sich auf die serverseitige Option root_squash zu verlassen. Deshalb sollten Sie clientseitig in der Datei "fstab" oder beim Mounten des Exports die Optionen "nosuid" und "nodev" verwenden:
sudo mount -o nosuid,nodev HOST:EXPORT /MOUNTPOINT
"nosuid" verhindert, dass setuid- und setgid-Binaries aus dem Export ihre UID oder GID ändern. "nodev" wiederum verhindert, dass auf Gerätedateien aus dem Export zugegriffen wird. Das ist wichtig, weil ein Angreifer auch mithilfe von Gerätedateien Rechte ausweiten kann. Hierfür erstellt er im Export eine Gerätedatei, die durch dieselbe Major- und Minor-Nummer identifiziert wird wie die Systempartition, macht diese allen zugänglich und greift aus einer unprivilegierten Shell darauf zu. Es gibt jedoch auch Situationen, in denen es nicht möglich ist, diese Optionen zu setzen, zum Beispiel im bereits erwähnten Fall von disklosen Clients, da das Betriebssystem ohne setuid-Binaries nicht funktionieren würde.
Auch auf dem Server ist es sinnvoll, die Dateisysteme, auf denen die Exporte gespeichert sind, mit den Optionen "nosuid" und "nodev" zu mounten. Das verhindert, dass ein Angreifer auf dem Server seine Rechte ausweiten kann.
Ein vom Angreifer manipuliertes File Handle mit "INODE = 0x2" anstelle von "0x1f5". Dadurch ändern sich die Zugriffsmöglichkeiten.
Zugriffe außerhalb des Exports verhindern
Ein kaum bekanntes Sicherheitsrisiko bei NFS liegt an der Funktionsweise des Protokolls. Anders als bei SMB werden Dateien und Ordner nicht über ihren Pfad, sondern über ein sogenanntes File Handle identifiziert. Dabei handelt es sich um ein vom Server generiertes Byte-Array, dessen Inhalt nicht standardisiert ist. Will ein Client auf eine Datei zugreifen, muss dieser erst eine LOOKUP-Anfrage mit dem File Handle des Ordners und dem Namen der Datei stellen. Als Antwort erhält er dann das File Handle, mit dem er auf die Datei zugreifen kann. Bei Linux-Servern enthalten File Handles unter anderem die UUID des Dateisystems, die Inode-Nummern der Datei und des Exportverzeichnisses.
Laut Standard dürfen Clients nichts an den File Handles verändern. Verstoßen sie dagegen, kann das zu unerwarteten Ergebnissen führen. Standardmäßig überprüft Linux nämlich nicht, ob die angeforderte Datei tatsächlich im Exportverzeichnis liegt. Ein Angreifer hat also Zugriff auf beliebige Dateien und Ordner, die außerhalb des Exports, aber auf demselben Dateisystem liegen. Dies ist besonders problematisch, wenn der Export auf der Systempartition liegt, denn dann erhält ein Angreifer unter Umständen die Kontrolle über den Server.
Absicherung mit subtree_check
Um diesen Angriff zu verhindern, gibt es die Option "subtree_check", die den Server anweist, File Handles zu prüfen. Diese Option ist allerdings standardmäßig deaktiviert, weil durch sie eine wichtige Eigenschaft von File Handles verloren geht: Ein solches muss weiterhin gültig bleiben, auch wenn die zugrundeliegende Datei in ein anderes Verzeichnis verschoben wurde. Ist subtree_check aktiv, erhält der Client in diesem Fall eine Fehlermeldung.
Grundsätzlich lautet daher die Empfehlung, dass jeder Export das Root-Verzeichnis eines eigenen Dateisystems sein soll. Falls dies nicht möglich ist, kann subtree_check aktiviert werden, wenn die Abweichung vom Standardverhalten tolerierbar ist.
Bind Mounts und ihre Risiken
Häufig werden NFS-Server so eingerichtet, dass es einen Root-Export gibt und dann alle anderen Exporte als Bind Mount darunter eingebunden sind. Das liegt daran, dass NFSv4 früher nicht ohne einen expliziten Root-Export funktioniert hat. Mittlerweile ist das aber nicht mehr nötig. Dabei ist zu beachten, dass Bind Mounts nicht vor diesem Angriff schützen. Als Beispiel sehen wir uns einen Dateiserver mit folgenden Einträgen in der "/etc/fstab" an:
/dev/sda2 / ext4
/dev/sdb1 /mnt/disk ext4
/mnt/disk/public /nfs/public none
/mnt/disk/secret /nfs/secret none
Daneben gibt es die folgenden drei Exporte in "/etc/exports".
/nfs *(ro,fsid=root)
/nfs/public *(rw)
/nfs/secret *(rw,sec=krb5p)
Bei dieser Konfiguration gibt es zwei Probleme: In der ersten Zeile wird "/nfs" exportiert. Da die Option "subtree_check" fehlt, kann ein Angreifer alle Dateien auf der Systempartition lesen, die nicht root gehören. Und zweitens befinden sich "/nfs/public" und "/nfs/secret" auf demselben Dateisystem und sind ohne "subtree_check" exportiert. Ein Angreifer erhält also über den "/nfs/public"-Export Zugriff auf alle Dateien in "/mnt/disk". Lösen lassen sich die Probleme mit subtree_check. Da "/nfs" readonly ist, sollte subtree_check keine Probleme verursachen. Bei den anderen beiden Exporten hängt es vom Nutzungsverhalten der Clients ab, ob subtree_check eine akzeptable Lösung ist, oder ob es erforderlich ist, die Exporte auf zwei Dateisysteme aufzuteilen.
Diese Konfiguration ist dann allerdings nur sicher, weil "/nfs" auf einem anderen Dateisystem liegt als "/nfs/public" und "/nfs/secret". Wäre "/nfs/secret" kein Bind Mount auf ein anderes Dateisystem, sondern einfach nur ein Unterordner von "/nfs", könnte ein Client einfach "/nfs" mounten und hätte dann Lesezugriff auf "/nfs/secret". Das kann auch subtree_check nicht verhindern. Deshalb sollten Unterordner von Exporten nicht exportiert werden.
Schutzmechanismen moderner Dateisysteme
Moderne File-Systeme wie BTRFS und ZFS bieten die Möglichkeit, in einem Dateisystem mehrere getrennte Root-Verzeichnisse zu nutzen. ZFS-Datasets schützen vor diesem Angriff, weil es nicht möglich ist, auf Dateien außerhalb des exportierten Datasets zuzugreifen. BTRFS-Subvolumes bieten hingegen keinen Schutz. Wird ein Subvolume ohne subtree_check exportiert, kann ein Angreifer auf alle Subvolumes und Snapshots zugreifen.
Wenn Exporte mit verschieden hohen Sicherheitsanforderungen aktuell auf einem Dateisystem liegen und subtree_check nicht nutzbar ist, besteht die einzige Lösung darin, die Exporte auf separate Dateisysteme oder ZFS Datasets aufzuteilen – auch wenn dies einen erheblichen Aufwand verursacht. Der Windows-NFS-Server umgeht dieses Problem gänzlich, indem er an jedes File Handle eine Signatur anhängt. Dadurch erkennt er, wenn ein Client versucht, File Handles zu manipulieren und verhindert das unmittelbar.
Erkennen von Konfigurationsfehlern
Die folgenden Regeln helfen dabei, Fehlkonfigurationen zu erkennen und zu vermeiden:
- Exporte nur für die notwendigen Clients freigeben. Keine Zugriffe über nicht vertrauenswürdige Netze zulassen (gegebenenfalls Nutzung von VPN).
- Die Option "no_root_squash" vermeiden, idealerweise "all_squash" nutzen.
- Für jeden Export ein eigenes Dateisystem nutzen oder subtree_check aktivieren (unter Berücksichtigung der möglichen Nachteile).
- Bind Mounts mit Vorsicht verwenden, da sie keine Isolation bieten. Bind Mounts nur auf das Root-Verzeichnis eines Dateisystems setzen oder subtree_check verwenden.
- Unterordner anderer Exporte nicht separat exportieren.
- Exporte in getrennte ZFS-Datasets speichern, um sie voneinander zu isolieren. Bei BTRFS-Subvolumes funktioniert das jedoch nicht.
- NFS-Freigaben auf Clients mit den Optionen "nosuid" und "nodev" mounten, um Rechteausweitung zu verhindern.
Fazit
Bei der Konfiguration des NFS-Servers unter Linux gibt es einige gängige Fehler, die es Angreifern ermöglichen, unbefugt auf Dateien zuzugreifen. Viele Probleme lassen sich leicht beheben. Nur in manchen Fällen ist ein größerer Aufwand erforderlich, etwa beim Aufteilen von Exporten auf unterschiedliche Dateisysteme für den Schutz vor unbefugten Zugriffen.
(dr)
Philipp Tekeser-Glasz ist Junior Cyber Security Consultant bei der HvS-Consulting GmbH.