Relevant Identifiers:ZDI-10-056,
CVE-2010-0840 Impact:Privilege escalation of the Java security sandbox. The most obvious target would be the Java Runtime running Java Applets, JavaFX and Java Web Start applications in a web browser. Untrusted code will gain full privileges of the user executing the browser process.
Oracle Java Patch:http://www.oracle.com/technology/deploy/security/critical-patch-updates/javacpumar2010.htmlSteps to remedy:Update to Java 6 update 19
Details:Java code originating from the Java core classes in the JRE/lib directory is considered trusted.
Java code originating from an unsigned Java applet is considered untrusted.
When Java evaluates privileges for any given operation, it considers the whole method call stack.
For each item on the stack, the privileges of the class that defined the method in question are considered. Thus, if class Foo defines method call() and class Bar is a subclass of Foo, and an instance of Bar is on the stack, and the method is call(), the privileges of Foo, not Bar, are considered.
It is possible to implement interface methods with methods inherited from a superclass; For example, if interface CacheItem has void method delete() and class Folder, which implements no interfaces, has a method with a compatible signature, it is possible to create a concrete class FolderPosingAsACacheItem which extends the Folder class, and implements the CacheItem (with the inherited method) without defining any methods of its own.
There are hundreds (thousands?) of trusted classes in the Java core that call methods on objects which can be defined by untrusted code either directly, via sub-classing or via deserialization.
These methods can be arranged in such a way that a trusted thread (such as one of the event threads) may be chained into calling method A which calls method B which calls method C ... which calls method Z. As only trusted code will be on the calling stack, the privileged context of the trusted thread is maintained. If one finds a method Z that does something interesting, such as a parameterizable method invocation via reflection, that invocation will take place in a privileged context.
This is very bad because it means that security relies that there not exist harmful combinations of methods signatures; something that is not feasible to control, as opposed to the very controlled model of having a number of doPrivileged blocks which are known to be dangerous, but relatively easy to control.
ZDI-10-056/CVE-2010-0840 leverages this by creating a trusted chain as follows:
- instantiate a vuln.Link (subclass of java.beans.Expression) pointing the invoke params to class: java.lang.System, method setSecurityManager, args: null
- instantiate a new java.util.HashSet and put the vuln.Link (which is also a Map.Entry) in the Set
- instantiate an anonymous subclass of HashMap where the entrySet method returns the instance defined above
- instantiate a javax.swing.JList object, passing the HashMap instance defined above as the list contents
- add the JList on any visible component (such as the applet itself)
And here's what happens when the digital Rube Goldberg machine is set into motion:
- the GUI thread wants to draw the JList and calls JList.paint(Graphics)
- JList while drawing itself, calls toString on the list contents, including said anonymous subclass of HashMap
- HashMap inherits AbstractMap's toString method which calls entrySet().iterator() and iterates the resulting Set
, calling getValue on each Entry
- one of the Entry objects returned by the implementation is a subclass of Statement, which implements the Entry interface's getValue() method with the Statement.getValue()
- Expression.getValue() calls Statement.invoke()
- Statement.invoke() has been parametrized to call System.setSecurityManager(null) via reflection
...and Java security gets switched off.
Safety First:
The vuln.Link class cannot be created with a normal Java compiler. Hopefully that'll keep the virus writers at bay, while the details enlighten the security community.
The Fix:
Based on my very brief analysis, Java 6 update fixes this problem by altering the Statement.invoke() to use the AccessControlContext captured at the moment of instantiation when it uses the reflection.