可利用性分析结果: 根本原因已确认。但针对标准
UserDatabaseRealm部署,端到端利用不可复现。详情请参见分析。
CVE-2026-43512 是 Apache Tomcat 的 HTTP DIGEST 认证机制中的一个漏洞。方法 RealmBase.getDigest() 在构造 A1 哈希输入之前,未验证 getPassword(username) 的返回值。当用户名在已配置的 Realm 中不存在时,getPassword() 返回 null,Java 的字符串连接运算符会静默地将其转换为四个字符的字面量 "null"。
服务器因此计算:
A1 = MD5("<username>:<realm>:null")
客户端如果提交的 DIGEST 响应中使用字面量字符串 "null" 作为密码计算,则会产生相同的哈希。根据安全公告,这构成认证绕过。
本仓库包含一个最小可复现环境和一个基于 Go 的概念验证代码,用于对真实 Tomcat 实例验证这一论断。
| 受影响范围 | 修复版本 |
|---|---|
| 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 |
RealmBase.java 中的脆弱代码路径(所有受影响分支):
// RealmBase.java — 脆弱版本
protected String getDigest(String username, String realmName, String algorithm) {
if (hasMessageDigest(algorithm)) {
return getPassword(username); // 对于未知用户返回 null
}
// null 会被 Java 连接为字面量 "null"
String a1 = username + ":" + realmName + ":" + getPassword(username);
return HexUtils.toHexString(
ConcurrentMessageDigest.digest(algorithm, a1.getBytes(...))
);
}
修复(提交 6565a6c)增加了一个显式的空检查:
// RealmBase.java — 已修复
protected String getDigest(String username, String realmName, String algorithm) {
String password = getPassword(username);
if (password == null) {
return null;
}
...
}
针对 Tomcat 11.0.0-M1 运行 PoC,并启用 FINE 级别日志,观察到以下结果:
Digest: 2388e2c78407def640f37f092a8d3a84 ← 客户端
Server digest: 2388e2c78407def640f37f092a8d3a84 ← 服务端
Failed to authenticate user [ghost]
摘要哈希匹配。 getDigest() 中的错误确实存在且已确认。然而,认证仍然失败,因为 RealmBase.authenticate() 包含一个独立的二次检查:
// RealmBase.authenticate()
if (serverDigest.equals(clientDigest)) {
return getPrincipal(username); // 对于不存在的用户返回 null
}
return null;
在由 tomcat-users.xml 支持的典型 UserDatabaseRealm 中,getPrincipal() 会查询内存中的用户数据库。对于数据库中不存在的用户名,返回 null。调用方将 null Principal 视为认证失败,并返回 401。
cve-2026-43512-poc/
├── Dockerfile # Tomcat 11.0.0-M1(受影响版本)
├── tomcat-users.xml # 最小 Realm 配置 — 无用户 "ghost"
├── web.xml
├── exploit/
│ ├── exploit.go # PoC — Go,仅使用标准库
│ └── go.mod
└── README.md
| 工具 | 版本 | 说明 |
|---|---|---|
| Podman | ≥ 4.0 | Docker 亦可使用 |
| Go | ≥ 1.22 | 仅在本地运行利用代码时需要 |
podman build -t tomcat-cve-2026-43512 .
podman run -d --name tomcat-vuln -p 8080:8080 tomcat-cve-2026-43512
等待数秒使 Tomcat 完成启动,然后验证其是否正常运行:
curl -si http://localhost:8080/protected/secret.html | head -1
# 预期输出:HTTP/1.1 401
cd exploit
go run exploit.go \
-target http://localhost:8080 \
-path /protected/secret.html \
-username ghost
可用参数:
要观察内部认证状态,可添加 logging.properties 文件并挂载:
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
日志将直接显示摘要比较结果,从而确认哈希是否匹配。
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.
============================================================
本仓库仅用于教育目的和本地可利用性分析。所有测试均在自托管的容器环境中进行。请勿将此 PoC 用于非您拥有或未获得明确书面授权的系统。
| 10.1.55 |
| 11.0.0.M1 – 11.0.21 | 11.0.22 |
| 标志 | 默认值 | 说明 |
|---|
-target | http://localhost:8080 | Tomcat 基础 URL |
-path | /protected/ | 受保护资源的路径 |
-username | ghost | 要使用的用户名 — 必须不存在于 tomcat-users.xml 中 |
| 资源 | 链接 |
|---|
| Apache Tomcat 安全公告 | https://tomcat.apache.org/security-9.html |
| 修复提交 | https://github.com/apache/tomcat/commit/6565a6cb6499e56fe2f34457cec99f9d1c4f39e9 |
RealmBase.java(主分支) | https://github.com/apache/tomcat/blob/main/java/org/apache/catalina/realm/RealmBase.java |
| RFC 2617 — HTTP Digest 认证 | https://datatracker.ietf.org/doc/html/rfc2617 |
| 完整分析 — 博客文章 | https://return-zero.dev/posts/cve-2026-43512 |