Introduction

One of the quite recent (at least, not too old) and amusing things to look at when you are beginning to study security in java is the issue 54 from Security Exploitation. This issue is quite interesting, because it is a low level trick and is, so far, not patched.

Security in java

Before talking about this particular issue, let’s see some basics about security in Java in general.

The first thing to know is what and why are we attacking java? Java is designed to run code from untrusted sources securely. This is a well known property and you can find it “everyday” in your browser with the java applets. When an applet is downloaded from a website the browser will run it and you don’t want a potentially malicious attacker to have full permissions under your machine.

Java implements a system of permissions to limit possibilities for the code executed with unprivileged rights (the applet). The goal for an attacker will be to acquire full privileges from an unprivileged application, allowing full jeopardy of the computer. The traditionnal attacks (overflow, use-after-free…) are still working but there is an additional type which is less common : the sandbox bypass (which can itself be divided in several parts: unsafe reflection, least privilege violation…).

The security of Java is based on several things, the first is the gestion of the memory which is handled by the JVM (Java Virtual Machine) and not by the user. It first avoids most of the stupid errors developers can make, but it is also mandatory for running code safely (if we can do what we want with the memory we already have the same privilege that the program).

The second part of the security is handled at the loading of a class. This loading process is divided into two parts: the class loader and the bytecode verifier.

The class loader has a similar goal as the dynamic linker in Unix systems. There are several implementations (classes) of the class loader, like the applet class loader which can load code over the internet from a website. All class loaders inherit from java.lang.ClassLoader. Of course, a class loader has to take some precautions not to execute malicious code. In particular, it will have to check that we are not trying to spoof a System class which would allow us to bypass all security protections.

During the validation step by the class loader, the bytecode will be checked by the bytecode verifier. It is called from the class loader through the method defineClass. It will not perform any check of logic but only check that the bytecode is valid and other various things, for example that it is not overflowing the stack. Once the bytecode verifier has done his work, if the class loader validates the class, the code is considered to be of no harm to the JVM (this doesn’t mean you have all the privileges).

The last important part in java security is the security manager, it’s the part which will check all the permissions during runtime. If unprivileged code tries to do something forbidden, it will raise an exception. The basic class for the security manager is java.lang.SecurityManager Usually, the security manager will be retrieved by a call to getSecurityManager (java.lang.System).

If the security manager is set to null, no check is performed and the code runs with full privileges. Therefore, the goal of a lot of exploits will be to rewrite the security manager to null. Some permissions allow to change the security manager and to set it to null (AllPermission, setSecurityManager, createClassLoader, accessClassInPackage.sun…). Typically, a permission check looks like this:

::java
// From AppletClassLoader.java
SecurityManager sm = System.getSecurityManager();
if (sm != null)
    sm.checkPackageAccess(name.substring(0, i));

The method checkPackageAccess and all the other check functions will throw an error if the code doesn’t have the rights to perform the action desired. The check looks into the stack-call and if it finds an unprivileged function, it throws an exception. To go from unprivileged code to privileged code, Java uses the ActionController.doPrivileged method:

::java
AccessController.doPrivileged(new PrivilegedAction() {
    public Object run() {
        // insert priviledge code here
    }
});

This check is performed by the security manager and will stop at the first doPrivileged it finds.

The MethodHandle resolution mecanism

In the constant pool of a class file it is possible to define a MethodHandle. This entry in the constant pool contains two elements: the reference kind and the reference index. The reference kind characterizes the bytecode behavior of the methodhandle, there are 9 possible kinds, as follow:

REF_getField
REF_getStatic
REF_putField
REF_putStatic
REF_invokeVirtual
REF_invokeStatic
REF_invokeSpecial
REF_newInvokeSpecial
REF_invokeInterface

All 9 kinds are used to get a MethodHandle. This object can reference not only methods but also fields, constructors “and similar low-level operations”. The kinds 1 to 4 are used to create a MethodHandle on a field and the reference index must point to a CONSTANT_Fieldref. For kinds 5 to 8 the reference index must point to a CONSTANT_Methodref. It is used to get a MethodHandle on a method.

The last kind (REF_invokeInterface) is used for CONSTANT_InterfaceMethodref and returns a MethodHandle for an interface method. The interesting part about the use of a CONSTANT_MethodHandle into the constant pool is that the creation of the MethodHandle is done at the loading of the class file. Theoretically, it should make no difference between retrieving the MethodHandle at the loading of the class and after the loading. We will see that it’s not the case.

Issue 54: the vulnerability

