Yesterday I spotted the news about a new Java 0day being exploited in the wild and soon after a POC was released: http://pastie.org/4594319.
I decided to analyse this code to understand what is the vulnerability that triggers the exploit. Here is a brief description of my findings.
The code instantiates a Statement object that will be used to run the setSecurityManager() method of the System class. The purpose is to set the Security Manager to null, which means escaping the Java sandbox. Of course, you can't do this directly and here comes the exploit!
The Statement object contains a field named "acc", which is a AccessControlContext (a sort of security descriptor) that specifies the permissions allowed for the Statement object itself. This field is normally not accessible from the code outside the Statement class, so the exploit needs to find a way to modify it.
It does so by using the getField() method of the sun.awt.SunToolkit object: this function returns a given field from a given object; in this case it returns Statement.acc. At this point the game is over because the malicious code can just create a new AccessControlContext object, assign to it full permissions and then replace the old restricted Statement.acc with the new unrestricted one.
Mistery solved? Not yet: the tricky part is in obtaining an instance of the object sun.awt.SunToolkit, that is supposed to be a restricted package. The exploit does this by calling Class.forName(); this method simply returns an object from its name.
This is how I understand the code (and I'm no Java expert), but I read this blog entry that has a slightly different explanation. In their analysis, the authors see another method that accomplishes the task: com.sun.beans.finder.ClassFinder.
I don't know what this is about: do they have a different POC or sample? It does seem so!
Also they say that the exploit itself relies on the possibility of instantiating the sun.awt.SunToolkit object through the com.sun.beans.finder.ClassFinder object. This would mean that in the POC I have analysed the vulnerability is in the Class.forName() method, that is, there are TWO different vulnerabilities (one in ClassFinder and one in Class.forName()).
However, debugging the exploit in Java version 1.6 (jre6) it did not work: the Class.forName() object successfully instantiated the sun.awt.SunToolkit object, but then the use of its getField() method threw an exception. Instead, the method works fine in version 1.7 (jre7). To make it short:
So, even if version 1.6 allows the instantiation of the sun.awt.SunToolkit object, it prevents it from accessing the private Statement.acc field, which seems correct. It seems that the bug is really in version 1.7, in the access to the Statement.acc. Or maybe none of the two is supposed to happen: sun.awt.SunToolkit must not be instantiated to restricted code, and the Statement.acc field must not be accessed by anyone.
I will look forward to new results.
*UPDATE* [28 August 2012]
1) Now we can refer to the above vulnerability as "CVE-2012-4681".
2) A new analysis, based on the same POC I documented, has been published today: http://thexploit.com/sec/java-facepalm-suntoolkit-getfield-vulnerability/ . So, yes, it seems that getField() is the culprit, or at least it's one of them...
*UPDATE 2* [28 August 2012]
A more in-depth analysis is finally out: http://immunityproducts.blogspot.com.ar/2012/08/java-0day-analysis-cve-2012-4681.html
As I though there are two different 0days: one that allows you to get a reference to the restricted class sun.awt.SunToolkit, and the other one (getField()) that lets you access a private field of a class. The missing detail (classFinder()) is also solved: it is used in the internal implementation of the execute() method of the Expression object.