
Ist dein Linux-Host CVE-2026-98432 ausgesetzt?
Prüft, ob ein Linux-Host CVE-2026-98432 ausgesetzt sein könnte, dem Use-after-free im IPv4-TCP-Handshake des Kernels. Teil von shouldipanic.ch.
Ein SYN mit IPv4-Optionen (Record Route, Timestamp) erreicht Code, der die Optionen liest, nachdem sie möglicherweise bereits freigegeben wurden. Ein beliebiger offener IPv4-TCP-Port genügt, keine Anmeldung erforderlich. Es steckt in jedem Kernel seit 4.4 (2016) bis zur korrigierten Version jedes Zweigs: 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56, 7.2.10, 7.3. Die Kernel-CNA bewertet es mit 9.8; ein funktionierender Remote-Root-Exploit gegen Server mit MPTCP-Listenern wurde gemeldet (nicht veröffentlicht). Der Fix ist im Netzverkehr unsichtbar: ein korrigierter Kernel antwortet exakt wie ein ungepatchter.
Das bestimmt, was die einzelnen Modi aussagen können:
--on-host liest den laufenden Kernel auf der Maschine selbst: seine Version,
das Paket-Changelog und ob ein neuerer Kernel auf einen Neustart wartet.Server-Header und zeigt an, ob diese Distribution
bereits einen korrigierten Kernel veröffentlicht hat. Das ist ein starker Hinweis, kein Urteil: hinter einem
Reverse-Proxy oder in einem Container gehört der Kernel zu einer anderen Maschine.kernel98scan gibt es in zwei Formen:
kernel98scan.py: eine einzelne Python-Datei ohne Abhängigkeiten. Auf einem Host
liefert --on-host das tatsächliche Urteil; auf Adressen gerichtet betreibt es Distribution-
Fingerprinting über IP-Bereiche, mit Portscan und vhost-Erkennung.
curl -LO https://github.com/akaihigurashi/kernel98scan/releases/latest/download/kernel98scan.py
python3 kernel98scan.py --on-host # real verdict for THIS machine
Python 3.8 oder neuer, nichts zu installieren. Beispiele:
python3 kernel98scan.py --on-host # read the running kernel
python3 kernel98scan.py 203.0.113.10 # outside: distribution + fix status
python3 kernel98scan.py 203.0.113.0/24 # a whole range from outside
python3 kernel98scan.py 203.0.113.10 --ip-options # + do IP-options packets get through?
python3 kernel98scan.py 203.0.113.10 -o out.csv # CSV output
python3 kernel98scan.py -h # all options
Auf dem Host (--on-host, Exit-Code 2 / 1 / 0 / 3):
| Status | Bedeutung |
|---|---|
VULNERABLE | Nichts deutet im laufenden Kernel auf den Fix hin |
CHECK | Ein gepatchter Kernel ist installiert, aber der alte läuft noch: Neustart erforderlich |
FIXED | Das Kernel-Changelog nennt die CVE, oder ein unveränderter Upstream-Kernel hat die gepatchte Version |
Hersteller-Kernel (Ubuntu, RHEL, Proxmox) backporten Fixes auf alte Versionsnummern, daher zählt bei ihnen nur das Changelog. Es zeigt außerdem, ob MPTCP aktiv ist (der gemeldete Exploit läuft über MPTCP-Listener) und tcp_migrate_req.
Von außen:
| Status | Bedeutung |
|---|---|
POSSIBLY VULNERABLE | Das Banner zeigt eine Linux-Distribution: Entweder gibt es noch keinen gepatchten Kernel (Ubuntu, RHEL und Rebuilds derzeit) oder es gibt einen, der installiert und gebootet werden muss |
UNKNOWN | Die Distribution ist nicht sichtbar, oder ein Proxy/CDN antwortet |
NOT LINUX | Der Server-Header deutet auf einen Nicht-Linux-Host hin |
VULNERABLE und PATCHED werden niemals von außen gemeldet. Der Fix-Status pro Distribution ist eine Tabelle in check.py (FIX_STATUS, FIXED_TABLE), die mit jedem Hersteller-Release aktualisiert wird.
| Option | Was sie bewirkt |
|---|---|
--on-host | Liest den laufenden Kernel auf dieser Maschine und liefert ein echtes Urteil |
--ip-options | Eine Verbindung, deren SYN eine Record-Route-IP-Option trägt (siehe unten) |
-o FILE | Schreibt alle Ergebnisse zusätzlich in eine CSV-Datei |
-a / -v | Verborgene Ergebnisse anzeigen / die Belege anzeigen |
-d | Debug: jede Anfrage, jeder Header und jeder Treffer |
-q | Kein Banner (für Skripte) |
-V | Gibt die Version aus |
-h | Alle Optionen |
--ip-options (Opt-in, nur über die Kommandozeile)Öffnet eine normale Verbindung und eine, deren SYN eine leere Record-Route-IP-Option trägt, und meldet, ob solche Pakete den Host erreichen (reach), unterwegs verworfen werden (filtered) oder der Port geschlossen ist (noport). Das ist die Paketform, über die der Bug erreicht wird, daher ist sie standardmäßig deaktiviert und läuft nie auf der Webseite: Verwende sie auf deinen eigenen Hosts, zum Beispiel um zu bestätigen, dass deine Firewall IP-Optionen verwirft. Ein einzelner Verbindungsaufbau kann das Rennen, das der Bug erfordert, nicht gewinnen, und ein filtered-Ergebnis kann von jedem Netzwerk dazwischen stammen.
nft add table ip cve98432
nft add chain ip cve98432 pre '{ type filter hook prerouting priority -300; }'
nft add rule ip cve98432 pre meta l4proto tcp ip hdrlength != 5 drop
sysctl -w net.mptcp.enabled=0 # if you don't need MPTCP
Verwirft IPv4-TCP-Pakete, die beliebige IP-Optionen enthalten. Nicht persistent über Neustarts hinweg und kein Ersatz für den gepatchten Kernel.
docker run -d --name kernel98scan --restart unless-stopped \
-p 127.0.0.1:8092:8092 \
-e PANIC_ORIGIN=https://kernel98scan.example.ch \
-v kernel98scan-data:/data \
ghcr.io/akaihigurashi/kernel98scan:latest
Oder mit Compose: Lade docker-compose.yml herunter, setze
PANIC_ORIGIN und führe dann docker compose up -d aus. Der Container lauscht nur auf localhost;
setze einen Reverse-Proxy mit TLS davor
(nginx-Beispiel).
| Variable | Standard | Zweck |
|---|---|---|
PANIC_ORIGIN | – | Öffentliche Adresse. Anfragen von anderen Ursprüngen werden abgelehnt. Setze sie. |
PANIC_OPERATOR / PANIC_CONTACT | – | Optionaler Kontaktbereich am unteren Ende der Seite |
PANIC_IMPRINT_URL | – | Optionaler Link zu einem bestehenden Impressum |
PANIC_TRUSTED_PROXY | 127.0.0.1,::1 | Proxies, deren X-Real-IP-Header vertraut wird |
PANIC_DENY_HOSTS / PANIC_DENY_IPS | – | Diese Domains / Adressen niemals prüfen |
PANIC_AUDIT_DIR | /data/audit | Tägliche Audit-Logdateien |
PANIC_RETENTION_DAYS | 30 | Ältere Audit-Dateien werden gelöscht |