Java Pwn2Own

James Forshaw - 19th April 2013      

On 16th April Oracle released Java 7 Update 21 (which you should install now if you haven’t already!) This release fixes all the Java vulnerabilities disclosed to Oracle during the recent Pwn2Own 2013 competition held at the CanSecWest security conference in Vancouver on the 6th March 2013, alongside a significant number of other bugs.

I was the first winner of the Java exploit competition at this event, and this blog provides an both an overview of my winning entry, and an insight into just how difficult it is to fully secure a complex system such as Java against a determined attacker.

But let’s start with the bug itself, CVE-2013-1488, which is surprisingly innocuous and one which could easily be missed during a code security review. It was an issue I found in the java.sql.DriverManager class which is a trusted part of the framework. As the documentation states this class’s purpose is for “… managing a set of JDBC drivers.” and is an extensible Java framework for accessing relational databases. Within the source code> for this class a Java vulnerability hunter would be drawn to the two AccessController.doPrivileged blocks like a moth to a flame, they allow the Java libraries to temporarily elevate its privileges to perform a security critical action. The first block does not do very much (it simply gets a system property) but the second one is far more interesting:

Figure 1
Figure 1

The reason this code is interesting is because it is performing a non-trivial task during this block of elevated privileges. Even more importantly, an attacker can directly interact with this process because of the use of the ServiceLoader class which will instantiate a sequence of objects from a manifest of class names provided in the applet’s JAR file.

Figure 2
Figure 2

That in and of itself might not be massively helpful to an attacker, mainly because all objects created have to implement the java.sql.Driver interface, so we cannot just find any arbitrary class and reuse it. We could try and find an existing driver which did something bad when created with its default ‘empty’ constructor, but doesn’t sound too likely either. But looking closer at the lines which are actually doing the work, there is something else interesting going on:

Figure 3
Figure 3

Whilst it isn’t immediately obvious these lines are doing a lot more than they seem, the code is actually looping through an “iterator” which creates each object from a list of class names in turn via the reflection API Class.newInstance(). It then concatenates that object with a string and tries to log the result (ironically by default there is no log enabled and this result is thrown away). Whilst it isn’t explicit in the code, and thus might be missed unless you are paying close attention, what this is actually doing is calling the toString method on every object it creates during a privileged block. To say this is probably bad is maybe understating the issue, but what can we do with it?

Exploiting this comes down to a variation of the “Trusted Method Chain” attack. This is a technique in platforms such as Java and .NET which allows an attacker to construct a chain of method calls from parts of the trusted Java class libraries and the JVM, which result in some action which circumvents security restrictions. I can’t claim credit for the discovery of this technique, and so for a better description in the Java world I would defer to the legendary Sami Koivu here.

The reason you need to do this is because unsigned Java code running in the browser plugin is untrusted. If you try and perform a security critical action (such as opening a file) the security manager installed to protect the sandbox will notice you and stop the action. But if all the calls on the stack are trusted (i.e. from built in classes) then the manager will trust you to perform the action, leading to the potential for a sandbox escape.

From this we need some way of going from a toString method call to a sandbox escape, and that doesn’t sound like it should be easy. But looking over the history of Java exploitation, it turns out there are a number of examples of doing just this, the previous link to Sami’s blog has one (fixed obviously) and there is another very well-known one related to the Rhino Javascript Engine, CVE-2011-3544 discovered by Michael Schierl (which is also fixed). So a similar technique might be worth pursuing in this case, perhaps if we could create a Javascript Error object in a similar fashion to CVE-2011-3544 it would work for us, we could get it called by DriverManager and we could escape the sandbox?

But how could we do that, as I’ve just said this has been fixed? Well “yes”, but perhaps not in the way you would expect. The actual implementation of the Rhino Script Engine NativeError class wasn’t changed; instead the script engine code was modified to ‘capture’ the access control context under which it was instantiated during its default constructor. Any Javascript method is then run within an AccessController.doPrivileged block with the captured context, so that the Javascript code can only ever do as much damage as the thing which created it. This means that, if untrusted Java applet code created the engine, all Javascript would run at most with the applet’s permissions. However what if the engine was created by trusted code running with elevated permissions? Well, if we look at the code for the RhinoScriptEngine class we can actually see the fix in action:

Figure 4
Figure 4

If running in a sandbox, the constructor checks whether it is running under a fully privileged context, if it isn’t then an exception occurs and the current context is captured, otherwise accCtxt is left as its default value of null. When it comes to running Javascript code, if accCtxt is null then it is run with the permissions of the direct caller, which is exactly the scenario we want, as it breaks the fix applied to solve CVE-2011-3544 and allows us to repurpose the same technique to create our trusted chain. It is worth noting that this isn’t actually the original fix, its behaviour resulted in a code change which made it less vulnerable to these attacks, but as I will demonstrate it didn’t matter for this vulnerability.

So the final piece of the puzzle is how to create the RhinoScriptEngine class under a privileged context, well the answer has been staring us in the face all along: we can use our own ServiceLoader iterator combined with a Set class to create a trusted chain between the toString method and instantiation of the RhinoScriptEngine class. The reason this works is that the Set class’s toString method will iterate over the values of the iterator object, which, in turn, causes the ServiceLoader iterator to instantiate an attacker supplied list of objects. This list can then be recovered at a later time for the purposes of exploitation. Take, for example, the following class which implements the Driver interface and derives from AbstractSet but uses a “fake” iterator:

Figure 5
Figure 5

When called by the DriverManager code the order of operations is as follows:

Figure 6
Figure 6

Once the script engine object is created, we now just need a second driver which again derives from a Set class, this time we use it to call toString on our custom Error object, by adding it to the Set, and it’s “game over”:

Figure 7
Figure 7

In conclusion, to exploit that single, seemingly innocuous bug required repurposing a massive amount of unrelated code to disable the security manager and therefore break out of the sandbox. I guess that is why Oracle considering it to have a Medium Access Complexity within the CVSSv2 scoring scheme. But that is also why I think something like Java can never be secured against hostile code running within a sandboxed environment: the attacker has too much control to craft the environment to exploit the tiniest of weaknesses. The large amount of “trusted” code bundled with the JRE just acts to amplify that power.


© Copyright 2013 Context Information Security