Java (JSP) - Bring Your Own Jar
On this page, we will explore how to reflectively load a class from a Java library and call its main method. In red team context, this can be used to stage additional java code without touching disk.
TL;DR
Final proof of concept can be found here.
Introduction
As red team operators, we are often challenged with situations where a certain service is vulnerable and perhaps even has a public proof of concept, but one look at the exploit code is enough to know that it will likely cause all the alarms to go off on the blue team side. This is not the way we like to make an entry (initial foothold) and put the SOC on alert in the beginning of the exerices.
What if this exploitable target is some java application? If the situation allows for it, we could opt for some Java memshell, which usually registers a servlet for you to interact with from Java. This already seems to rely on some dynamic class loading. Some examples:
However, if feels like a complicated setup and often does not immediately bootstrap your favourite C2 framework. So what would be the shortest route to achieve that from inside - let's say - a JSP file? Reflective DLL loading existed on Windows for a long time so why not reflective jar loading?
Reflective Jar Loading
First of all, this is not intended as a malicious proof of concept. There are legitimate use cases for loading libraries dynamically without dropping these to disk first. For example, one could use this technique to decrypt encrypted java jars at runtime as a way of protecting against reverse engineering.
Neither is this a new technique. There are public code snippets that can help develop an implementation of this (e.g. this). Nor am I the first one to explore this topic. As always, a random stranger on the internet, in our case Holger, posted it in ten years ago on StackOverflow. Credit goes to him for the least complex and most portable implementation, which we will use in our proof of concept. There is also this amazing article by DiabloHorn, which I discovered after writing this post.
Dynamic Class Loading in MetaSploit
Before we start porting Holger's class loader to JSP, let's dig into the MetaSploit implementation first. I have this really old vulnerable ActiveMQ server running on Windows, which I sometimes use to experiment with Java webshells. Conveniently, MetaSploit already has an exploit for this, which we can point and run against the target. It's a path traversal file upload, which allows you to drop executable files at remotely accessible paths. Classic webshell drop scenario.
Upon execution of the exploit, it drops two files to disk:
A JSP with a randomized name.
A .jar file with a randomized name
Dynamic Class Loading from Disk
The JSP will look something like shown below. When accessing https://host:8161/api/random.jsp, the webshell will be triggered. First, it loads a random.jar file, which was also dropped to disk. From this jar, it dynamically loads the MetaSploit.Payload class and calls the main method of this class.
After this, Meterpreter loudly announces its presence to all EDRs on the system and attempts to establish an egress connection. However, EDR/SOC might not agree.
Custom Jar
Perhaps we should replace the Meterpreter jar file that the exploit drops to disk with our own, more customized way of staging any C2 shellcode we want from inside Java. I am using a fat jar with JNA (Pinvoke alternative for Java). It's essentially a native shellcode stager ported to Java. Have a look at this to get the idea. Explaining our loader may be material for a future blog post if I ever find the time.
However, I'll say this: Do we really want to drop this jar to disk, where AV can scan it, sandboxes can start analysing it and most notably, we have to clean it up after the engagement? Nope.
Fetch Remote Jar
Fortunately, if egress HTTPS traffic is allowed, we won't have to drop anything to disk. The following JSP code snippet is perfectly capable of reading a remote jar file and saving it to the buffer
ByteArray.
Extracting Classes
Next, we need to loop over entries in our jar file and extract classes into a map.
Custom ClassLoader
After this, we should implement our custom Class Loader. Why can't we use the standard ClassLoader for this? Holger explained it quite well in his StackOverflow reply:
Loading classes from such a representation doesn’t work out-of-the-box because the standard
ClassLoader
implementations rely on theJarFile
implementation which relies on a physical file rather than an abstraction.So unless you simply write the buffer into a temporary file, it boils down to implement your own
ClassLoader
. Since the JRE supports only stream access as shown above, you will have to scan linearly to find a requested resource/class or iterate once and store the entries into aMap
.One alternative to implementing a
ClassLoader
is to implement a customURL
handler to use together with aURLClassLoader
which reduces the task to the lookup as described above
Since we're loading the classes from a Map in memory, we can build a custom URLStreamHandler
which will return a URLConnection
to the appropriate class.
Finally, we can construct a URLClassLoader
with our custom URLStreamHandler
, after which we can instantiate our custom com.nativewin32.MyClass
object and invoke the main method.
Final POC
Moments after uploading and accessing this custom jsp page, our custom jar file is downloaded again.
The Jar file loads our shellcode in the current process (java.exe) to avoid spawning suspicious subprocesses which have a higher risk of triggering endpoint detection.
We successfully injected Meterpreter shellcode into the java.exe process using our custom jar. To validate, we check our process ID. Of course, this could have been any your favourite C2 framework as well. You can Bring Your Own Jar.
Potential Improvements
Feel free to make a PR if you would like to implement any of these:
TLS support
Encrypt/Decrypt remote jar with AES
Error handling
Test on Linux (works in theory)
Detections
As always, keep track of JSP and other executable files being written to disk via web processes.
I also embedded a signature in the webshell. Scan the file for the following string:
87c30278b52d957fc722ca030e020b726f40be2c
References
Last updated