covepseng/cve-2026-43512-poc

GitHub: covepseng/cve-2026-43512-poc

Apache Tomcat DIGEST 认证绕过漏洞(CVE-2026-43512)的概念验证项目,包含漏洞复现环境和 Go 语言 PoC 利用程序。

Stars: 0 | Forks: 1

# CVE-2026-43512 — Apache Tomcat DIGEST 认证绕过 ## 目录 - [概述](#overview) - [受影响版本](#affected-versions) - [根本原因](#root-cause) - [分析](#analysis) - [仓库结构](#repository-structure) - [环境要求](#requirements) - [用法](#usage) - [预期输出](#expected-output) - [参考资料](#references) - [免责声明](#disclaimer) ## 概述 CVE-2026-43512 是 Apache Tomcat 的 HTTP DIGEST 认证机制中的一个漏洞。`RealmBase.getDigest()` 方法在构造 A1 哈希输入之前,没有对 `getPassword(username)` 的返回值进行校验。当配置的 Realm 中不存在某个用户名时,`getPassword()` 会返回 `null`,而 Java 的字符串拼接操作符会将其静默转换为四个字符的字面量 `"null"`。 因此,服务器计算的内容为: ``` A1 = MD5("::null") ``` 如果客户端提交的 DIGEST 响应是使用字面字符串 `"null"` 作为密码计算出来的,则会产生完全相同的哈希值。根据安全公告,这构成了认证绕过。 本仓库包含一个最小化的复现环境以及一个基于 Go 的概念验证(PoC),用于针对真实的 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 | 10.1.55 | | 11.0.0.M1 – 11.0.21 | 11.0.22 | ## 根本原因 `RealmBase.java` 中的易受攻击代码路径(所有受影响的分支): ``` // 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(...)) ); } ``` 修复方案([提交 `6565a6c`](https://github.com/apache/tomcat/commit/6565a6cb6499e56fe2f34457cec99f9d1c4f39e9))添加了一个显式的 null 检查: ``` // RealmBase.java — patched protected String getDigest(String username, String realmName, String algorithm) { String password = getPassword(username); if (password == null) { return null; } ... } ``` ## 分析 在启用 `FINE` 级别日志记录的情况下,针对 Tomcat 11.0.0-M1 运行 PoC 会显示以下信息: ``` Digest: 2388e2c78407def640f37f092a8d3a84 ← client Server digest: 2388e2c78407def640f37f092a8d3a84 ← server Failed to authenticate user [ghost] ``` **摘要哈希值匹配。** `getDigest()` 中的 bug 是真实的并已得到确认。然而,认证仍然会失败,因为 `RealmBase.authenticate()` 还有第二个独立的检查: ``` // RealmBase.authenticate() if (serverDigest.equals(clientDigest)) { return getPrincipal(username); // returns null for non-existent users } return null; ``` 在由 `tomcat-users.xml` 支持的标准 `UserDatabaseRealm` 中,`getPrincipal()` 会针对内存中的用户数据库执行查找。对于该数据库中不存在的用户名,它会返回 `null`。调用方会将 `null` 的 Principal 视为认证失败,并发出 `401` 状态码。 ## 仓库结构 ``` cve-2026-43512-poc/ ├── Dockerfile # Tomcat 11.0.0-M1 (affected version) ├── tomcat-users.xml # Minimal Realm config — no user "ghost" ├── webapps/ │ └── protected/ │ ├── WEB-INF/ │ │ └── web.xml # DIGEST auth on /protected/* │ └── secret.html # Protected resource ├── exploit/ │ ├── exploit.go # PoC — Go, stdlib only │ └── go.mod └── README.md ``` ## 环境要求 | 工具 | 版本 | 备注 | |------|---------|-------| | Podman | ≥ 4.0 | Docker 也可以 | | Go | ≥ 1.22 | 仅用于在本地运行漏洞利用程序 | ## 用法 ### 1. 构建并启动容器 ``` 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 ``` ### 2. 运行漏洞利用程序 ``` cd exploit go run exploit.go \ -target http://localhost:8080 \ -path /protected/secret.html \ -username ghost ``` 可用的标志: | 标志 | 默认值 | 描述 | |------|---------|-------------| | `-target` | `http://localhost:8080` | Tomcat 基础 URL | | `-path` | `/protected/` | 受保护资源的路径 | | `-username` | `ghost` | 要使用的用户名 — 必须**不**存在于 `tomcat-users.xml` 中 | ### 3. 启用详细的 Tomcat 日志记录(可选) 要观察内部认证状态,请添加一个 `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 ``` 日志将直接显示摘要比对的结论,从而确认哈希值是否匹配。 ### 4. 清理 ``` 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. ============================================================ ``` ## 参考资料 | 资源 | 链接 | |----------|------| | Apache Tomcat 安全公告 | https://tomcat.apache.org/security-9.html | | 修复提交 | 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 | | 完整分析 — 博客文章 | https://return-zero.dev/posts/cve-2026-43512 | ## 免责声明 本仓库仅供教育目的和本地漏洞利用分析使用。所有测试均是在自行搭建的容器环境中进行的。请勿对您不拥有或未获得明确书面授权测试的系统运行此 PoC。
标签:Apache Tomcat, CISA项目, EVTX分析, Go语言, PoC, 日志审计, 暴力破解, 程序破解, 请求拦截, 身份验证绕过