abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · tomcat-rewrite-ns-loop
类别: DoS 可达性: 远程
Apache Tomcat 11.0.27 (52f3b364) - tomcat.apache.org
RewriteValve.parseRuleFlag 使用前缀匹配。在 NC/NE 之后,任何以 startsWith("N") 开头的剩余标志都会启用下一个标志。从 httpd 复制过来的 [NS](nosubreq)和 [NV](novary)会变成 [N]。替换符 - 会使 substitution 为 null;随后 RewriteRule.evaluate 返回原始 URL。isNext() 加上非 null 的 newtest 会将 i = -1 设置,且没有轮次上限,因此一个匹配该规则的未认证 GET 请求会一直占用 HTTP 连接器线程,直到客户端断开或进程重启。显式 [N] 和 [S=-1] 是相同的占用。[L,NS] 是安全的,因为 isLast() 会先中断。
CVE-2026-65927(Important,11.0.25)修复了 [N] 在第二条规则处重新开始的问题。此占用仍然没有轮次上限。11.0.27 之后的同日 main 添加了 MAX_REWRITE_ROUNDS=1000 和精确标志匹配(2da9fddb、8992dbdd),但没有安全公告。
| ID | 暂无 CVE |
| 类别 | DoS |
| 可达性 | 远程(未认证 HTTP) |
| CWE | CWE-835 |
| CVSS | High: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| 产品 | Apache Tomcat |
| 受影响 | 11.0.27 (52f3b364e5882a5dbcfc42cb8313a7c2ae532c64) RewriteValve |
| 认证 | 未认证 HTTP |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1 |
我固定了标签 11.0.27 并阅读了 RewriteValve.invoke。该 valve 不在默认的 conf/server.xml 中。默认 Host 路径是 conf/Catalina/localhost/rewrite.config。实验环境是 127.0.0.1:18910 上的回环 HTTP。官方 11.0.27 tarball。不是 RCE。
| 方法 | 汇聚点 | 权限 |
|---|---|---|
未认证 GET /loop 匹配 Host rewrite.config 中的 RewriteRule ^/loop$ - [NS] | RewriteValve.invoke 中 i = -1,因为对 token NS 执行 startsWith("N") | 可用性(实验环境已证实): 占用一个 HTTP 连接器线程,直到客户端断开或进程重启。实验环境:/loop 在 4.002s 超时。 |
未认证 GET /next 使用显式 [N] | 相同的 isNext() 重启 | 可用性(实验环境已证实): 相同的占用。实验环境:/next 在 4.003s 超时。 |
未认证 GET /skip 使用 [S=-1] | i += -1 然后 for 递增 | 可用性(实验环境已证实): 相同的占用。实验环境:/skip 在 4.002s 超时。 |
| 每个 worker 一个匹配请求 | 相同的汇聚点,maxThreads 个并发匹配 URL | 可用性(推断): 填满连接器池(实验环境使用 32;默认值为 200)。新请求随后排队或被拒绝。当一个 /loop 正在执行时,同级 /ok 仍能响应。 |
挂起 vs /ok 上 13ms 的 404 | next/skip 与 [L] 的时序 | 侦察(实验环境已证实): 判断出 next/skip 规则已匹配。实验环境:4.002s 挂起 vs 0.013s 404。 |
实验环境已证实 vs 推断: /loop [NS] 挂起、/next [N] 挂起、/skip [S=-1] 挂起、/ok [L] 在 13ms 内返回 404、/safe [L,NS] 在 5ms 内返回 404,以及 /loop 执行期间同级 /ok 返回 404 均为实验环境已证实。池耗尽是根据单线程占用加上 maxThreads 推断的。
前提条件: Host 或 Context 上启用了 RewriteValve,并且存在匹配的 rewrite.config 规则。该 valve 是选择性启用的,与注释掉的 AJP 属于同一类。从 httpd 复制过来的 [NS] 是匹配规则,而不是有意为之的无限 [N] 循环。
| 攻击面 | 实验环境 |
|---|---|
[L,NS](httpd last+nosubreq) | /safe 在 5ms 内返回 404(L-ns-safe=yes) |
| 一个线程被占用时其他在途请求 | /loop 期间 /ok 在 13ms 内返回 404(sibling-alive=yes) |
不带 RewriteValve 的默认 server.xml | valve 不存在;遗留内容不会触发 |
| CVE-2026-65927 的 RCE / WEB-INF 读取 / 约束绕过 | [N] 现在从规则 0 重新开始;此遗留问题仅影响可用性 |
| Manager / JMX / AJP / DefaultServlet PUT | 未改变;PUT 仍为 readonly |
没有以 Tomcat 用户身份执行代码。没有读取 conf/ 或 WEB-INF。没有会话窃取。没有 Manager 部署。JVM 保持运行;其他 worker 仍能响应,直到池被填满。
cd lab
./run.sh
回环 127.0.0.1:18910 映射到容器 8080。Compose 项目 tomcat-rewrite-ns-loop。镜像标签 tomcat-rewrite-ns-loop:11.0.27。官方 apache-tomcat-11.0.27.tar.gz SHA512 a617896307cada4884b24f80c4e977ddad8b3e0f88ce0e2a6eea29d5f332498e276ae5976c227a9c8daecf05c7c90def684a3766dd5a81f47a56d8b1adf43dc3。见证 TOMCAT-REWRITE-NS-LOOP-WITNESS。最后一行:
SUCCESS TOMCAT-REWRITE-NS-LOOP control-ok=yes ns-hang=yes L-ns-safe=yes n-hang=yes skip-hang=yes sibling-alive=yes TOMCAT-REWRITE-NS-LOOP-WITNESS
实验环境 rewrite.config:
RewriteRule ^/loop$ - [NS]
RewriteRule ^/next$ - [N]
RewriteRule ^/skip$ - [S=-1]
RewriteRule ^/ok$ - [L]
RewriteRule ^/safe$ - [L,NS]
限制重写轮次(此标签之后的 main 上为 MAX_REWRITE_ROUNDS=1000,提交 2da9fddb)。精确匹配标志,使 [NS] 解析失败(提交 8992dbdd)。拒绝 skip < 0。在这些进入正式发布之前:避免在匹配规则中使用 [NS]/[NV]/[N]/[S=-1],或移除 RewriteValve。
52f3b364e5882a5dbcfc42cb8313a7c2ae532c64)RewriteValve.java 中的 isNext() 重启和 startsWith("N")RewriteRule.java 中替换符 - 返回原始 URL