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 — Proof-of-concept in C per CVE-2026-8933, un'escalation di privilegi locale in snap-confine che sfrutta il congelamento dei cgroup, race condition su symlink e iniezione di regole udev per eseguire comandi come root. | Kitploit
Strumenti/GitHubGitHub/yifengchen-cc/cve-2026-8933
Escalation di PrivilegiSicurezza dei ContenitoriAnalisi delle VulnerabilitàExploit
GitHubyifengchen-cc/cve-2026-8933

CVE-2026-8933

Proof-of-concept in C per CVE-2026-8933, un'escalation di privilegi locale in snap-confine che sfrutta il congelamento dei cgroup, race condition su symlink e iniezione di regole udev per eseguire comandi come root.

Vedi Repository
14 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 — snap-confine set-capabilities PoC di escalation locale dei privilegi

Riprodurre l'avviso di Qualys «Local Privilege Escalation in set-capabilities versions of snap-confine» (https://cdn2.qualys.com/advisory/2026/07/21/snap-confine-set-capabilities.txt).

Testato su questa macchina (Ubuntu 25.10 / snapd 2.73+ubuntu25.10.1 / kernel 6.17): partendo da uid 1000, infine systemd-udevd esegue il comando come root, /tmp/pwned ottiene uid=0(root) gid=0(root) groups=0(root), coerente con l'effetto dimostrato alla fine dell'avviso.

Le note sugli ostacoli incontrati durante la riproduzione, e perché la prima valutazione aveva erroneamente giudicato "non sfruttabile", sono in NOTES.md.

File

FileDescrizione
poc.cPoC completo (file singolo)
MakefileBuild (collega la libfuse3.so.3.17.4 già installata nel sistema)
include/Header di libfuse3 3.17.4 (corrispondenti alla libreria runtime di sistema)
NOTES.mdNote sugli ostacoli + revisione metodologica dell'analisi di raggiungibilità

Principio della vulnerabilità

cmd/snap-confine/mount-support.c (snapd 2.73):

sc_bootstrap_mount_namespace()      // 第 475 行起
  479:  mkdtemp("/tmp/snap.rootfs_XXXXXX")          <- 目录先归调用者所有
  491:  sc_do_mount(scratch, scratch, NULL, MS_BIND)
  498:  sc_do_mount("none", scratch, NULL, MS_UNBINDABLE)
  503:  sc_do_mount("none", scratch, "tmpfs", ...)
  504:  sc_replicate_base_rootfs(scratch, rootfs_dir, mounts)

sc_replicate_base_rootfs()
  330:  chown(scratch, 0, 0)
  418:  fd = open(full_path, O_CREAT | O_TRUNC, 0644)   <- 缺少 O_NOFOLLOW
  422:  fchown(fd, 0, 0)

I numeri di riga sono presi dal codice sorgente di snapd 2.73 presente su questa macchina (cmd/snap-confine/mount-support.c). L'avviso di Qualys fa riferimento alla propria copia del file, con i numeri di riga corrispondenti 511 / 523 / 530 / 535 / 536 / 362 / 450 / 454 — le istruzioni corrispondono una a una, solo i numeri di riga sono diversi.

Su questa macchina /usr/lib/snapd/snap-confine è mode=755 + file capabilities (non setuid-root), quindi viene eseguito con l'euid dell'attaccante ma possiede capacità quasi root: le directory e i file che crea appartengono all'attaccante per un breve periodo, e l'open() alla riga 418 segue i collegamenti simbolici.

Il disassemblaggio conferma: i flag di open@plt su questa macchina sono 0x240 (O_CREAT|O_TRUNC, senza O_NOFOLLOW); nello stesso punto della versione corretta 2.77.1 sono 0x20240.

