前言

无。


环境搭建

下载安装NodeJS,新建一个目录并运行命令npm init后下载依赖:

npm install vm2@3.6.10

npm提示说该版本的vm2存在高危安全漏洞,但是坚持安装。

vm2

NodeJS沙盒,vm沙盒的优化版本,简单用法如下:

const {VM, VMScript} = require('vm2');

const script = new VMScript("this;");

console.log((new VM()).run(script));

运行一下,看到此时的this作用域为vm环境下的特殊作用域。

可以在本目录的node_modules文件夹下找到vm2的代码,比如main.js中可以找到VMScript的构造函数:

constructor(code, filename) {
    this.code = code;
    this.filename = filename || 'vm.js';
}

只是简单地把待运行代码保存起来。

也可以找到VM的构造函数:

const host = {
    version: parseInt(process.versions.node.split('.')[0]),
    console,
    String,
    Number,
    Buffer,
    Boolean,
    Array,
    Date,
    Error,
    RangeError,
    ReferenceError,
    SyntaxError,
    TypeError,
    RegExp,
    Function,
    Object,
    VMError,
    Proxy,
    Reflect,
    Map,
    WeakMap,
    Set,
    WeakSet,
    Promise
};

this._context = vm.createContext();

Reflect.defineProperty(this, '_internal', {
    value: vm.runInContext(`(function(require, host) { ${cf} \n})`, this._context, {
        filename: `${__dirname}/contextify.js`,
        displayErrors: false
    }).call(this._context, require, host)
});

根据参考文章,这里将一些沙盒中需要的对象放入host中,创建了沙盒作用域并调用vm的API将contextify.js封装成了一个匿名函数,contextify.js涉及到一些对象代理之类的东西。可以看到global下只挂载了VMError和Buffer两个对象:

global.VMError = VMError;
...
const LocalBuffer = global.Buffer = Contextify.readonly(host.Buffer, {
    allocUnsafe: function allocUnsafe(size) {
        return this.alloc(size);
    },
    allocUnsafeSlow: function allocUnsafeSlow(size) {
        return this.alloc(size);
    }
});

readonly一直找到Contextify.object,可以看到Buffer实际上是一个代理对象Proxy:

const proxy = new host.Proxy(object, host.Object.assign(base, traps, deepTraps));
Contextify.proxies.set(object, proxy);
Contextified.set(proxy, object);
return proxy;

该代理对象拦截了get、set、construct等等操作,所以这个Buffer对象虽然是从外面传入沙盒的,但是也无法访问其constructor等属性,从而保证了沙盒安全性。

CVE-2019-10761

基于调用栈过大爆栈捕获外部对象。

CVE-2021-23449

基于import未经沙箱,

trick

基于对象代理和异常捕获。


参考

NodeJS VM和VM2沙箱逃逸

vm2实现原理分析


Web NodeJS

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

PHP GC垃圾回收与反序列化
PHP Development Server 远程源码泄露漏洞