
CHARON — pre-built PoC for CVE-2026-46333 (Linux ptrace mm==NULL fd theft)
/ || | | | / \ | _ \ / _ | \ | | | | | || | / _ \ | |) | | | | | | | | | _ |/ ___ | _ <| || | |\ | _||| |// __| _\/|_| _|
traghetta i fd attraverso la Stige di exit-mm() CVE-2026-46333 / Linux <= 6.12.89
"È cosa terribile cadere nelle mani del Dio vivente." — Ebrei 10:31
Un PoC compatto e senza dipendenze per CVE-2026-46333: il
bypass mm==NULL di __ptrace_may_access divulgato da Qualys il
15 maggio 2026. Charon mette in gara pidfd_getfd(2) contro un processo
SUID-root morente per sottrarre il descrittore di file aperto di
/etc/shadow attraverso la breve finestra mm-NULL in do_exit(). Eseguilo come un utente non privilegiato
su una macchina vulnerabile; scrive /etc/shadow su stdout.
$ ./charon
[banner on stderr]
[*] lure /usr/bin/chage target /etc/shadow
root:$y$j9T$ztS5H...$hz9W87TlqxEW...:...
daemon:*:20582:0:99999:7:::
bin:*:20582:0:99999:7:::
...
Tasso di successo tipico: meno di un secondo su una VM a 4 core, ~137 tentativi nello smoke test.
__ptrace_may_access() cortocircuita il controllo di dumpability quando
task->mm == NULL. Il percorso veloce è stato scritto per i thread del kernel
(swapper e altri), che legittimamente non hanno mm e non dovrebbero mai essere
sottoposti a ptrace. Ma do_exit() esegue exit_mm() prima di exit_files(),
il che significa che un processo SUID nello spazio utente ha brevemente:
task->mm == NULL (mm rilasciato) → controllo di dumpability saltatosetreuid() → il controllo di accesso passapidfd_getfd(2) si fida di quel controllo di accesso e consegna all'attaccante i
descrittori di file aperti del processo SUID.
do_exit()
├── exit_mm() ← task->mm = NULL
├── ... ← __ptrace_may_access() now lies
└── exit_files() ← fd table reaped
Jann Horn segnalò la forma di furto di FD su lore.kernel.org nell'ottobre 2020. La correzione è rimasta in revisione tra i maintainer per ~6 anni prima che Qualys la riportasse in cima alla coda.
Fix upstream: 31e62c2ebbfd
(Linus 14 maggio 2026). Al 15 maggio 2026 il backport non è ancora arrivato
nei rami stabili linux-6.12.y o linux-6.6.y.
| Ramo stabile | Stato |
|---|---|
| linux-6.12.y (≤ 6.12.89) | ❌ vulnerabile |
| linux-6.6.y (in attesa del backport) | ❌ vulnerabile |
| mainline ≥ 6.15-rc1 | ✅ corretto (31e62c2ebbfd) |
La tabella con lo stato di PR e rami rolling verrà aggiornata man mano che i backport arriveranno.
# Tiny 38 KB static binary (recommended)
sudo apt-get install musl-tools
make static
# Or just the standard glibc build
make
Output: un singolo ELF ./charon.
./charon # dump /etc/shadow (default)
./charon -q # no banner / progress, just shadow on stdout
./charon -v # show per-hit + final stats
./charon -r 5000 # more patience for slow systems
./charon -t /etc/ssh/ssh_host_ecdsa_key # different target (uses ssh-keysign bait)
./charon -a # auto-discover SUID/SGID baits if built-ins miss
./charon -L # list candidate baits without trying any
./charon --help
--auto esamina /usr/bin, /usr/sbin, /usr/local/{bin,sbin},
/usr/lib/openssh, /usr/libexec, /bin, /sbin, trova ogni
file regolare SUID/SGID (escludendo le esche interattive come su,
sudo, newgrp, pkexec) e prova ciascuno come esca contro il
target richiesto. Il budget per esca è stretto (5 round × 2000 iterazioni interne)
quindi una scansione completa termina in ~10 secondi anche quando non c'è alcuna corrispondenza.
--list-baits è la versione sola lettura — enumera gli stessi
candidati senza attivare l'exploit. Utile per capire quali
distro includono quali esche.
| Codice | Significato |
|---|
Charon include quattro esche SUID note:
Aggiungere un'esca è una modifica di 3 righe all'array lures[] in charon.c.
31e62c2ebbfd direttamente.pidfd_getfd(2) via seccomp sugli host di produzione.chage e passwd se non hai bisogno che
utenti non privilegiati interroghino l'invecchiamento delle password.no_new_privs sull'host
blocca completamente la primitiva — ogni "SUID" all'interno del container
diventa inerte, lasciando Charon senza prede.La VM della sfida VRP di Google kernelctf esegue la bash del giocatore
all'interno di un sandbox nsjail con clone_newuser:true (uid 0 non
mappato), chroot:/chroot e no_new_privs:1. Con no_new_privs il
bit setuid è inerte, quindi non ci sono vere prede SUID all'interno del
sandbox, e /flag si trova sull'host al di fuori della chroot. Charon
quindi non può vincere il kCTF VRP. Rimane comunque una legittima LPE Linux
su installazioni bare-metal della famiglia Debian / Ubuntu / RHEL.
Solo uso educativo e difensivo autorizzato.
⛵ STYX ⛵
╔══════════════════════════════╗
║ do_exit(): ║
║ ├── exit_mm() ← task->mm ║
║ │ = NULL ║
║ ├── ... ← ferry ║
║ └── exit_files() ║
╚══════════════════════════════╝
| Distro | Kernel | Stato (2026-05-15) |
|---|
| Debian trixie | 6.12.86+deb13 | ❌ |
| AlmaLinux 10.1 | 6.12.0-124.55.3 | ❌ |
| Ubuntu 26.04 | 7.0.0-15 | ⚠️ verificare |
| Fedora 44 | 7.0.4-200 | ⚠️ verificare |
| 0 | Successo — contenuto del file su stdout |
| 1 | Nessuna esca SUID su questo sistema apre il file richiesto |
| 2 | Il kernel appare corretto (CVE-2026-46333 chiusa) |
| 3 | Round esauriti senza successo (raro; prova -r 5000) |
| 4 | Errore CLI / IO |
| Binario | File che apre | Copertura distro |
|---|
/usr/bin/chage (chage -l <user>) | /etc/shadow | La maggior parte di Debian, Ubuntu, Fedora |
/usr/sbin/chage | /etc/shadow | Famiglia RHEL / Rocky / Alma |
/usr/bin/passwd (passwd -S <user>) | /etc/shadow | La maggior parte delle distro |
/usr/lib/openssh/ssh-keysign | /etc/ssh/ssh_host_*_key | Distro con HostbasedAuthentication abilitato |