【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)内部方法,其中 P就是属性名 "name"。 对于普通对象 target(即 {}),in操作符(或内部的 \[\[HasProperty\]\])会沿着该对象的原型链向上查找属性。 target本身是空对象,没有 has方法。 接着,查找 target的原型,即 Object.getPrototypeOf(target),它指向 Object.prototype。 在代码中,通过 Object.prototype.has = function() { ... }在 Object.prototype上直接添加了一个 has方法。 因此,当查找 has属性时,就在 Object.prototype上找到了它,于是执行了这个方法,打印出了 "has"。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/9b33dab8d85440dcad5ac38f0aa84936.png) 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函数。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/ca0ee17d0c61433f9cc08a6438b1ec91.png) ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/d7922f0e67ee4ddf8a47a7b66ec20264.png) ## 四、练习 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e2034efae9ad4846a11c105373e1f4be.png) (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命令。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/bb8f3c1f73454d78a043cfbfa62812be.png) ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/03d2409827c84604975817d4e4aa0601.png)

相关推荐
昭昭日月明16 小时前
搭建高可用私有 NPM 镜像
node.js·代码规范
七牛云行业应用21 小时前
保姆级 OpenClaw 避坑指南:手把手教你看日志修 Bug,顺畅连通各大 AI 模型
人工智能·后端·node.js
多厘1 天前
使用 nvm 管理多版本 Node 项目依赖
node.js
前端双越老师2 天前
Skills 是什么?如何用于 Agent 开发?
人工智能·node.js·agent
San303 天前
AI 时代的“USB-C”接口:MCP 核心原理与实战
langchain·node.js·mcp
helloweilei4 天前
javascript 结构化克隆
javascript·node.js
小蜜蜂dry5 天前
nestjs学习 - 控制器、提供者、模块
前端·node.js·nestjs
San305 天前
手写 Mini Cursor:基于 Node.js 与 LangChain 的开发实战
langchain·node.js·agent
前端付豪5 天前
Nest 项目小实践之图书增删改查
前端·node.js·nestjs
sunny_5 天前
面试踩大坑!同一段 Node.js 代码,CJS 和 ESM 的执行顺序居然是反的?!99% 的人都答错了
前端·面试·node.js