ActiveMQ 是一个开源的消息传递和集成模式服务器,它包含支持 JMS 的代理(Broker),不仅可以在 Java 环境中使用,还能够实现使用多种语言的系统之间的通信。此外,通过集群功能、数据库以及文件系统,它维护了各系统之间的一致性和持久性。
OpenWire 是 Apache ActiveMQ 使用的一种二进制消息协议。它专为代理(ActiveMQ)与客户端之间的高效数据传输而设计。
CVE-2023-46604 是 ActiveMQ 中 OpenWire 协议(在 Marshal 过程中)的一个漏洞,具有网络访问权限的远程攻击者可以通过操纵 OpenWire 协议中序列化的类类型,执行任意 Shell 命令,从而使得客户端或代理(各自)能够实例化类路径上的任何类。这也是 APT 组织 Andariel 典型使用的攻击方式之一。
CVE-2023-46604 通过在 OpenWire 协议的数据收发过程中操纵 XML 调用或插入恶意数据来执行远程命令。OpenWire 协议主要处理数据序列化和传输,漏洞利用的是在序列化过程中允许恶意类类型这一点。
[图] POC
[图] XML
接下来我们通过分析 ActiveMQ 5.17.3 中发送到 OpenWire 协议的数据包来了解。首先,在分析数据包之前,需要先了解数据包的格式。数据包 Header
+----------------------------------------------------------------------------------+
| Packet Length | Command | Command Id | Command response required | CorrelationId |
|---------------|---------|------------|---------------------------|---------------|
| 00000066 | 1f | 00000000 | 00 | 00000000 |
+----------------------------------------------------------------------------------+
数据包 Body
+--------------------------------------------------------------------------------------+
| not-null | not-null | classname-size | classname | not-null | message-size | message |
|----------|----------|----------------|-----------|----------|--------------|---------|
| 01 | 01 | 0043 | ..... | 01 | 0012 | ..... |
+--------------------------------------------------------------------------------------+
OpenWire 数据包 Body 格式
[=If not-null is 1===========]
+----------+ [ +-------+----------------+ ]
| not-null | [ | size | encoded-string | ]
+----------+ [ +-------+----------------+ ]
| byte | [ | short | size octects | ]
+----------+ [ +-------+----------------+ ]
[============================]
[图 1] WireShark OpenWire 数据包检查
图1 所示的是包含上述数据包 Header、Body 格式的实际 Payload(为方便起见,不是通过原有的 POC 方式中的 ClassPath 调用,而是通过 FileSystem 调用)。接下来我们将在代码中更详细地了解这些数据包内容是如何作用的,以及为什么要这样发送。
[图 2] 数据包 Header 的含义
分段解析数据包 Header
+----------------------------------------------------------------------------------+
| Packet Length | Command | Command Id | Command response required | CorrelationId |
|---------------|---------|------------|---------------------------|---------------|
| 00000066 | 1f | 00000000 | 00 | 00000000 |
+----------------------------------------------------------------------------------+
Packet Length : 00000066 / 像 OpenWire 这样的协议通常明确指定数据包长度。
Command : 1f / 用于指定 ExceptionResponse(31),31 的十六进制表示为 1f。
Command Id : 00000000 / 为 int 类型,4 字节,十六进制表示为 00 00 00 00。
Command response required : 00 / 布尔类型,True(01)、False(00),此处为 False。
CorrelationId : 与 Command Id 类型相同。
图2 是为了帮助理解上述数据包 Header,补充了各个 Header 项的形式以及指定代码的说明。现在了解了 Header,我们通过 Body 内容来看一下它是如何通过代码的。
[图 3] 数据包 Body 的含义
分段解析数据包 Body 内容
+--------------------------------------------------------------------------------------+
| not-null | not-null | classname-size | classname | not-null | message-size | message |
|----------|----------|----------------|-----------|----------|--------------|---------|
| 01 | 01 | 0043 | ..... | 01 | 0012 | ..... |
+--------------------------------------------------------------------------------------+
not-null (01) | / 在图3的第一个函数中通过 not-null 检查
not-null (01) | classname-size (0043) | classname / 在图3的第二个函数中通过 not-null 检查,在第三个函数中用于大小检查
not-null (01) | message-size (0012) | message / 在图3的第二个函数中通过 not-null 检查,在第三个函数中用于大小检查
图3 展示了数据包 Body 中设置的值是如何起作用的。最终,通过图4,序列化的数据被用来加载并实例化类。
[图 4] 通过 createThrowable 执行 RCE
[图 5] RCE 计算器执行示例
[图 5] Git Diff (5.17.2 -> 5.17.6)
[图 5] validate 函数
与其它分析不同,我们分析该漏洞的攻击数据包是为了理解和学习攻击是如何实际执行的。
通过仔细检查数据包的结构和流程,我们能够清晰地识别攻击者入侵系统所使用的具体方法及其运作机制。
(nist) https://nvd.nist.gov/vuln/detail/cve-2023-46604
(POC) https://github.com/X1r0z/ActiveMQ-RCE/tree/main
(blog) https://attackerkb.com/topics/IHsgZDE3tS/cve-2023-46604/rapid7-analysis