
CHARON — pre-built PoC for CVE-2026-46333 (Linux ptrace mm==NULL fd theft)
____ _ _ _ ____ ___ _ _
/ ___|| | | | / \ | _ \ / _ \| \ | |
| | | |_| | / _ \ | |_) | | | | \| |
| |___ | _ |/ ___ \| _ <| |_| | |\ |
\____||_| |_/_/ \_\_| \_\\___/|_| \_|
transporta fds a través del Styx exit-mm()
CVE-2026-46333 / Linux <= 6.12.89
"Es algo temible caer en las manos del Dios vivo." — Hebreos 10:31
Un PoC ajustado, sin dependencias para CVE-2026-46333: la
evasión __ptrace_may_access mm==NULL revelada por Qualys el
2026-05-15. Charon compite pidfd_getfd(2) contra un proceso SUID-root
moribundo para levantar su descriptor de archivo abierto /etc/shadow a
través de la breve ventana mm=NULL en do_exit(). Ejecútelo como un usuario
no privilegiado en un sistema afectado; vuelca /etc/shadow a 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:::
...
Tasa de acierto típica: menos de un segundo en una VM de 4 núcleos, ~137 intentos en la prueba de humo.
__ptrace_may_access() evita su comprobación de volcabilidad cuando
task->mm == NULL. La ruta rápida fue escrita para hilos del kernel
(swapper y otros), que legítimamente no tienen mm y nunca deberían
ser rastreados. Pero do_exit() ejecuta exit_mm() antes de
exit_files(), lo que significa que un proceso SUID de espacio de
usuario tiene brevemente:
task->mm == NULL (mm recolectada) → comprobación de volcabilidad omitidasetreuid() → comprobación de acceso pasapidfd_getfd(2) confía en esa comprobación de acceso y entrega al
atacante los descriptores de archivo abiertos del proceso SUID.
do_exit()
├── exit_mm() ← task->mm = NULL
├── ... ← __ptrace_may_access() ahora miente
└── exit_files() ← tabla fd recolectada
Jann Horn señaló la forma de robo de FD en lore.kernel.org en octubre de 2020. La corrección estuvo en revisión de mantenedores durante ~6 años antes de que Qualys la trajera de vuelta al frente de la cola.
Corrección ascendente: 31e62c2ebbfd
(Linus 2026-05-14). Al 2026-05-15 el backport no ha llegado a
linux-6.12.y o linux-6.6.y estable.
| Rama estable | Estado |
|---|---|
| linux-6.12.y (≤ 6.12.89) | ❌ vulnerable |
| linux-6.6.y (pre-fix backport) | ❌ vulnerable |
| mainline ≥ 6.15-rc1 | ✅ parcheado (31e62c2ebbfd) |
La tabla de PR/estado actualizado se actualizará a medida que lleguen los backports.
# Binario estático pequeño de 38 KB (recomendado)
sudo apt-get install musl-tools
make static
# O simplemente la compilación glibc estándar
make
Salida: un único ELF ./charon.
./charon # vuelca /etc/shadow (predeterminado)
./charon -q # sin banner / progreso, solo shadow en stdout
./charon -v # muestra estadísticas por intento + finales
./charon -r 5000 # más paciencia para sistemas lentos
./charon -t /etc/ssh/ssh_host_ecdsa_key # objetivo diferente (usa cebo ssh-keysign)
./charon -a # auto-descubrir cebos SUID/SGID si los integrados fallan
./charon -L # lista cebos candidatos sin intentar ninguno
./charon --help
--auto recorre /usr/bin, /usr/sbin, /usr/local/{bin,sbin},
/usr/lib/openssh, /usr/libexec, /bin, /sbin, encuentra cada
archivo regular SUID/SGID (excluyendo cebos interactivos como su,
sudo, newgrp, pkexec), y prueba cada uno como cebo contra el
objetivo solicitado. El presupuesto por cebo es ajustado (5 rondas ×
2000 internas) por lo que un escaneo completo termina en ~10 segundos
incluso cuando no hay coincidencia.
--list-baits es la versión de solo lectura — enumera los mismos
candidatos sin disparar el exploit. Útil para inspeccionar qué distros
incluyen qué cebos.
| Código | Significado |
|---|
Charon incluye cuatro cebos SUID conocidos:
Agregar un cebo es una edición de 3 líneas en el arreglo lures[] en charon.c.
31e62c2ebbfd directamente.pidfd_getfd(2) mediante seccomp en hosts de producción.chage y passwd si no necesita que usuarios no privilegiados consulten el envejecimiento de contraseñas.no_new_privs en el host bloquea la primitiva por completo — cada "SUID" dentro del contenedor se vuelve inerte, dejando a Charon sin presa.La VM del desafío Google kernelctf VRP ejecuta la bash del jugador
dentro de un sandbox nsjail con clone_newuser:true (uid 0 sin
mapear), chroot:/chroot, y no_new_privs:1. Bajo no_new_privs el
bit setuid es inerte, por lo que no hay presas SUID reales dentro del
sandbox, y /flag vive en el host fuera del chroot. Por lo tanto,
Charon no puede ganar kCTF VRP. Sigue siendo un LPE legítimo de Linux
en instalaciones bare-metal de la familia Debian / Ubuntu / RHEL.
Solo para uso educativo y defensivo autorizado.
⛵ STYX ⛵
╔══════════════════════════════╗
║ do_exit(): ║
║ ├── exit_mm() ← task->mm ║
║ │ = NULL ║
║ ├── ... ← ferry ║
║ └── exit_files() ║
╚══════════════════════════════╝
| Distro | Kernel | Estado (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 | ⚠️ verificar |
| Fedora 44 | 7.0.4-200 | ⚠️ verificar |
| 0 | Éxito — contenido del archivo en stdout |
| 1 | Ningún cebo SUID en este sistema abre el archivo solicitado |
| 2 | El kernel parece parcheado (CVE-2026-46333 cerrado) |
| 3 | Se agotaron las rondas sin éxito (raro; intente -r 5000) |
| 4 | Error de CLI / IO |
| Binario | Archivo que abre | Cobertura de distro |
|---|
/usr/bin/chage (chage -l <user>) | /etc/shadow | La mayoría de Debian, Ubuntu, Fedora |
/usr/sbin/chage | /etc/shadow | Familia RHEL / Rocky / Alma |
/usr/bin/passwd (passwd -S <user>) | /etc/shadow | La mayoría de distros |
/usr/lib/openssh/ssh-keysign | /etc/ssh/ssh_host_*_key | Distros con HostbasedAuthentication habilitado |