
Ausnutzbarkeits-PoC für CVE-2026-43512 (Apache Tomcat Digest-Authentifizierungs-Bypass)
Ergebnis der Exploitability-Analyse: Die Ursache wurde bestätigt. Eine End-to-End-Ausnutzung ist nicht reproduzierbar gegen eine standardmäßige
UserDatabaseRealm-Bereitstellung. Siehe Analyse für Details.
CVE-2026-43512 ist eine Schwachstelle im HTTP-DIGEST-Authentifizierungsmechanismus von Apache Tomcat. Die Methode RealmBase.getDigest() validiert den Rückgabewert von getPassword(username) nicht, bevor sie den A1-Hash-Eingabe konstruiert. Wenn ein Benutzername in der konfigurierten Realm nicht existiert, gibt zurück, was der Java-String-Konkatenationsoperator stillschweigend in das vier Zeichen lange Literal umwandelt.
getPassword()null"null"Der Server berechnet daher:
A1 = MD5("<username>:<realm>:null")
Ein Client, der eine DIGEST-Antwort übermittelt, die mit dem Literal "null" als Passwort berechnet wurde, erzeugt einen identischen Hash. Laut dem Advisory stellt dies eine Authentifizierungsumgehung dar.
Dieses Repository enthält eine minimale reproduzierbare Umgebung und einen auf Go basierenden Proof of Concept, um diese Behauptung gegen eine echte Tomcat-Instanz zu überprüfen.
| Betroffener Bereich | Behoben in |
|---|---|
| 7.0.0 – 7.0.109 | 7.0.110 |
| 8.5.0 – 8.5.100 | 8.5.101 |
| 9.0.0.M1 – 9.0.117 | 9.0.118 |
| 10.1.0.M1 – 10.1.54 | 10.1.55 |
| 11.0.0.M1 – 11.0.21 | 11.0.22 |
Der anfällige Codepfad in RealmBase.java (alle betroffenen Branches):
// RealmBase.java — vulnerable
protected String getDigest(String username, String realmName, String algorithm) {
if (hasMessageDigest(algorithm)) {
return getPassword(username); // returns null for unknown users
}
// null is concatenated as the literal "null" by Java
String a1 = username + ":" + realmName + ":" + getPassword(username);
return HexUtils.toHexString(
ConcurrentMessageDigest.digest(algorithm, a1.getBytes(...))
);
}
Der Fix (Commit 6565a6c fügt eine explizite Null-Überprüfung hinzu:
// RealmBase.java — patched
protected String getDigest(String username, String realmName, String algorithm) {
String password = getPassword(username);
if (password == null) {
return null;
}
...
}
Das Ausführen des PoC gegen Tomcat 11.0.0-M1 mit aktiviertem FINE-Logging zeigt Folgendes:
Digest: 2388e2c78407def640f37f092a8d3a84 ← client
Server digest: 2388e2c78407def640f37f092a8d3a84 ← server
Failed to authenticate user [ghost]
Die Digest-Hashes stimmen überein. Der Fehler in getDigest() ist real und bestätigt. Allerdings schlägt die Authentifizierung dennoch fehl, weil RealmBase.authenticate() eine zweite, unabhängige Prüfung durchführt:
// RealmBase.authenticate()
if (serverDigest.equals(clientDigest)) {
return getPrincipal(username); // returns null for non-existent users
}
return null;
In einer standardmäßigen UserDatabaseRealm, die auf tomcat-users.xml basiert, führt getPrincipal() eine Suche in der In-Memory-Benutzerdatenbank durch. Für einen Benutzernamen, der in dieser Datenbank nicht existiert, gibt es null zurück. Der Aufrufer behandelt einen null-Principal als Authentifizierungsfehler und sendet einen 401.
cve-2026-43512-poc/
├── Dockerfile # Tomcat 11.0.0-M1 (betroffene Version)
├── tomcat-users.xml # Minimale Realm-Konfiguration – kein Benutzer "ghost"
├── web.xml
├── exploit/
│ ├── exploit.go # PoC – Go, nur stdlib
│ └── go.mod
└── README.md
| Tool | Version | Hinweise |
|---|---|---|
| Podman | ≥ 4.0 | Docker funktioniert auch |
| Go | ≥ 1.22 | Nur zum lokalen Ausführen des Exploits |
podman build -t tomcat-cve-2026-43512 .
podman run -d --name tomcat-vuln -p 8080:8080 tomcat-cve-2026-43512
Einige Sekunden warten, bis Tomcat vollständig gestartet ist, dann überprüfen, ob es läuft:
curl -si http://localhost:8080/protected/secret.html | head -1
# Erwartet: HTTP/1.1 401
cd exploit
go run exploit.go \
-target http://localhost:8080 \
-path /protected/secret.html \
-username ghost
Verfügbare Flags:
| Flag | Standard | Beschreibung |
|---|---|---|
-target | http://localhost:8080 | Tomcat-Basis-URL |
-path | /protected/ | Pfad der geschützten Ressource |
-username | ghost | Zu verwendender Benutzername – darf nicht in tomcat-users.xml existieren |
Um den internen Authentifizierungsstatus zu beobachten, eine logging.properties-Datei hinzufügen und einbinden:
org.apache.catalina.authenticator.level = FINE
org.apache.catalina.realm.level = FINE
podman run -d --name tomcat-vuln -p 8080:8080 \
-v ./logging.properties:/usr/local/tomcat/conf/logging.properties:ro \
tomcat-cve-2026-43512
Das Log zeigt direkt das Ergebnis des Digest-Vergleichs und bestätigt, ob die Hashes übereinstimmen.
podman stop tomcat-vuln && podman rm tomcat-vuln
============================================================
CVE-2026-43512 — Tomcat DIGEST Auth Bypass PoC
============================================================
Target : http://localhost:8080/protected/secret.html
Username : "ghost" (must NOT exist in tomcat-users.xml)
Password : "null" (literal string)
------------------------------------------------------------
[1] Sending unauthenticated request to obtain DIGEST challenge...
[+] HTTP 401 received — DIGEST challenge:
Digest realm="UserDatabase", qop="auth", nonce="...", opaque="..."
[*] realm="UserDatabase" nonce="..." qop="auth" algorithm="MD5"
[2] Computing DIGEST response with password="null"...
Digest username="ghost", realm="UserDatabase", ...
[3] Sending request with crafted DIGEST credentials...
------------------------------------------------------------
[✗] HTTP 401 — exploit failed.
The UserDatabaseRealm provides a second line of defence:
getPrincipal("ghost") returned null after the digest matched.
============================================================
| Ressource | Link |
|---|---|
| Apache Tomcat Security Advisory | https://tomcat.apache.org/security-9.html |
| Fix-Commit | https://github.com/apache/tomcat/commit/6565a6cb6499e56fe2f34457cec99f9d1c4f39e9 |
RealmBase.java (main) | https://github.com/apache/tomcat/blob/main/java/org/apache/catalina/realm/RealmBase.java |
| RFC 2617 — HTTP Digest Authentication | https://datatracker.ietf.org/doc/html/rfc2617 |
| Vollständige Analyse – Blogbeitrag | https://return-zero.dev/posts/cve-2026-43512 |
Dieses Repository ist ausschließlich für Bildungszwecke und die lokale Exploitability-Analyse bestimmt. Alle Tests wurden gegen eine selbst gehostete Container-Umgebung durchgeführt. Führen Sie diesen PoC nicht gegen Systeme aus, die Ihnen nicht gehören oder für die Sie keine ausdrückliche schriftliche Genehmigung zum Testen haben.