
مُعيد إنتاج لـ CVE-2026-40860 — Apache Camel camel-jms/sjms/amqp إلغاء تسلسل غير آمن لكائنات JMS ObjectMessage (RCE)
يعرض هذا المشروع ثغرة إلغاء تسلسل في Java في مكوّن camel-jms الخاص بـ Apache Camel
(وبالتبعية في camel-sjms، وcamel-sjms2، وcamel-amqp، وcamel-activemq، وcamel-activemq6)،
وتُتتبَّع باسم CVE-2026-40860. يقوم JmsBinding.extractBodyFromJms() بإلغاء تسلسل حمولة رسالة JMS
ObjectMessage الواردة عبر ObjectMessage.getObject() بدون أي ObjectInputFilter أو قائمة سماح
أو قائمة منع للفئات. ولأن هذا التنفيذ يحدث كلما كان mapJmsMessage=true (الوضع الافتراضي) وكانت Camel مستهلكًا لـ JMS،
فإن أي مهاجم قادرًا على نشر ObjectMessage مزيّفة إلى قائمة انتظار/موضوع مستهلك يمكنه تحقيق تنفيذ برمجي عن بُعد
عند وجود سلسلة أدوات (gadget chain) على مسار الفئات (classpath).
الإشعار الأمني: https://camel.apache.org/security/CVE-2026-40860.html
// JmsBinding.extractBodyFromJms(Exchange, Message) - affected version
if (message instanceof ObjectMessage objectMessage) {
Object payload = objectMessage.getObject(); // <-- deserializes with no ObjectInputFilter
if (payload instanceof DefaultExchangeHolder holder) {
...
}
return payload;
}
يستدعي getObject() أسلوب ObjectInputStream.readObject() الخاص بمزوّد JMS على جسم الرسالة. ولا يضيف Camel أي تصفية فئات خاصة به، لذلك يتم تنفيذ سلسلة أدوات (gadget chain) موجودة على مسار الفئات أثناء إلغاء التسلسل.
يضيف الإصلاح (4.14.7 / 4.18.2 / 4.20.0) قائمة سماح افتراضية عبر ObjectInputFilter (java.**;javax.**;org.apache.camel.**;!*)، ويمكن تخصيصها عبر خيار نقطة النهاية الجديد deserializationFilter أو عبر خيار JVM العام -Djdk.serialFilter. إليك نص رسالة الالتزام الخاصة بـ Camel لهذا الإصلاح:
يتم هذا الفحص بعد أن يكون مزوّد JMS قد ألغى تسلسل الحمولة بالفعل. فهو يمنع الفئات غير المتوقعة من الانتشار إلى المسار، لكنه لا يستطيع وحده إيقاف سلاسل الأدوات التي يتم فيها استدعاء
readObject()داخلObjectInputStreamالخاص بالمزوّد. تتطلب الحماية الكاملة ضبط مرشّح إلغاء التسلسل الخاص بمزوّد JMS و/أو-Djdk.serialFilterالعام على مستوى JVM.
إذًا الحماية الكاملة = ترقية Camel + تقييد مرشّح المزوّد / JVM. يستخدم هذا الإثبات المفاهيمي (PoC) عميل ActiveMQ مع trustAllPackages=true (وهو إعداد شائع في البيئات الحقيقية) لكي يقوم المزوّد بإلغاء تسلسل الحمولة؛ وعلى إصدار Camel المتأثر لا يوجد أي حاجز آخر.
from("jms:queue:evil") // mapJmsMessage defaults to true
.log("Consumed: ${body.class.name}");
مجرد استلام ObjectMessage يؤدي إلى تشغيل إلغاء التسلسل — ومحتوى المسار غير ذي صلة.
الضحية هي مستهلك Camel JMS. أما المهاجم فهو أي مُنتِج يمكنه النشر إلى قائمة الانتظار. يتواصل كلاهما مع وسيط Apache ActiveMQ Artemis حقيقي يعمل في Docker.
CVE-2026-40860/
├── pom.xml # camel-jms 4.18.1 + activemq-client 6.2.4 + commons-collections 3.2.1 (gadget)
├── Dockerfile # runs the app (--add-opens only to build the gadget)
├── docker-compose.yml # Artemis broker (quay.io) + the reproducer app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── JmsConfig.java # OpenWire ConnectionFactory (trustAllPackages=true) + jms component
│ ├── VictimRoute.java # victim: from("jms:queue:evil")
│ ├── Gadget.java # CommonsCollections6 gadget, fires during getObject()
│ └── ExploitController.java # attacker: publishes ObjectMessage(gadget) to the queue
└── resources/
└── application.properties
في هجوم حقيقي، يتم إنتاج البايتات المسلسلة دون اتصال من قبل المهاجم (مثلًا باستخدام ysoserial)؛ فقط الضحية تحتاج إلى سلسلة الأدوات على مسار الفئات. يبني هذا الإثبات المفاهيمي الأداة داخل العملية من أجل الراحة، ولهذا يعمل JVM مع
--add-opens java.base/java.util=ALL-UNNAMED— وهو تفصيل خاص ببناء الأداة، لا علاقة له بالثغرة.
mvn clean package -DskipTests
docker compose up -d --build
يؤدي هذا إلى تشغيل وسيط Artemis (quay.io/artemiscloud/activemq-artemis-broker) وتطبيق إعادة الإنتاج،
الذي يتصل به عبر OpenWire.
curl -s http://localhost:8080/exploit/attack
# -> ObjectMessage published to queue 'evil'.
# camel-jms consumer called ObjectMessage.getObject() -> deserialization.
#
# >>> RCE proof — /tmp/pwned exists: true
docker exec cve-2026-40860 ls -la /tmp/pwned
docker compose down
أي مستهلك Camel JMS (camel-jms، camel-sjms، camel-sjms2، camel-amqp، camel-activemq،
camel-activemq6) يقرأ من وجهة يمكن للمهاجم النشر إليها — وسيط مشترك، أو موضوع بمُنتِجين مفتوحين، أو قائمة انتظار
تغذّيها جهة علوية غير موثوقة — مع mapJmsMessage=true (الافتراضي).
mapJmsMessage=true (الافتراضي).ObjectMessage في الوجهة المستهلكة.trustAllPackages=true، أو مزوّد بدون مرشّح تقييدي).commons-collections:3.2.1).قم بترقية Camel إلى 4.14.7 / 4.18.2 / 4.20.0، وقيّد عملية إلغاء التسلسل من البداية إلى النهاية:
-Djdk.serialFilter=java.**;org.apache.camel.**;!* (أو خيار نقطة النهاية الجديد deserializationFilter).trustedPackages، ولا تستخدم trustAllPackages=true).إلى حين الترقية:
ObjectMessage؛ واضبط mapJmsMessage=false عندما تكون الرسالة الخام مقبولة.trustAllPackages=true على وجهات غير موثوقة.-Djdk.serialFilter.تم توفير هذه الأداة لإعادة الإنتاج لأغراض البحث الأمني والاختبار المصرّح به فقط، وذلك لثغرة تم الكشف عنها وإصلاحها علنًا. لا تستخدمها ضد أي أنظمة دون إذن صريح.
| الخاصية | القيمة |
|---|
| المكوّنات | camel-jms (+ camel-sjms, camel-sjms2, camel-amqp, camel-activemq, camel-activemq6) |
| الفئة المتأثرة | org.apache.camel.component.jms.JmsBinding#extractBodyFromJms → jakarta.jms.ObjectMessage#getObject() |
| CWE | CWE-502: إلغاء تسلسل بيانات غير موثوقة |
| الأثر | تنفيذ برمجي عن بُعد (RCE) |
| آلية التفعيل | مستهلك Camel JMS + mapJmsMessage=true (الافتراضي) + ObjectMessage يمكن للمهاجم إدراجها |
| الإصدارات المتأثرة | من 3.0.0 حتى ما قبل 4.14.7، ومن 4.15.0 حتى ما قبل 4.18.2، ومن 4.19.0 حتى ما قبل 4.20.0 |
| الإصدارات المُصحَّحة | 4.14.7, 4.18.2, 4.20.0 |
| JIRA | CAMEL-23321 |
| المُبلِّغ | Venkatraman Kumar (Securin) |