node.js沙盒逃逸分析
背景
在日常开发中,会在业务代码中直接使用eval/function/vm等功能,其中 eval/Function 算是动态执行 JS,但无法屏蔽当前执行环境的上下文,但node.js 里提供了 vm 模块,相当于一个虚拟机,可以让你在执行代码时候隔离当前的执行环境,避免被恶意代码攻击。
沙盒简介
沙盒的特点在于很好的系统隔离性,在某种程度上,沙盒sandbox可以视为一个容器container,application运行在沙盒中,沙盒运行在windows操作系统上运行在沙盒中的application和沙盒外的application一样可以访问硬盘中的文件等资源。运行在沙盒中的application和沙盒外的application的主要区别在于:
对于沙盒外的application而言,沙盒内的application是透明的(即不可见的);
当沙盒内的application退出后,所做的更改将不会被保存。
一个很好的例子是:当沙盒内的application退出后,沙盒内的application已下载或“安装”的恶意软件都将被丢弃。
总而言之,沙盒就是一个可以让你相对安全执行代码的环境
沙盒逃逸
首先来一段沙盒逃逸的实例,直接进行分析:
const vm = require('vm'); |
以上事例大致可以拆分出:
tmp=ctx.constructor//object |
以上被称为原型链的方式完成逃逸,个人感觉可以和继承的思想联系在一起,有点类似但是又不同,大概是通过往前引用原型链,引用到沙箱外的函数,从而实现逃逸。
原理
根据这个图片进行讲解,就是在vm上下文通过原型链的prototype属性向上链接引用function,引用到全局数据实现在沙盒内进行沙盒外的function的调用。实例分析
const vm = require('vm'); |
其中this
通过其__proto__属性指向的是主环境的Object.prototype,所以:
this.constructor.constructor('return process')().mainModule.require('child_process').execSync('whoami').toString() |
1.通过this的原型链向上获得主环境的function
2.然后通过(‘return process’)()获得主环境process变量
3通过process.mainModule.require导入child_process模块,实现命令执行
知识补充
process变量:是nodejs中的一个全局变量,
拿到这个环境变量,相当于此时是在主环境下进行函数的执行,类似偷梁换柱?
child_process模块:提供了命令执行的方法
http://nodejs.cn/api/child_process.html#child_process_child_process
https://chinese.freecodecamp.org/forum/t/topic/587
https://liotree.github.io/2020/04/29/vm2%E6%B2%99%E7%9B%92%E9%80%83%E9%80%B8%E5%88%86%E6%9E%90/
node.js沙盒逃逸分析