I sei passi del PoC

  1. Inserire snap-confine nel proprio cgroup: systemd-run --user --scope --unit=snap.<snap>.<app>. Questo scope appartiene all'utente corrente, cgroup.freeze è scrivibile, quindi è possibile lasciar procedere snap-confine una system call alla volta.
  2. Congelare nel punto giusto: con SNAPD_DEBUG=1 snap-confine stampa associated snap application process ... with device cgroup. Questa riga compare dopo l'attach del programma BPF del cgroup dei dispositivi e prima di mkdtemp(). Non si può congelare prima: il verificatore BPF restituisce EAGAIN in presenza di un freeze trap, e snap-confine esce direttamente. stderr è collegato a un pty (non a una pipe): altrimenti stdio sarebbe bufferizzato a blocchi e il marker verrebbe spesso emesso solo dopo mkdtemp() e i bind mount. Inoltre lo scope viene avviato con CPUQuota=1%: dal marker a mkdtemp() ci sono solo poche centinaia di microsecondi di tempo CPU, dello stesso ordine di grandezza della latenza di risveglio del processo che effettua la cattura; la limitazione allunga questa finestra in tempo reale fino all'ordine dei millisecondi, e subito dopo la conferma del congelamento si ripristina cpu.max al 100%.
  3. Sostituire la directory scratch con un symlink che punta alla nostra directory: mount(2) segue i symlink nel percorso di destinazione, quindi il bind/unbindable/tmpfs di snap-confine finisce tutto su <scratch>.dA, mentre il ciclo di copia continua a usare la stringa della directory scratch.
  4. Dopo che il tmpfs è montato (ns_mount_count(sc, .dA) >= 2), far puntare di nuovo il symlink a <scratch>.dB, e inserire in dB symlink con lo stesso nome dei file regolari di primo livello del rootfs base, che puntano a /run/udev/rules.d/97-cve-2026-8933-<pid>-<rand>.rules. A questo punto la risoluzione del percorso del ciclo di copia ricade su dB — una directory normale che controlliamo completamente. Il tmpfs resta in dA e non ci ostacola più. Nota: quando su .dA c'è un solo mount si tratta di un bind mount (/tmp è già tmpfs, dopo il bind il fstype resta tmpfs), bisogna attendere il secondo mount (il vero tmpfs) prima di cambiare destinazione, altrimenti il mount --make-unbindable di snap-confine fallisce con EINVAL perché il percorso non è più la radice di un mount.
  5. Vincere la finestra tra open()/fchown(): il ciclo di copia esegue sul primo file regolare open(O_CREAT|O_TRUNC) (seguendo il symlink, creando il file come root sotto /run/udev/rules.d), e subito dopo fchown(fd,0,0). In questo istante il file appartiene ancora a noi. Il PoC usa contemporaneamente due mezzi:
    • percorso principale: continuare a usare il freezer lasciando procedere circa una system call alla volta; non appena stat() vede il file e l'uid è ancora il nostro, eseguire subito chmod 0666 + scrivere la regola udev (in quel momento snap-confine è congelato e la finestra viene "allargata");
    • rete di sicurezza: diversi processi spinner con un ciclo serrato di chmod() si contendono la stessa finestra. Quando lo spinner la conquista, il file è di proprietà di root ma con modo 0666 — i bit di modo restano dopo fchown(0,0), quindi anche il percorso principale riesce a completarne la scrittura (il codice verifica "se si può scrivere", non "se si è il proprietario").
  6. Attivare udev: il profilo AppArmor di snap-confine consente /run/udev/** rw. Montare/smontare un filesystem FUSE fa sì che il kernel emetta un uevent add per il sottosistema bdi, e systemd-udevd esegue quindi come root il PROGRAM= della regola.

Utilizzo

make
./poc --diagnose            # 只读自检,不改动任何系统状态
./poc                       #  exploit,默认最多 5 次尝试
./poc --attempts 8          # 增加尝试次数
./poc --file default256.png # 只用 base rootfs 里的这一个普通文件
sudo ./poc --cleanup        # 清理(仅在异常中断留下残留时需要)

Parametri:

ParametroDescrizione
--snap NAMEQuale rootfs dello snap usare (predefinito firefox, oppure la variabile d'ambiente CVE8933_SNAP)
--app NAMEL'app di quello snap (predefinito: il primo sotto apps: in meta/snap.yaml)
--file NAMEUsa solo questo singolo file regolare dal rootfs di base; esce con errore se non c'è corrispondenza
--attempts NNumero di tentativi (predefinito 5)
--step US / --step2 USTempo CPU per slice delle due fasi (microsecondi), per il debug
--keepConserva le directory <scratch>.dA / .dB e i symlink (per il debug)
--diagnoseAutodiagnostica in sola lettura
--cleanupPulisce i residui storici (richiede root)

I log vengono scritti in /tmp/cve8933.log, l'output di debug di snap-confine viene scritto in /tmp/cve8933-debug.txt.

CVE8933_PAYLOAD_CMD='<comando shell>' può sostituire il corpo del payload (per dimostrare l'esecuzione di altri comandi root), in questo caso non viene eseguita la pulizia automatica; il comando personalizzato deve comunque scrivere /tmp/pwned, altrimenti il PoC considererà il tentativo non riuscito.

Risultati dei test

$ ./poc
[+] WIN: uid=0(root) gid=0(root) groups=0(root)
[+] exploit succeeded, evidence in /tmp/pwned

/tmp/cve8933.log corrisponde a un processo riuscito (2026-10-23, retest dopo le modifiche):

Scarica lo strumento