
CHARON — pre-built PoC for CVE-2026-46333 (Linux ptrace mm==NULL fd theft)
____ _ _ _ ____ ___ _ _
/ ___|| | | | / \ | _ \ / _ \| \ | |
| | | |_| | / _ \ | |_) | | | | \| |
| |___ | _ |/ ___ \| _ <| |_| | |\ |
\____||_| |_/_/ \_\_| \_\\___/|_| \_|
ferries fds across the exit-mm() Styx
CVE-2026-46333 / Linux <= 6.12.89
„Es ist schrecklich, in die Hände des lebendigen Gottes zu fallen." — Hebräer 10:31
Ein kompaktes, abhängigkeitsfreies PoC für CVE-2026-46333: den von Qualys am 15.05.2026 offengelegten __ptrace_may_access-mm==NULL-Bypass. Charon lässt pidfd_getfd(2) gegen einen sterbenden SUID-Root-Prozess antreten, um dessen offenen /etc/shadow-Dateideskriptor durch das kurze mm-NULL-Fenster in do_exit() abzugreifen. Führen Sie es als unprivilegierter Benutzer auf einem betroffenen System aus; es gibt /etc/shadow auf stdout aus.
$ ./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:::
...
Typische Trefferquote: unter einer Sekunde auf einer 4-Kern-VM, ~137 Versuche im Smoke-Test.
__ptrace_may_access() überspringt seine Dumpability-Prüfung, wenn task->mm == NULL ist. Der Fast-Path wurde für Kernel-Threads (swapper et al.) geschrieben, die legitimerweise kein mm haben und niemals ptraced werden sollten. Aber do_exit() führt exit_mm() vor exit_files() aus, was bedeutet, dass ein Userspace-SUID-Prozess kurzzeitig Folgendes aufweist:
task->mm == NULL (mm abgeräumt) → Dumpability-Prüfung übersprungensetreuid() → Zugriffsprüfung bestehtpidfd_getfd(2) vertraut dieser Zugriffsprüfung und übergibt dem Angreifer die offenen Dateideskriptoren des SUID-Prozesses.
do_exit()
├── exit_mm() ← task->mm = NULL
├── ... ← __ptrace_may_access() now lies
└── exit_files() ← fd table reaped
Jann Horn meldete die FD-Diebstahl-Variante im Oktober 2020 auf lore.kernel.org. Der Fix lag ~6 Jahre in der Maintainer-Review, bevor Qualys ihn wieder an die Spitze der Warteschlange brachte.
Upstream-Fix: 31e62c2ebbfd (Linus 14.05.2026). Stand 15.05.2026 ist der Backport noch nicht in linux-6.12.y oder linux-6.6.y stable gelandet.
| Stable-Baum | Status |
|---|---|
| linux-6.12.y (≤ 6.12.89) | ❌ verwundbar |
| linux-6.6.y (ohne Fix-Backport) | ❌ verwundbar |
| mainline ≥ 6.15-rc1 | ✅ gepatcht (31e62c2ebbfd) |
Die PR-/Rolling-Status-Tabelle wird aktualisiert, sobald Backports landen.
# Tiny 38 KB static binary (recommended)
sudo apt-get install musl-tools
make static
# Or just the standard glibc build
make
Ausgabe: ein einzelnes ELF-Binary ./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 durchläuft /usr/bin, /usr/sbin, /usr/local/{bin,sbin}, /usr/lib/openssh, /usr/libexec, /bin, /sbin, findet jede SUID/SGID-Regulärdatei (ausgenommen interaktive Köder wie su, sudo, newgrp, pkexec) und probiert jede als Köder gegen das angeforderte Ziel aus. Das Pro-Köder-Budget ist knapp bemessen (5 Runden × 2000 innere Iterationen), sodass ein vollständiger Scan in ~10 Sekunden abgeschlossen ist, selbst wenn nichts matcht.
--list-baits ist die Read-only-Version — sie listet dieselben Kandidaten auf, ohne den Exploit auszulösen. Nützlich, um zu überblicken, welche Distributionen welche Köder mitbringen.
| Code | Bedeutung |
|---|
Charon wird mit vier bekannten SUID-Ködern ausgeliefert:
Einen Köder hinzuzufügen ist eine 3-Zeilen-Änderung am lures[]-Array in charon.c.
31e62c2ebbfd direkt anwenden.pidfd_getfd(2) per seccomp auf Produktionshosts deaktivieren.chage und passwd entfernen, wenn unprivilegierte Benutzer keine Passwort-Aging-Abfragen benötigen.no_new_privs auf dem Host die Primitive vollständig — jedes „SUID“ im Container wird inert, sodass Charon ohne Beute dasteht.Die Google-kernelctf-VRP-Challenge-VM führt die Bash des Spielers in einer nsjail-Sandbox mit clone_newuser:true (uid 0 ungemappt), chroot:/chroot und no_new_privs:1 aus. Unter no_new_privs ist das Setuid-Bit inert, es gibt also keine echte SUID-Beute in der Sandbox, und /flag befindet sich auf dem Host außerhalb des Chroots. Charon kann daher kein kCTF-VRP gewinnen. Es bleibt ein legitimer Linux-LPE auf Bare-Metal-Installationen der Debian-/Ubuntu-/RHEL-Familie.
Nur für Bildungszwecke und autorisierte defensive Nutzung.
⛵ STYX ⛵
╔══════════════════════════════╗
║ do_exit(): ║
║ ├── exit_mm() ← task->mm ║
║ │ = NULL ║
║ ├── ... ← ferry ║
║ └── exit_files() ║
╚══════════════════════════════╝
| Distribution | Kernel | Status (15.05.2026) |
|---|
| Debian trixie | 6.12.86+deb13 | ❌ |
| AlmaLinux 10.1 | 6.12.0-124.55.3 | ❌ |
| Ubuntu 26.04 | 7.0.0-15 | ⚠️ prüfen |
| Fedora 44 | 7.0.4-200 | ⚠️ prüfen |
| 0 | Erfolg — Dateiinhalt auf stdout |
| 1 | Kein SUID-Köder auf diesem System öffnet die angeforderte Datei |
| 2 | Kernel scheint gepatcht (CVE-2026-46333 geschlossen) |
| 3 | Alle Runden ohne Treffer aufgebraucht (selten; -r 5000 versuchen) |
| 4 | CLI-/IO-Fehler |
| Binary | Geöffnete Datei | Distributionsabdeckung |
|---|
/usr/bin/chage (chage -l <user>) | /etc/shadow | Die meisten Debian-, Ubuntu- und Fedora-Systeme |
/usr/sbin/chage | /etc/shadow | RHEL-/Rocky-/Alma-Familie |
/usr/bin/passwd (passwd -S <user>) | /etc/shadow | Die meisten Distributionen |
/usr/lib/openssh/ssh-keysign | /etc/ssh/ssh_host_*_key | Distributionen mit aktiviertem HostbasedAuthentication |