Privileg Eskalation mit docker
Containerisierung wird immer häufiger eingesetzt, insbesondere im agilen Umfeld. Was jedoch oft vernachlässigt wird, ist die Absicherung der Container. Besonders bei der Konfiguration der Container bzw. der Benutzer, die Container ausführen dürfen, können viele Fehler gemacht werden.
Auch wenn ein Container eine gewisse Abstraktion vom Hostsystem darstellt, ist ein Ausbruch oder entsprechende Berechtigungserweiterung dennoch möglich. Besonders wenn auf einem Host mehrere Container oder Applikationen laufen, kann eine unzureichende Absicherung zu einem erheblichen Schaden führen.
In diesem Beitrag wollen wir uns daher anschauen, welche Methoden ein Angreifer anwenden kann, um seine Berechtigungen mithilfe von Docker Befehlen zu erweitern, um letztendlich Root-Berechtigungen auf dem Hostsystem zu erlangen, auch Privileg Eskalation (Englisch: privilege escalation) genannt.
Voraussetzungen
Bei den folgenden Beispielen wird angenommen, dass der Angreifer bereits unprivilegierten Zugriff auf das System hat. Der kompromittierte Benutzer hat dabei in unterschiedlichen Ausprägungen das Recht docker Container auf dem System zu starten.
Beispiel 1: Benutzer darf docker run ohne Einschränkungen ausführen
Um möglichst einfach erweiterte Berechtigungen auf dem Hostsystem zu erhalten, wird der folgende Befehl ausgeführt:
sudo docker run -it -v /:/host <image-name> /bin/sh
Für diesen Privilege Eskalation-Angriff muss der kompromittierte Benutzer die Berechtigung haben, den Befehl docker rununeingeschränkt ausführen zu dürfen. Der Befehl mountet das gesamte Filesystem des Host, unter dem Pfad /host im Container. Da der Standardbenutzer in einem Container root ist (was in diesem Fall angenommen wird), kann der Angreifer nun die /etc/shadow (/host/etc/shadow im Container) Datei auslesen oder die /etc/passwd (/host/etc/passwd im Container) Datei verändern und somit das root Passwort des Hostsystem manipulieren.
Mitigation
Um diese Methode der Privileg-Eskalation zu verhindern, müssen die Berechtigungen der Benutzer so gesetzt sein, dass es nicht möglich ist, einen Container zu starten, der frei wählbare Bind-Mounts hat. Da der docker run Befehl viele positionsunabhängige Parameter hat und viele Parameter sich mehrfach hinzufügen lassen, ist die einzig praktikable Möglichkeit, die Berechtigungen entsprechend einzuschränken, den kompletten Befehl (inklusive Image Bezeichnung) in die sudoers Datei wie folgt einzutragen:
alice ALL = /usr/bin/docker run -it -v /path/to/files/without/critical/data/:/host <image-name> *
Dies erlaubt es dem Benutzer alice den entsprechenden Container zu starten und beliebige Befehle im Container auszuführen, aber keine weiteren mounts hinzuzufügen oder andere Parameter zu verändern. Außerdem sollte alice nicht Mitglied der sudo, wheel oder docker Gruppe sein. Trotzdem lassen diese Einschränkungen noch viel Spielraum für Angreifer. Deshalb sollte darauf geachtet werden, dass das gemountete Verzeichnis nicht von alice geschrieben oder gelesen werden darf und dass das Verzeichnis nicht die Ausführung von Programmen erlaubt, mehr dazu im Beispiel 3. Am besten wäre es auf Bind-Mounts zu verzichten und die in docker implementierten volumes zu verwenden.
Beispiel 2: Ungepatchte docker Version wird verwendet
Eine weitere Möglichkeit zur Privileg-Eskalation verwendet den CVE-2019-5736. Der PoC ist bereits zwei Jahre alt, zeigt jedoch auch, dass Docker ohne offensichtliche Konfigurationsfehler, anfällig für Angriffe ist. Der PoC demonstriert, wie mithilfe von runC, die Binary /bin/sh des Hostsystems vom docker Container aus überschrieben wird, was einem Angreifer eine root-Shell auf dem Hostsystem ermöglicht.
Vorsicht beim Ausprobieren des PoC, da hierbei die runC Binary überschrieben wird, was zur Folge hat, dass keine Container mehr gestartet werden können.
Mitigation
Relativ einfach, haltet die Software aktuell.
Beispiel 3: Benutzer darf einen docker Container mit festgelegtem Verzeichnis starten
Bei der letzten Möglichkeit zur Privileg Eskalation sind die Berechtigungen des Benutzers etwas stärker eingeschränkt. Ein Admin hat eingestellt, dass der Benutzer nur Container mit einem festgelegten (unkritischen) Verzeichnis gemountet, starten kann. Es ist ihm ist also nicht mehr möglich wie in Beispiel 1 die /etc/passwd Datei oder ähnliche Dateien zu mounten und zu verändern. Leider hat der Admin vergessen, dass dieses Verzeichnis von jedem beschrieben werden darf und Berechtigungen zum Ausführen von Programmen besitzt.
Nun muss der Angreifer einfach die sh Binary in das gemountete Verzeichnis kopieren und mit dem root Benutzer des Containers den owner und das setuid bit setzen:
chown root:root /path/to/copied/bin/sh
chmod u+s /path/to/copied/bin/sh
Wird die Binary vom kompromittierten Benutzer auf dem Host System ausgeführt, öffnet sich eine Shell mit root Berechtigungen.
Mitigation
Um diesen Angriff zu verhindern, müssen wie im ersten Beispiel die Berechtigungen zum Starten der Container und die Berechtigungen der Bind-Mounts korrekt eingestellt werden (siehe Mitigation Beispiel 1).
Außerdem sollte es generell vermieden werden, dass root der Standardbenutzer im Container ist. Dafür muss im Dockerfile ein Benutzer erstellt und zu diesem gewechselt werden:
FROM ubuntu
useradd -r -u 999 -g appuser appuser
USER appuser
...
Oder man fügt die Option --user dem docker run Befehl in die sudoers Datei hinzu:
docker run -it --user nobody <image>
Zusammengefasst lässt sich sagen, dass nicht korrekt eingestellte Container und Mounts extrem gefährlich sind.
Docker Container Härtung
Einige Methoden zur Absicherung von Docker Containern wurden bereits besprochen, um jedoch einen besseren Überblick über die aktuelle Sicherheitslage der Container zu bekommen, gibt es geeignete Tools, die die Open-Source Community zur Verfügung stellt.
docker-bench-security
Zum einen wäre da das Projekt docker-bench-security. Mit der beiliegenden docker-compose Datei oder den in der Dokumentation beschriebenen docker run Befehl wird ein zusätzlicher Container gestartet. Dieser Container führt dann automatisch mehrere Shell-Skripte aus, die auf verschiedene Schwachstellen prüfen und dem Benutzer einen ausführlichen Report zum Zustand der Container bereitstellt. Die Shell-Skripte basieren hierbei auf dem CIS Docker Benchmark v1.2.0.
linPEAS
Zum anderen gibt es PEASS oder genau genommen linPEAS, da die meisten vermutlich einen Docker Host auf einem Linux System verwenden. PEASS ist eine Suite an Shell-Skripten (und für Windows auch normale Binarys), die das Hostsystem unter anderem auf Fehlkonfigurationen, veraltete Software und Dateien mit wertvollem Inhalt durchsucht. PEASS ist dabei nicht nur auf Docker spezialisiert, sondern analysiert das gesamte Hostsystem, um unter anderen potenzielle Schwachstellen zur Privileg-Eskalation zu identifizieren. Das Resultat ist wieder ein ausführlicher Report zum Status des Systems.
Rootless mode
Seit Version 19.03 gibt es die Möglichkeit, den docker deamon auch als unprivilegierter Benutzer auszuführen. Das Ganze nennt sich Rootless mode, mehr dazu hier.
Mit dem Rootless mode können Benutzer selbst einen docker deamon starten, der mit den Berechtigungen des Benutzers läuft. Auch wenn der Benutzer im Container root Berechtigungen hat und vorher das ganze Filesystem in den Container gemountet wurde (siehe Beispiel 1), kann er trotzdem nicht auf Dateien zugreifen, auf die der Benutzer des Hostsystem keinen Zugriff hat.
Seit Version 20.10 ist dieses Feature nicht mehr experimental und kann somit in Produktivsystemen eingesetzt werden.
Damit werden eine ganze Liste an Sicherheitsrisiken gelöst, da der docker deamon nicht mehr mit root Berechtigungen ausgeführt wird und somit die docker Befehle auch nicht mehr über die sudoers Datei verwaltet werden müssen.
Fazit
Docker erleichtert tagtäglich vielen Admins und Developern den Alltag und ist aus dem CI/CD-Umfeld nicht mehr wegzudenken. Doch wie bei anderer Software wird der Security Aspekt oft vernachlässigt. Diese einfach ausführbaren Angriffe sollen natürlich nur der Veranschaulichung dienen und zeigen, wie Angreifer Docker nutzen könnten, um ihre Berechtigungen auf dem System zu erweitern.
Die meisten Angriffsvektoren resultieren, wie bei vielen anderen Schwachstellen auch, aus einer fehlerhaften Konfiguration, aber durch den durch Einsatz vom Rootless mode lassen sich viele dieser Methoden zur Privilege Eskalation verhindern.