This part is titled "Keys". The intention is to list the key items that must remain elusive to the attacker in order for the JVM to remain unharmed. Compromising any of these will probably give the attacker full privileges. I'll also show, at least in theory, how each of them could be used for this.
The Security Manager
The Security Manager is at the very core of the Java Security Model. It essentially decides whether any given operation is allowed or not. While the JVM is running, the "current" or "installed" Security Manager is defined by the static java.lang.System.security field. The type of the field is java.lang.SecurityManager which is a concrete, non-final class, so the SecurityManager is either an instance of that class, or a subclass. A null value in the field is interpreted as security being turned off, thus: if that field can be set to null, security will be turned off.
The field is private, though, so one can’t just waltz in and try to set it to null.
There's a public static method for defining a new Security Manager:
System.setSecurityManager(SecurityManager)
If that method is called with a null parameter, the underlying field will be set to null and security will be turned off. In order for that call to succeed though, the current Security Manager is consulted to see if the caller has the setSecurityManager RunTime permission. Thus, possessing the setSecurityManager permission effectively gives code full privileges.
It would not be necessary to set a null SecurityManager to defy security. If the attacker can define his own SecurityManager and set it as the current SecurityManager, he can allow all operations and elevate his privileges. Aside from accessing the System class, a Security Manager class can be defined with the JVM startup argument
-Djava.security.manager=EvilUnsecureManager
Also, compromising the (class) definition of the SecurityManager class or that of any of its subclasses would probably give the attacker full control. More about compromising class definitions in a later item.
ClassLoader
The ClassLoader is responsible for loading class definitions. It also ultimately controls the privileges of each class that's being loaded. The ClassLoader.defineClass(...) methods have the access modifier protected, so only subclasses can access them. If you can create a valid subclass of the ClassLoader, you can call the protected methods and define classes with full privileges. This is essentially how CVE-2008-5353 leverages the privileged deserialization.
An example of how to define a new class with full privileges when you have access to the defineClass method:
byte[] evilBytecode = …
AllPermission allPerm = new AllPermission();
PermissionCollection allPermissions = allPerm.newPermissionCollection();
allPermissions.add(allPerm);
Class cls = defineClass(null, evilBytecode, 0,
evilBytecode.length, new ProtectionDomain(null, allPermissions));
cls.newInstance();
Java access modifiers
The Java access modifiers (private/protected/"default"/public) for classes, fields and methods are probably the one single most important thing keeping the whole security together. I've personally used protected and default very little in code I've written for any normal project. However, the security architecture heavily relies on them.
A lot of things are kept inaccessible for an attacker by marking methods, fields and classes with the default access modifier. It means that only the classes from the same package can access those items. Same package here refers to same package within the same classloader. Thus, it doesn't aid the attacker to define his applet class to be in the same package as some trusted Sun class, because the packages are classloader specific - if your class in package abc was defined in a different classloader than another class in package abc, it is effectively in a different package as far as access control goes.
If the attacker gained access to private members, it would be possible to set null to java.lang.System.security and disable Java security.
If the attacker gained access to protected members, it would be possible to call defineClass on the default applet ClassLoader and define classes with full privileges.
If the attacker gained access to default members, there'd be a lot of members in any number of classes that could be accessed to gain full privileges. There are almost 40 different versions of a package-private class SecuritySupport (or SecuritySupport12) that does privileged file reading, property access, URL access and so on.
Reflection may be used to circumvent some of the access control restrictions. More about reflection in its own item.
The final keyword
As I discussed in a previous post, "final" has very distinct functions when used in conjunction with classes, methods and fields.
If the final modifier of a class could be overridden, in other words, if the attacker managed to subclass a final class, he might subclass java.lang.String and create his own mutable Strings. More about String immutability in its own item.
Overriding final methods and modifying the value of final field could also possibly be abused, but I have no concrete examples of those cases.
Type system integrity
Yet another crucial part of the security architecture is the Java type system integrity. If the attacker can pass his own Foo class where a String class is expected he can probably create the effect of mutable Strings.
Or reversely, if the attacker is able to put a Java system class in a variable whose type is Bar (a user controlled class), he can probably gain access to private members.
Reflection
Java Reflection API gives dynamic access to classes, fields and methods. If one is able to call setAccessible(true) on Field and Method objects, Java access control can be somewhat bypassed. If you call setAccessible(true) on an otherwise inaccessible field or method (private/protected/default) you gain access to it. Example:
Field security = System.class.getDeclaredField("security");
security.setAccessible(true);
security.set(null, null);
However, many of the Reflection API calls require privileges and if a Security Manager is installed the attacker won't get far. To successfully run the above example, one would need to possess the accessDeclaredMembers and suppressAccessChecks privileges.
If the attacker succeeds in obtaining a Field object for java.lang.System.security and calling setAccessible(true) on it, he can turn off Java security by calling field.set(null, null).
Privileged Deserialization
Privileged Deserialization can be leveraged by the attacker in (possibly) many ways, probably the simplest being the creation of a custom Serializable ClassLoader which can then be used to define classes with full privileges. This was at the core of CVE-2008-5353.
A privileged block which does deserialization from a stream which can be manipulated by the attacker can probably be leveraged in other ways, too, since the serialization/deserialization protocol is quite complex and flexible.
SecurityManager protected packages (sun., com.sun.deploy., etc)
These packages have a more relaxed security. The security manager and applet ClassLoader do not allow applets to access these packages directly. If the attacker was able to access them, there'd probably be several ways to leverage it. It seems to me that currently it is not allowed to reference the following packages:
com.sun.deploy.*
com.sun.imageio.*
com.sun.javaws.*
com.sun.jnlp.*
com.sun.xml.internal.bind.*
com.sun.xml.internal.ws.*
sun.*
System Properties
The System Properties (System.getProperties()) contain a lot of influential stuff. If an attacker was able to manipulate the System Properties he could probably elevate his privileges.
System.getProperties(), despite of the name which suggest read access, returns a reference to the internal Properties object, so any modification to this object will alter the system properties.
Read access to the properties has the implication of privacy. The attacker can find out the logged on username and several system paths:
java.class.path = C:\PROGRAM~1\Java\jre6\classes
java.endorsed.dirs = C:\Program Files\Java\jre6\lib\endorsed
java.ext.dirs = C:\Program Files\Java\jre6\lib\ext;C:\WINDOWS\Sun\Java\lib\ext
java.home = C:\Program Files\Java\jre6
java.io.tmpdir = C:\DOCUME~1\ADMINI~1\CONFIG~1\Temp\
java.library.path = ...
sun.boot.library.path = C:\Program Files\Java\jre6\bin
user.dir = …
user.home = C:\Documents and Settings\Administrator
user.name = Administrator
There are known cases where for example being able to alter the java.ext.dirs lead to a vulnerability. I imagine this type of an attack only works if you can provide the property at JVM startup.
sun.misc.Unsafe
Unsafe is in a sun. package and therefore inaccessible to applets. It also has a private constructor, and the singleton getter method checks that the caller's classloader is null (system class) before handing out the object, so one could say it is very well guarded. And for a reason, since it truly is the Chuck Norris of Java classes.
Unsafe allows direct access to fields and memory. It allows, for example, for you to put an int value into an object field. No security checks and no access control takes place when using Unsafe. So it would be trivial to leverage Unsafe for privilege escalation. I’ll leave the how as a mental exercise for the reader.
Field usf = Unsafe.class.getDeclaredField("theUnsafe");
usf.setAccessible(true);
Unsafe unsafe = (Unsafe) usf.get(null);
Field stringChars = String.class.getDeclaredField("value");
long offset = unsafe.objectFieldOffset(stringChars);
String test = "test";
char[] value = (char[]) unsafe.getObject(test, offset);
value[2] = 'n';
System.out.println(test);
String immutability
String immutability is the basis for many operations. String objects contain a private char array that normally cannot be accessed. Should the attacker be able to access the char array and modify String objects, a lot of things could be broken, probably the security, too.
There is no defensive programming in the core classes against mutable Strings, and for a reason; it’d require a lot of code. A mutable String could thus be used in a timing attack, having a set of contents for verification and another set of contents for the actual operation. String instances are also pooled and reused, so the attacker could probably put his instance on the pool and have it be reused by code that’s inaccessible to him.
doPrivileged
If the attacker can control a trusted doPrivileged block, or code called by it, through means of controlling input, accessed fields, overriding methods, subclassing, deserialization and classloading, etc, the attacker may be able to elevate his privileges.
(Re)defining core classes
If the attacker can compromise the class definitions of not just the most obvious classes (System, ClassLoader, SecurityManager), but any number of menial classes that participate in privileged blocks of code, the attacker could easily elevate his privileges. I'm currently working on a twist of this type of an attack which should lead to a privilege escalation.
Key Permissions
Every class has a set of permissions associated with it. The permissions depend on where the code comes from (CodeSource) and what the java.security defines as the permissions for that source. There are several permissions that, if an attacker can obtain them for his code, will (probably) lead to privilege escalation:
AllPermission: The permission to do anything.
setSecurityManager: The permission to define a new security manager, set the security manager to null and all code has full permissions.
charsetProvider: Allows for creating mutable strings.
accessDeclaredMembers & suppressAccessChecks: With the combination of these two permissions, you can obtain any field or method, make it accessible and access it (call method, read/write field value). The most straightforward way to leverage this would be to set a null security manager.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment