概述
定义XML配置时如果namespace值未设置且上层动作配置(Action Configuration)中未设置或用通配符namespace时可能会导致远程代码执行。
url标签未设置value和action值且上层动作未设置或用通配符namespace时可能会导致远程代码执行。
官方解决方案
升级至版本2.3.35或2.5.17。这两个版本仅仅只是更新了安全补丁,不存在兼容性问题。
临时解决方案
推荐用户及时更新,但如果不想更新,可暂时使用官方提供的临时解决方案:当上层动作配置中未设置或使用通配符namespace时,验证所有XML配置中的namespace,同时在JSP中验证所有url标签的value和action。
影响范围
所有Struts2开发者及用户
漏洞影响
有可能会导致远程代码执行
最高安全风险
关键
推荐防护措施
更新至2.3.35或2.5.17
影响版本
Struts 2.3 – Struts 2.3.34, Struts 2.5 – Struts 2.5.16
其余版本也可能会受到影响
漏洞报告人
Man Yue Mo@Semmle Security Research team
CVE编号
CVE-2018-11776
CVSS v3
CVSS3 Base Score 9.8 CVSS3 Base Metrics CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H Attack Vector Network Attack Complexity Low Privileges Required None User Interaction None Scope Unchanged Confidentiality High Integrity Impact High Availability Impact High
可能的攻击向量
struts.xml中结果类型
未定义namespace时在<action …>tag中三种struts结果类型会有安全风险:
示例如下:
<struts> <package ....> <action name="a1"> <result type="redirectAction"> <param name="actionName">a2.action</param> </result> </action> </package> </struts>模板中的url tag
当模板关联的<action>tag没有提供namespace以及包含无value和action的<s:url …>tag时有安全风险。
示例如下:
<action name="help" namespace="/*"> <result>/WEB-INF/help.jsp</result> </action> <s:url includeParams="get"> <s:param name="id" value="%{'22'}" /> </s:url>
漏洞细节Semmle Security将在近期公布
以ServletActionRedirectResult.java为例:
首先,getNamespace()调用通过变量namespace传入ActionMapping构造函数中。
public void execute(ActionInvocation invocation) throws Exception { actionName = conditionalParse(actionName, invocation); if (namespace == null) { namespace = invocation.getProxy().getNamespace(); //<--- source } else { namespace = conditionalParse(namespace, invocation); } if (method == null) { method = ""; } else { method = conditionalParse(method, invocation); } String tmpLocation = actionMapper.getUriFromActionMapping(new ActionMapping(actionName, namespace, method, null)); //<--- namespace goes into constructor of ActionMapping setLocation(tmpLocation);可以看到,getUriFromActionMapping()通过ActionMapping对象返回URL字符串,接着通过tmpLocation传入setLocation()。
接着setLocation()将location传入StrutsResultSupport类。
public void setLocation(String location) { this.location = location; }接着在ServletActionResult上执行execute()。
String tmpLocation = actionMapper.getUriFromActionMapping(new ActionMapping(actionName, namespace, method, null)); setLocation(tmpLocation); super.execute(invocation);location被传入conditionalParse()。
public void execute(ActionInvocation invocation) throws Exception { lastFinalLocation = conditionalParse(location, invocation); doExecute(lastFinalLocation, invocation); }conditionalParse()将location传入translateVariables(),在此参数处理为OGNL表达式。
protected String conditionalParse(String param, ActionInvocation invocation) { if (parse && param != null && invocation != null) { return TextParseUtil.translateVariables( param, invocation.getStack(), new EncodingParsedValueEvaluator()); } else { return param; } }综上,当ServletActionRedirectResult中未设置namespace时,将会从ActionProxy中取namespace作为OGNL。因此此处可修改struts-actionchaining.xml测试:
<struts> <package name="actionchaining" extends="struts-default"> <action name="actionChain1" class="org.apache.struts2.showcase.actionchaining.ActionChain1"> <result type="redirectAction"> <param name = "actionName">register2</param> </result> </action> </package> </struts>启动应用,访问特定URL触发漏洞,绕过OGNL沙箱后可造成命令执行。
文章原文链接:https://www.anquanke.com/post/id/157397

