
أداة إثبات مفهوم قابلة للتشغيل لإعادة إنتاج CVE-2026-101259، تُظهر الكشف عن رسائل الخطأ في مستهلكي camel-coap في Apache Camel على Spring Boot وQuarkus، بالإضافة إلى التحقق من الإصلاح.
مُثبِت إثبات مفهوم قابل للتشغيل (PoC) لثغرة Apache Camel حيث، عندما تعذّر على مستهلك CoAP
بناء استجابته بعد اكتمال المسار، التقط CamelCoapResource الاستثناء الناتج
وأعاد إرسال رسالته إلى عميل CoAP كحمولة (payload) لاستجابة 5.00 Internal Server Error:
} catch (Exception e) {
cexchange.respond(ResponseCode.INTERNAL_SERVER_ERROR, e.getMessage());
}
| وقت التشغيل | الدليل | المكدّس |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-coap 4.22.1 |
| Camel Quarkus | camel-quarkus/ | Camel Quarkus 3.39.0 (Quarkus 3.39.0, Camel 4.22.0) |
يحوّل المستهلك جسم الرسالة النهائي إلى حمولة byte[]، ويحوّل ترويسات CamelCoapMaxAge وCamelCoapETag إلى أنواعها، بعد عودة المسار — وبالتالي خارج معالج أخطاء المسار. لا يمكن لـ onException داخل المسار التقاط ذلك، لأن الفشل يحدث في المستهلك، وليس في المسار.
cd camel-spring-boot # or: cd camel-quarkus
mvn clean package
docker compose up -d --build
until [ "$(curl -s http://localhost:8080/exploit/ready)" = "Started" ]; do sleep 1; done
curl -s http://localhost:8080/exploit/attack
docker compose down
الإخراج على بناء متأثر (متطابق على كلا زمني التشغيل):
1) Converting the body to the byte[] payload fails once the route has completed
CoAP GET coap://127.0.0.1:5683/reading
response code : 5.00 (INTERNAL_SERVER_ERROR)
response payload : Error during type conversion from type: com.example.FailingBackendStream to the
required type: byte[] with value com.example.FailingBackendStream@5eede7d7 due to
java.io.IOException: connection to prod-db.internal:5432 reset while streaming
sensor_readings for node edge-gateway-07.dc2.internal
2) The CamelCoapMaxAge header cannot be converted to its type
CoAP GET coap://127.0.0.1:5683/reading-maxage
response code : 5.00 (INTERNAL_SERVER_ERROR)
response payload : Error during type conversion from type: java.lang.String to the required type:
java.lang.Long with value not-a-number due to java.lang.NumberFormatException:
For input string: "not-a-number"
3) A route that simply fails
CoAP GET coap://127.0.0.1:5683/reading-failing
response code : 2.05 (CONTENT)
response payload : partially built response
What a remote CoAP client learned from these responses:
the backend host and port, out of the cause's message : true
class names of the cause : true
the source and target types of the conversion : true
the string form of the offending value : true
a failed route answered with a SUCCESS code : true
>>> PROVEN: ...
رسالة هذا الفشل تُسمّي صنف القيمة التي يجري تحويلها، وتحمل الصيغة النصية للقيمة، وتنتهي باسم الصنف ورسالة السبب الجذري — لذا قرأ عميل CoAP بعيد أسماء الأصناف والحزم، والصيغة النصية للقيمة، وكل ما يحمله السبب، والذي قد يشمل عمليًا المسارات وأسماء المضيفين وتفاصيل اتصال الواجهة الخلفية. ولم يكن لدى المستهلك أي خيار لكتم هذا، على عكس مستهلكي HTTP الذين يوفّرون muteException لهذا الغرض.
الفحص 3 هو النصف الثاني من المشكلة. لم يُرسَل الاستثناء الذي أثارته مسار فاشل على الإطلاق: فلم يتحقق المستهلك مما إذا كانت المبادلة قد فشلت، وأجاب على فشل مسار بـ 2.05 Content وأي جسم كان تحمله الرسالة عند تلك النقطة — رمز نجاح لمسار فاشل.
أمر واحد كان على هذا المُعيد إتقانه: جسم لا يوجد له محوّل ليس كافيًا. إذ يُرجع
getBody(byte[].class)القيمةnullفي تلك الحالة بدلًا من إثارة استثناء، ثم يجيب المستهلك بـ2.05مع حمولة فارغة — دون أي إفصاح. يجب أن يفشل التحويل، لا أن يكون غير متاح، ولهذا يستخدم الفحص 1 جسم تدفق يُثير استثناءً في منتصف عملية قراءة. أما فحص الترويسة فيفشل بالطريقة الأخرى، عبر قيمة ذات شكل خاطئ.
يتطلب الوصول إلى الإفصاح مسارًا يستطيع عميل بعيد جعل استجابته المكتملة غير قابلة للتحويل، وهو ما يعتمد على طريقة كتابة المسار. لا شيء هنا مُصادَق عليه، وطلبات CoAP GET العادية هي كل ما يرسله العميل.
| الخاصية | القيمة |
|---|---|
| المكوّن | camel-coap (CamelCoapResource) |
| CWE | CWE-209 (توليد رسالة خطأ تحتوي على معلومات حساسة) |
| الخطورة | متوسطة |
| ناقل الهجوم | طلب CoAP إلى مستهلك لا يمكن بناء استجابته المكتملة — جسم يفشل تحويله إلى byte[]، أو ترويسة CamelCoapMaxAge / CamelCoapETag تفشل في التحويل |
| التأثير | يقرأ عميل CoAP بعيد أسماء الأصناف والحزم، والصيغة النصية للقيمة، ورسالة السبب الجذري — وعمليًا المسارات وأسماء المضيفين وتفاصيل اتصال الواجهة الخلفية |
| الإصدارات المتأثرة | من 4.0.0 قبل 4.18.5، ومن 4.19.0 قبل 4.22.2 |
| الإصدارات المُصلحة | 4.18.5، 4.22.2، 4.23.0 |
| JIRA | CAMEL-25087 |
| الفضل | Zhixi "Jace" Sun، باحث أمني مستقل |
الإشعار الأمني: https://camel.apache.org/security/CVE-2026-101259.html
يكتسب المستهلك خيار muteException — على نقاط النهاية coap وcoaps وcoap+tcp وcoaps+tcp
على حد سواء — وهو يفترض القيمة true افتراضيًا على جميع خطوط الإصدارات المُصلحة الثلاثة، لذا يكفي الترقية بحد ذاتها
ولا حاجة إلى أي تغيير في الإعدادات. لا يزال المستهلك يجيب بـ 5.00 Internal Server Error، لكن بحمولة
فارغة، وهو الآن يبلّغ عن الاستثناء عبر معالج استثناءات المستهلك، لذا فإن كتمه
لا يخفيه عن المشغّل.
كما يتحقق مما إذا كانت المبادلة قد فشلت، ويجيب على فشل مسار بـ 5.00 Internal Server Error
وفق القاعدة نفسها، حيث كان يجيب سابقًا بـ 2.05 Content.
أُصلح على main في apache/camel#26994 (2245feac)، ونُقل إلى
camel-4.22.x في #27046 (868d5604) وإلى camel-4.18.x
في #27048 (aaf5bbf8).
اضبط camel.version على 4.22.2 وشغّله مرة أخرى. تم التحقق مقابل 4.22.1 → 4.22.2:
1) ... response code: 5.00 (INTERNAL_SERVER_ERROR) response payload : <empty>
2) ... response code: 5.00 (INTERNAL_SERVER_ERROR) response payload : <empty>
3) ... response code: 5.00 (INTERNAL_SERVER_ERROR) response payload : <empty>
>>> NOT reproduced: the error payload was empty.
يغيّر Probe 3 أيضًا الشيفرة، من 2.05 Content إلى 5.00 Internal Server Error — فأصبح فشل المسار الآن
يُجاب عنه كفشل.
تأكد من أن الاستجابة يمكن بناؤها دائمًا بمجرد اكتمال المسار: حوّل الجسم إلى byte[] أو
String كخطوة أخيرة في كل مسار يستهلك من نقطة نهاية coap (convertBodyTo)، وأعطِ
ترويسات CamelCoapMaxAge وCamelCoapETag قيمًا من أنواعها الخاصة فقط، وأضف معالج onException
يعلّم الفشل كمُعالَج ويضبط جسم الاستجابة صراحةً — بحيث يُرفع فشل التحويل
ويُستبدل داخل المسار بدلًا من المستهلك.
نُشر هذا المستودع لأغراض تعليمية ودفاعية: لمساعدة مستخدمي Apache Camel على فهم الثغرة، والتحقق مما إذا كانوا متأثرين بها، وتأكيد أن الترقية تحلّها. لا تستخدم هذه المواد ضد أنظمة لا تملكها أو لا تديرها.