YUes I am god

This commit is contained in:
velzie 2024-08-25 23:04:31 -04:00
parent 5024e19c08
commit c61e62ec91
No known key found for this signature in database
GPG key ID: 048413F95F0DDE1F
6 changed files with 56 additions and 8 deletions

View file

@ -110,7 +110,8 @@ export class ScramjetClient {
}); });
for (const module of modules) { for (const module of modules) {
if (module.enabled()) module.default(this, this.global); if (!module.enabled || module.enabled())
module.default(this, this.global);
else module.disabled(this, this.global); else module.disabled(this, this.global);
} }
} }

View file

@ -1,21 +1,35 @@
import { ScramjetClient } from "../client"; import { ScramjetClient } from "../client";
import { POLLUTANT } from "../shared/realm";
export default function (client: ScramjetClient) { export default function (client: ScramjetClient) {
client.Proxy("window.postMessage", { client.Proxy("window.postMessage", {
apply(ctx) { apply(ctx) {
// so we need to send the real origin here, since the recieving window can't possibly know. // so we need to send the real origin here, since the recieving window can't possibly know.
// except, remember that this code is being ran in a different realm than the invoker, so if we ask our `client` it may give us the wrong origin // except, remember that this code is being ran in a different realm than the invoker, so if we ask our `client` it may give us the wrong origin
// but, the first argument given will be polluted with the real realm // if we were given any object that came from the real realm we can use that to get the real origin
// and this works in every case EXCEPT for the fact that all three arguments can be strings which are copied instead of cloned
// so we have to use `$setrealm` which will pollute this with an object from the real realm
const pollutant = ctx.this[POLLUTANT] || {};
// this obtains a reference to the Function object of the real realm // and now we can steal Function from the caller's realm
const { const {
constructor: { constructor: Function }, constructor: { constructor: Function },
} = ctx.args[0]; } = pollutant;
// and finally, invoking the stolen Function will execute inside the caller's realm // invoking stolen function will give us the caller's globalThis, remember scramjet has already proxied it!!!
const callerGlobalThis: Self = Function("return globalThis")(); const callerGlobalThisProxied: Self = Function("return globalThis")();
const callerClient: ScramjetClient = const callerClient: ScramjetClient =
callerGlobalThis[ScramjetClient.SCRAMJET]; callerGlobalThisProxied[ScramjetClient.SCRAMJET];
// this WOULD be enough but the source argument of MessageEvent has to return the caller's window
// and if we just call it normally it would be coming from here, which WILL NOT BE THE CALLER'S because the accessor is from the parent
// so with the stolen function we wrap postmessage so the source will truly be the caller's window (remember that function is scramjet's!!!)
const wrappedPostMessage = Function(
"data",
"origin",
"transfer",
"this(data, origin, transfer)"
);
ctx.args[0] = { ctx.args[0] = {
$scramjet$origin: callerClient.url.origin, $scramjet$origin: callerClient.url.origin,
@ -24,6 +38,8 @@ export default function (client: ScramjetClient) {
// * origin because obviously // * origin because obviously
if (typeof ctx.args[1] === "string") ctx.args[1] = "*"; if (typeof ctx.args[1] === "string") ctx.args[1] = "*";
wrappedPostMessage.call(ctx.fn, ctx.args[0], ctx.args[1], ctx.args[2]);
}, },
}); });
} }

View file

@ -1,6 +1,6 @@
export function getOwnPropertyDescriptorHandler(target, prop) { export function getOwnPropertyDescriptorHandler(target, prop) {
let realDescriptor = Reflect.getOwnPropertyDescriptor(target, prop); let realDescriptor = Reflect.getOwnPropertyDescriptor(target, prop);
if (!realDescriptor) return realDescriptor; return realDescriptor;
let d: PropertyDescriptor = {}; let d: PropertyDescriptor = {};

View file

@ -0,0 +1,26 @@
import { ScramjetClient } from "../client";
import { config } from "../shared";
export const POLLUTANT = Symbol.for("scramjet realm pollutant");
export default function (client: ScramjetClient, self: typeof globalThis) {
// object.$setrealm({}).postMessage(...)
// the empty object is the "pollutant" which can reconstruct the real realm
// i explain more in postmessage.ts
Object.defineProperty(self.Object.prototype, config.setrealmfn, {
value(pollution: {}) {
// this is bad!! sites could detect this
Object.defineProperty(this, POLLUTANT, {
value: pollution,
writable: false,
configurable: true,
enumerable: false,
});
return this;
},
writable: false,
configurable: false,
enumerable: false,
});
}

View file

@ -16,12 +16,16 @@ export class ScramjetController {
importfn: "$scramjet$import", importfn: "$scramjet$import",
rewritefn: "$scramjet$rewrite", rewritefn: "$scramjet$rewrite",
metafn: "$scramjet$meta", metafn: "$scramjet$meta",
setrealmfn: "$scramjet$setrealm",
wasm: "/scramjet.wasm.js", wasm: "/scramjet.wasm.js",
shared: "/scramjet.shared.js", shared: "/scramjet.shared.js",
worker: "/scramjet.worker.js", worker: "/scramjet.worker.js",
thread: "/scramjet.thread.js", thread: "/scramjet.thread.js",
client: "/scramjet.client.js", client: "/scramjet.client.js",
codecs: "/scramjet.codecs.js", codecs: "/scramjet.codecs.js",
flags: {
serviceworkers: true,
},
}; };
this.config = Object.assign({}, defaultConfig, config); this.config = Object.assign({}, defaultConfig, config);

1
src/types.d.ts vendored
View file

@ -28,6 +28,7 @@ interface ScramjetConfig {
importfn: string; importfn: string;
rewritefn: string; rewritefn: string;
metafn: string; metafn: string;
setrealmfn: string;
wasm: string; wasm: string;
shared: string; shared: string;
worker: string; worker: string;