Apache Tomcat RewriteValve 路径遍历漏洞(CVE-2025-55752)

环境搭建:

1、下载 9.0.108 漏洞版本并解压:

https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.108/bin/apache-tomcat-9.0.108-windows-x64.zip

2、在 conf/server.xml 中添加如下开启 RewriteValve 配置:

1
<Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />

3、创建 conf/Catalina/localhost/rewrite.config 并配置 RewriteValve 规则:

1
2
RewriteCond %{QUERY_STRING} (^|&)path=([^&]+)
RewriteRule ^/download$ /%2 [B,L]

漏洞分析:

根据漏洞描述可知:关键点在 RewriteValve 重写,其作用类似于Apache HTTP 服务器的 mod_rewrite 实现了 URL 重写功能。

https://tomcat.apache.org/tomcat-9.0-doc/rewrite.html

比如存在以下规则:/download?path=/WEB-INF/web.xml 会通过 RewriteValve 处理后变为 //WEB-INF/web.xml, 然后归一化(normalize)后变为 /WEB-INF/web.xml

1
2
RewriteCond %{QUERY_STRING} (^|&)path=([^&]+)
RewriteRule ^/download$ /%2 [B,L]

继续查看漏洞补丁:根源在于 RewriteValve 处理URL重写时,归一化步骤在URL解码之前执行,导致 %2f 无法被正确识别和归一化。

https://github.com/apache/tomcat/commit/b5042622b8b78340ae65403c55dcb9c7416924df?diff=split

补丁前:

1
2
3
4
5
6
// 步骤1: 对重写后的URL进行编码
StringBuilder urlStringEncoded = new StringBuilder(REWRITE_DEFAULT_ENCODER.encode(urlStringRewriteEncoded, uriCharset));
// 步骤2: 归一化处理(但此时URL仍处于编码状态)
urlStringRewriteEncoded = RequestUtil.normalize(urlStringRewriteEncoded); // 归一化编码的URL
// 步骤3: 后续才进行URL解码
chunk.append(URLDecoder.decode(urlStringRewriteEncoded, uriCharset.name()));

补丁后:

1
2
3
4
5
6
// 步骤1: 先对编码的URL进行解码
String urlStringRewriteDecoded = URLDecoder.decode(urlStringRewriteEncoded, uriCharset.name());
// 步骤2: 对解码后的URL进行归一化
urlStringRewriteDecoded = RequestUtil.normalize(urlStringRewriteDecoded); // 归一化解码后的URL
// 步骤3: 使用归一化后的解码URL
chunk.append(urlStringRewriteDecoded);

比如以下请求 /download?path=%2FWEB-INF/web.xml,由于先归一化无法处理%2F,导致变成/%2FWEB-INF/web.xml,然后在URL解码变成//WEB-INF/web.xml。

org.apache.catalina.valves.rewrite.RewriteValve#invoke

而 tomcat 中的 StandardContextValve 会检查以 /WEB-INF/或 /META-INF/ 为开头的敏感路径,并且是在 RewriteValve 后才检查从而导致绕过。

org.apache.catalina.core.StandardContextValve#invoke

漏洞复现:

curl -i “http://localhost:8080/download?path=%2FWEB-INF/web.xml