S2-033漏洞分析

概述

itemdetail
Impact of vulnerabilityPossible Remote Code Execution
Maximum security ratingHigh
RecommendationDisable Dynamic Method Invocation if possible. Alternatively upgrade to Struts 2.5
Affected SoftwareStruts 2.3.20-2.3.28
ReporterAlvaro Munoz alvaro dot munoz at hpe dot com
CVE IdentifierCVE-2016-3087

分析

S2-032在修复过程中没有覆盖全面,遗漏了对rest插件中mapping.setName()方法传入数据的过滤,使系统开启动态方法调用(Dynamic Method Invocation)时,攻击者仍可构造恶意URL并通过rest插件触发命令执行。

rest插件中的问题代码

\struts-2.3.20.1\src\plugins\rest\src\main\java\org\apache\struts2\rest\RestActionMapper.java
line 181

public ActionMapping getMapping(HttpServletRequest request,
            ConfigurationManager configManager) {
        ActionMapping mapping = new ActionMapping();
        String uri = RequestUtils.getUri(request);
    ...
        parseNameAndNamespace(uri, mapping, configManager);
    ...
        // handle "name!method" convention.
        handleDynamicMethodInvocation(mapping, mapping.getName());

该函数通过RequestUtils.getUri()获取url输入,之后调用parseNameAndNamespace(uri, mapping, configManager)从url中提取出name值:

protected void parseNameAndNamespace(String uri, ActionMapping mapping,
            ConfigurationManager configManager) {
        String namespace, name;
        int lastSlash = uri.lastIndexOf("/");
        if (lastSlash == -1) {
            namespace = "";
            name = uri;
        } else if (lastSlash == 0) {
            // ww-1046, assume it is the root namespace, it will fallback to
            // default
            // namespace anyway if not found in root namespace.
            namespace = "/";
            name = uri.substring(lastSlash + 1);
        } else {
            // Try to find the namespace in those defined, defaulting to ""
            Configuration config = configManager.getConfiguration();
            String prefix = uri.substring(0, lastSlash);
            namespace = "";
            // Find the longest matching namespace, defaulting to the default
            for (Object o : config.getPackageConfigs().values()) {
                String ns = ((PackageConfig) o).getNamespace();
                if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) {
                    if (ns.length() > namespace.length()) {
                        namespace = ns;
                    }
                }
            }

            name = uri.substring(namespace.length() + 1);
        }

        mapping.setNamespace(namespace);
        mapping.setName(name);
    }

这个从url提取出的name字段最终通过mapping.setName()函数,存储在mapping.name

struts-2.3.20.1\src\core\src\main\java\org\apache\struts2\dispatcher\mapper\ActionMapping.java  
line 129

public void setName(String name) {
        this.name = name;
}

随后,mapping.name通过handleDynamicMethodInvocation()方法传入mapping.method变量。

line 299

    private void handleDynamicMethodInvocation(ActionMapping mapping, String name) {
        int exclamation = name.lastIndexOf("!");
        if (exclamation != -1) {
            mapping.setName(name.substring(0, exclamation));
            if (allowDynamicMethodCalls) {
                mapping.setMethod(name.substring(exclamation + 1));
            } else {
                mapping.setMethod(null);
            }
        }
    }

在这里,mapping.method值被带入ognl表达式,命令执行和S2-032相同。

struts-2.3.20.1-all\struts-2.3.20.1\src\xwork-core\src\main\java\com\opensymphony\xwork2\DefaultActionInvocation.java
line 410

protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
        String methodName = proxy.getMethod();

        if (LOG.isDebugEnabled()) {
            LOG.debug("Executing action method = #0", methodName);
        }

        String timerKey = "invokeAction: " + proxy.getActionName();
        try {
            UtilTimerStack.push(timerKey);

            Object methodResult;
            try {
                methodResult = ognlUtil.getValue(methodName + "()", getStack().getContext(), action);
            } catch (OgnlException e) {
                // hmm -- OK, try doXxx instead
                try {
                    String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1)  + "()";
                    methodResult = ognlUtil.getValue(altMethodName, ActionContext.getContext().getContextMap(), action);

修复建议

官方给出的建议:

Disable Dynamic Method Invocation if possible. Alternatively upgrade to Struts 2.3.20.3, Struts 2.3.24.3 or Struts 2.3.28.1.

事实上这三个最新版本并没有修复这个漏洞,在下一版本更新之前建议选用如下方法修复:

  • 关闭动态方法调用
  • 更新至2.5
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值