从 CC1 到 CC7:Java 反序列化漏洞的攻击链分析与防御解析
Apache Commons Collections(简称“CC”)是 Java 生态中最常用的第三方工具库之一,提供了丰富的集合操作类。然而,其内部部分可序列化类(如 TransformedMap、LazyMap)与“函数式接口”(如 Transformer)的组合,存在反序列化代码执行漏洞。从 CC1 到 CC7,攻击者通过不同的类组合与触发逻辑,构建了多条成熟的反序列化攻击链,成为 Java 反序列化漏洞的“经典标杆”。本文将逐一拆解 7 条 CC 攻击链的核心原理、依赖条件与执行流程,并提供体系化的防御方案。
一、CC 系列漏洞基础:核心前提与关键概念
在分析具体攻击链前,需明确 CC 漏洞的两大核心前提与关键类,这是所有 CC 攻击链的共同基础:
1. 核心前提
- 反序列化入口:目标应用存在“反序列化不可信数据”的场景(如通过
ObjectInputStream.readObject()读取用户传入的Serializable对象); - 依赖 CC 库:目标应用引入了存在漏洞的 Apache Commons Collections 版本(不同 CC 链对应不同版本,详见下文)。
2. 关键概念与类
CC 攻击链的核心是“利用可序列化类的 readObject() 方法,触发预设的 Transformer 函数链,最终执行恶意代码”,关键类如下:
| 类名 | 作用 |
|---|---|
Transformer |
函数式接口,定义 transform(Object input) 方法,用于对对象进行转换 |
ChainedTransformer |
实现 Transformer,将多个 Transformer 组成“链式调用”,依次执行 transform |
InvokerTransformer |
实现 Transformer,通过反射调用任意类的任意方法(CC1 核心) |
InstantiateTransformer |
实现 Transformer,通过反射实例化任意类(CC2 核心) |
TransformedMap |
实现 Map,对键/值的修改操作触发预设 Transformer(CC1、CC2 触发载体) |
LazyMap |
实现 Map,对不存在的键调用 get() 时触发预设 Transformer(CC3、CC6、CC7 触发载体) |
Proxy |
JDK 动态代理类,调用代理对象方法时触发 InvocationHandler 的 invoke()(CC3、CC7 核心) |
BadAttributeValueExpException |
JDK 内置异常类,readObject() 会调用 toString() 触发恶意逻辑(CC5、CC7 触发载体) |
二、CC1 到 CC7 攻击链逐一解析
(一)CC1:最经典的“TransformedMap + InvokerTransformer”链
1. 核心原理
利用 TransformedMap 在反序列化时对“键/值”的转换逻辑,触发 ChainedTransformer 链式调用,最终通过 InvokerTransformer 的反射能力执行系统命令。
2. 依赖版本
- Apache Commons Collections:3.1 ~ 3.2.1(3.2.2 版本修复了
InvokerTransformer的危险反射调用); - JDK 版本:无特殊限制(JDK 1.7+ 均可触发)。
3. 攻击链流程
- 构造
Transformer链:创建ChainedTransformer,包含 3 个关键Transformer:ConstantTransformer:返回目标类(如Runtime.class);InvokerTransformer:调用Runtime.getRuntime()(反射获取getRuntime方法并执行);InvokerTransformer:调用Runtime.exec(String cmd)(反射执行系统命令)。
- 创建
TransformedMap:通过TransformedMap.decorate()为普通HashMap绑定上述Transformer(指定对“值”进行转换); - 触发反序列化:将
TransformedMap序列化后传入目标应用,目标执行readObject()时:TransformedMap的readObject()会恢复 Map 数据,对“值”触发Transformer链;- 最终通过
InvokerTransformer反射执行Runtime.exec(cmd)。
4. 关键代码示例(简化 POC)
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class CC1 {
public static void main(String[] args) throws Exception {
// 1. 构造命令执行的 Transformer 链
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class), // 传入 Runtime.class
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}), // 反射 getRuntime() 方法
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}), // 执行 getRuntime(),返回 Runtime 实例
new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"calc.exe"}) // 执行 exec("calc.exe"),弹出计算器
};
Transformer chain = new ChainedTransformer(transformers);
// 2. 创建 TransformedMap(对值触发 Transformer 链)
Map map = new HashMap();
map.put("key", "value");
Map transformedMap = TransformedMap.decorate(map, null, chain); // 键:null(不转换),值:chain
// 3. 序列化与反序列化(模拟目标应用操作)
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(transformedMap); // 序列化
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
ois.readObject(); // 反序列化,触发命令执行
}
}
5. 特点
- 最经典、最易理解的 CC 链,无复杂依赖;
- 3.2.2 版本后因
InvokerTransformer被限制(禁止调用exec、getRuntime等危险方法)而失效。
(二)CC2:针对 CC4.x 的“InstantiateTransformer + TemplatesImpl”链
1. 核心原理
CC 4.0 版本修复了 InvokerTransformer,但引入了 InstantiateTransformer(用于实例化类)。攻击者通过 InstantiateTransformer 实例化 JDK 内置的 TemplatesImpl 类,利用 TemplatesImpl 的 defineClass() 方法加载恶意字节码,实现代码执行。
2. 依赖版本
- Apache Commons Collections:4.0 ~ 4.0.1(4.1 版本修复
InstantiateTransformer); - JDK 版本:需支持
TemplatesImpl(JDK 1.6+,默认包含com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl)。
3. 攻击链流程
- 构造恶意字节码:编写触发命令执行的 Java 类(如
Evil),编译为字节码; - 构造
TemplatesImpl:设置TemplatesImpl的_bytecodes为恶意字节码,_name为非空值(触发defineClass()); - 构造
Transformer链:通过ChainedTransformer组合ConstantTransformer(返回TemplatesImpl)和InstantiateTransformer(实例化TemplatesImpl); - 触发反序列化:通过
TransformedMap作为载体,反序列化时触发Transformer链,InstantiateTransformer实例化TemplatesImpl并加载恶意字节码,执行命令。
4. 特点
- 规避了
InvokerTransformer的限制,利用 JDK 内置类TemplatesImpl加载字节码; - 4.1 版本后
InstantiateTransformer被限制实例化危险类,链失效。
(三)CC3:“LazyMap + Proxy”变种链
1. 核心原理
CC1 的 TransformedMap 需“修改值”触发转换,而 CC3 利用 LazyMap 的 get() 方法(获取不存在的键时触发 Transformer),结合 JDK 动态代理(Proxy),在反序列化时自动调用 get(),无需手动修改值。
2. 依赖版本
- Apache Commons Collections:3.1 ~ 3.2.1(同 CC1,依赖
InvokerTransformer); - JDK 版本:支持动态代理(JDK 1.3+)。
3. 攻击链流程
- 构造
Transformer链:同 CC1(ChainedTransformer + InvokerTransformer),实现命令执行; - 创建
LazyMap:通过LazyMap.decorate()为HashMap绑定Transformer链; - 创建动态代理:以
LazyMap为目标,创建Map接口的代理对象,InvocationHandler中重写invoke(),调用LazyMap.get(); - 触发反序列化:反序列化代理对象时,
readObject()会调用代理的entrySet()方法(Map 反序列化默认操作),进而触发InvocationHandler.invoke()→LazyMap.get()→Transformer链 → 命令执行。
4. 特点
- 无需“修改值”即可触发,适用场景更广(如目标反序列化时不修改 Map 值,但会调用
entrySet()等方法); - 依赖
Proxy,需目标反序列化时调用代理对象的方法。
(四)CC4:“PriorityQueue + TransformedMap”的 CC4.x 适配链
1. 核心原理
CC4 针对 CC 4.x 版本,利用 PriorityQueue(优先级队列)的 readObject() 会调用 comparator.compare() 的特性,结合 TransformedMap 和 InstantiateTransformer,触发 TemplatesImpl 加载恶意字节码。
2. 依赖版本
- Apache Commons Collections:4.0 ~ 4.0.1(同 CC2,依赖
InstantiateTransformer); - JDK 版本:支持
PriorityQueue(JDK 1.5+)。
3. 攻击链流程
- 构造
TemplatesImpl与Transformer链:同 CC2,通过InstantiateTransformer实例化TemplatesImpl; - 创建
TransformedMap:绑定Transformer链; - 创建
PriorityQueue:将TransformedMap的entrySet()作为元素传入,设置comparator为触发Map操作的逻辑; - 反序列化触发:
PriorityQueue的readObject()会调用comparator.compare(),间接触发TransformedMap的Transformer链 →InstantiateTransformer→TemplatesImpl加载字节码 → 命令执行。
4. 特点
- 利用
PriorityQueue的反序列化逻辑,无需依赖Proxy; - 仅适用于 CC 4.x 版本,4.1 后失效。
(五)CC5:“BadAttributeValueExpException + LazyMap”链
1. 核心原理
利用 JDK 内置异常类 BadAttributeValueExpException 的 readObject() 方法:该方法会调用 getValue().toString(),若 getValue() 返回 LazyMap 的代理对象,会触发 invoke() → LazyMap.get() → Transformer 链。
2. 依赖版本
- Apache Commons Collections:3.1 ~ 3.2.1(依赖
LazyMap和InvokerTransformer); - JDK 版本:支持
BadAttributeValueExpException(JDK 1.2+,默认包含)。
3. 攻击链流程
- 构造
LazyMap + Proxy:同 CC3,创建绑定Transformer链的LazyMap,并生成代理对象; - 创建
BadAttributeValueExpException:将其val字段设为上述代理对象; - 反序列化触发:
BadAttributeValueExpException的readObject()调用val.toString()→ 代理对象的invoke()→LazyMap.get()→ 命令执行。
4. 特点
- 利用 JDK 内置类(无第三方依赖除 CC 外),隐蔽性更强;
- 无需目标调用
Map的entrySet(),仅需反序列化BadAttributeValueExpException。
(六)CC6:“HashMap + TiedMapEntry + LazyMap”链
1. 核心原理
CC6 针对 CC 3.2.1 版本(InvokerTransformer 未完全修复),利用 HashMap 的 readObject() 会处理 TiedMapEntry 的特性:TiedMapEntry.getValue() 会调用 LazyMap.get(),进而触发 Transformer 链。
2. 依赖版本
- Apache Commons Collections:3.2.1(特定版本,3.2.2 后失效);
- JDK 版本:支持
HashMap和TiedMapEntry(JDK 1.2+,CC 库包含TiedMapEntry)。
3. 攻击链流程
- 构造
LazyMap:绑定Transformer链(同 CC1); - 创建
TiedMapEntry:将LazyMap作为map参数传入TiedMapEntry; - 创建
HashMap:将TiedMapEntry作为键存入HashMap; - 反序列化触发:
HashMap的readObject()会调用TiedMapEntry.hashCode()→TiedMapEntry.getValue()→LazyMap.get()→ 命令执行。
4. 特点
- 利用
HashMap反序列化的默认逻辑,无需额外方法调用; - 仅适用于 CC 3.2.1 版本,兼容性较窄。
(七)CC7:“BadAttributeValueExpException + LazyMap + Proxy”终极链
1. 核心原理
CC7 是 CC5 的优化版,通过调整 BadAttributeValueExpException 的 val 字段类型(直接设为 LazyMap 而非代理对象),并利用 Proxy 的 invoke() 触发 LazyMap.get(),进一步降低触发条件。
2. 依赖版本
- Apache Commons Collections:3.1 ~ 3.2.1(同 CC1、CC3);
- JDK 版本:支持
BadAttributeValueExpException和Proxy。
3. 攻击链流程
- 构造
LazyMap + Proxy:同 CC3,生成LazyMap的代理对象; - 修改
BadAttributeValueExpException:通过反射将val字段设为代理对象(绕过val的类型检查); - 反序列化触发:
readObject()调用val.toString()→ 代理invoke()→LazyMap.get()→ 命令执行。
4. 特点
- 结合
BadAttributeValueExpException的隐蔽性与Proxy的灵活性,适用场景最广; - 需通过反射修改
BadAttributeValueExpException的val字段(默认val为Object类型,可绕过检查)。
三、CC 系列攻击链核心差异对比
| 攻击链 | 核心类组合 | 依赖 CC 版本 | 触发关键操作 | 优势 | 劣势 |
|---|---|---|---|---|---|
| CC1 | TransformedMap + InvokerTransformer | 3.1~3.2.1 | 反序列化时修改 Map 值 | 简单易懂,兼容性强 | 需手动修改值,场景受限 |
| CC2 | InstantiateTransformer + TemplatesImpl | 4.0~4.0.1 | TransformedMap 转换值 | 规避 InvokerTransformer 限制 | 依赖 CC4.x,字节码构造复杂 |
| CC3 | LazyMap + Proxy | 3.1~3.2.1 | 代理对象调用 entrySet() | 无需修改值,场景更广 | 依赖 Proxy 方法调用 |
| CC4 | PriorityQueue + TransformedMap | 4.0~4.0.1 | PriorityQueue 比较元素 | 适配 CC4.x,无 Proxy 依赖 | 仅支持 CC4.x,兼容性窄 |
| CC5 | BadAttributeValueExpException + LazyMap | 3.1~3.2.1 | 反序列化异常类 | 用 JDK 类,隐蔽性强 | 依赖 LazyMap 代理 |
| CC6 | HashMap + TiedMapEntry + LazyMap | 3.2.1 | HashMap 计算 hashCode | 无需额外方法调用 | 仅支持 3.2.1,版本限制严 |
| CC7 | BadAttributeValueExpException + Proxy | 3.1~3.2.1 | 异常类 val.toString() | 场景最广,隐蔽性最强 | 需反射修改异常类字段 |
四、体系化防御方案
CC 系列漏洞的本质是“不可信数据反序列化 + 危险类的链式调用”,防御需从“阻断反序列化入口”“限制危险类”“升级依赖”三个维度落地:
1. 根本防御:禁止反序列化不可信数据
- 核心原则:仅反序列化“可信来源”的数据(如内部系统生成的序列化对象),拒绝用户传入的
Serializable对象; - 替代方案:使用安全的序列化协议(如 JSON、Protobuf)替代 Java 原生序列化,避免
ObjectInputStream.readObject()的直接调用。
2. JDK 层面:配置序列化过滤器(Serial Filter)
JDK 9+ 引入 serialFilter,可通过黑名单/白名单限制反序列化的类,阻断 CC 链的关键类:
- JVM 参数配置(全局生效):
java -Djdk.serialFilter=!org.apache.commons.collections.functors.*,!org.apache.commons.collections.map.TransformedMap,!org.apache.commons.collections.map.LazyMap,!com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl -jar app.jar - 代码层面配置(局部生效):
ObjectInputStream ois = new ObjectInputStream(inputStream); // 设置过滤器,禁止 CC 关键类 ois.setObjectInputFilter((filterInfo) -> { String className = filterInfo.serialClass().getName(); if (className.startsWith("org.apache.commons.collections.functors.") || className.equals("org.apache.commons.collections.map.TransformedMap")) { return ObjectInputFilter.Status.REJECTED; // 拒绝反序列化 } return ObjectInputFilter.Status.ALLOWED; }); ois.readObject();
3. 依赖层面:升级 Apache Commons Collections 到安全版本
- CC 3.x 系列:升级至 3.2.2 及以上(修复
InvokerTransformer危险反射); - CC 4.x 系列:升级至 4.1 及以上(修复
InstantiateTransformer危险实例化); - Maven 配置示例:
<dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.2</version> <!-- 安全版本 --> </dependency>
4. 工具层面:检测与监控
- 静态检测:使用代码扫描工具(如 FindSecBugs、SonarQube)检测代码中是否存在
ObjectInputStream.readObject()处理不可信数据的场景; - 动态监控:部署应用防火墙(WAF)或运行时监控工具(如 AppSensor),监控异常的序列化流量(如包含 CC 关键类的 payload);
- POC 验证:使用
ysoserial(Java 反序列化漏洞测试工具)生成 CC 链 POC,验证应用是否存在漏洞(需授权测试)。
五、总结与启示
CC 系列漏洞从 1 到 7 的演进,体现了攻击者对 Java 反序列化机制与第三方库的深度挖掘——从依赖单一类到组合 JDK 内置类,从明确触发条件到隐蔽触发逻辑,攻击链的兼容性与隐蔽性持续增强。
对企业而言,防御的核心并非“针对某一条 CC 链”,而是建立“反序列化安全治理体系”:
- 优先避免使用 Java 原生序列化,采用安全协议;
- 若必须使用,通过
serialFilter严格限制反序列化类; - 定期升级第三方依赖,修复已知漏洞;
- 结合静态检测与动态监控,形成全生命周期防护。
只有从“源头阻断风险”而非“被动防御攻击链”,才能真正抵御 Java 反序列化这类“基础性漏洞”的威胁。
更多推荐

所有评论(0)