The issue 54 has been found by Security Exploitation and is well documented (http://www.security-explorations.com/materials/se-2012-01-54.pdf). The usual way to get a Method Handler of a function in a class is to call the public method findVirtual from the MethodHandles.Lookup module. The code of this method is the following:

::java
public MethodHandle findVirtual(Class<?> refc, String name, MethodType type)
throws NoSuchMethodException, IllegalAccessException {
    MemberName method = resolveOrFail(refc, name, type, false);
    checkSecurityManager(refc, method);
    return accessVirtual(refc, method);
}

In this code we can see the call to the method checkSecurityManager which checks whether the calling code has the right to get the MethodHandle. In particular, it will forbid to get a MethodHandle on a private method of a super-class. On the other hand, when getting a MethodHandle at class loading with a REF_invokeVirtual, the method called is resolveVirtual :

::java
private MethodHandle resolveVirtual(Class<?> refc, String name, MethodType
type) throws NoSuchMethodException, IllegalAccessException {
    MemberName method = resolveOrFail(refc, name, type, false);
    return accessVirtual(refc, method);
}

We can see that the only difference between these two functions is the call to the checkSecurityManager function which is not done in the resolveVirtual method. The resolveVirtual function is of course private but during loading it is called by the class loader. That means that a specially crafted class can get virtual and static methods (the same issue exists with findStatic and resolveStatic) from a class, allowing to have a valid MethodHandle on something we shouldn’t have had access to.

This issue is also present in most of the different kinds of CONSTANT_MethodHandle entries in the constant pool of a class file. Still, this issue alone does not allow to execute code from an untrusted source as privileged. When Security Exploitation reported that vulnerability, they used a second one (Issue 55 http://www.security-explorations.com/materials/SE-2012-01-ORACLE-10.pdf) to get the execution of code as privileged. The issue 55 allows to bind a MethodHandle to an object instance of incompatible type. This could allow to set the securitymanager to null, bypassing all the permission protection.

Issue 54: the exploitation

With this issue, Security Exploitation has released a demonstration of the the issues 54 and 55 (http://www.security-explorations.com/materials/se-2012-01-50-60.zip). In particular, it contains a class MyCL.class which is “hand made”, and contains the exploitation of issue 54. Here is the constant pool of this class:

::java
CONSTANT_MethodRef(10) 5, 16
CONSTANT_MethodRef(10) 5, 17
CONSTANT_String(8) 10
CONSTANT_Class(7) 18
CONSTANT_Class(7) 19
CONSTANT_Utf8(1) 6 : <init>
CONSTANT_Utf8(1) 3 : ()V
CONSTANT_Utf8(1) 4 : Code
CONSTANT_Utf8(1) 15 : LineNumberTable
CONSTANT_Utf8(1) 5 : dummy
CONSTANT_Utf8(1) 57 : (Ljava/lang/String;[BIILjava/security/ProtectionDomain;)V
CONSTANT_Utf8(1) 18 : get_defineClass_mh
CONSTANT_Utf8(1) 20 : ()Ljava/lang/Object;
CONSTANT_Utf8(1) 10 : SourceFile
CONSTANT_Utf8(1) 9 : MyCL.java
CONSTANT_NameAndType(12) 6, 7
CONSTANT_NameAndType(12) 20, 21
CONSTANT_Utf8(1) 4 : MyCL
CONSTANT_Utf8(1) 21 : java/lang/ClassLoader
CONSTANT_Utf8(1) 11 : defineClass
CONSTANT_Utf8(1) 73 : (Ljava/lang/String;[BIILjava/security/ProtectionDomain;)Ljava/lang/Class;
CONSTANT_MethodHandle(15) REF_invokeVirtual(5), 2

We can see that the entry 22 is a CONSTANT_MethodHandle1 with the kind REF_invokeVirtual for exploiting the vulnerability and refer to the CONSTANT_MethodRef at the entry 2, which is in the class java.lang.ClassLoader the method defineClass.

The defineClass method in java.lang.ClassLoader is a protected final method and it should be impossible to have an handle on this method and obviously to call it.

In MyCL.class we have three methods :

  • <init> which is for the initialisation
  • dummy
  • get_defineClass_mh which returns the CONSTANT_MethodHandle at the entry 22 of the constant pool.

The other part of the exploit is for the issue 55 which will allow to bind the method handle to another class and get it called with privileged rights, allowing a sandbox bypass.

Conclusion

This issue, even if a little old, is really interesting because it puts in light some internals of the class loading process which are often unclear. It is also really disturbing because Oracle doesn’t seem to consider this issue as a problem, indicating that this was an “allowed behavior”. Still not patched, this issue can be used for developing exploits, enlarging the possibility for finding vulnerabilities. Even if this issue was basically focused on a MethodHandle pointing to a method, the same problem exists with MethodHandle pointing on a field, allowing to gain even more access.