沙箱逃逸:
- 当我们需要测试一些存在潜在风险的程序/代码时,不宜直接在主机运行,此时就可以选择在沙箱————一个与主机相互隔离的环境————运行。
- 沙箱一定安全么?显然不是,我们可以构造恶意程序/代码,从沙箱中逃逸到主机中,对主机造成实际危害。
- 沙箱逃逸的本质是:找到一个沙箱外部的对象或函数,然后通过这个对象或函数的属性或方法,获得对沙箱外的代码执行能力。
vm模块常见方法:
- vm模块:即一个沙箱环境。
常见方法:
- vm.runinThisContext(code):在当前global下创建一个作用域(沙箱),并将接收到的参数当作代码运行。sandbox中可以访问到global中的属性,但无法访问其他包中的属性(使用当前的作用域来运行代码,代码可以直接访问当前环境中的所有全局对象和模块)。
- vm.createContext([sandbox]):先创建一个沙箱对象,再将沙箱对象传给该方法(如果没有则会生成一个空的沙箱对象),v8(JavaScript 引擎)为这个沙箱对象在当前global外再创建一个作用域,此时这个沙箱对象就是这个作用域的全局对象,沙箱内部无法访问global中的属性。
- vm.runInContext(code, contextifiedSandbox[, options]):代码会在传入的沙箱对象的作用域中执行。
- vm.runInNewContext(code, sandbox):传入待执行代码,可传入沙箱对象,相当于createContext后接着runInContext。
- vm.runinThisContext(code):在当前global下创建一个作用域(沙箱),并将接收到的参数当作代码运行。sandbox中可以访问到global中的属性,但无法访问其他包中的属性(使用当前的作用域来运行代码,代码可以直接访问当前环境中的所有全局对象和模块)。
原型链逃逸:
先放代码:
const vm = require('vm');
const result = vm.runInNewContext(`this.constructor.constructor("return process")()`);
result.mainModule.require('child_process').exec('calc')
以上代码的原理是什么?
开头require('vm')引入了Node.js的vm模块,无需多言
vm.runInNewContext上文也已说明过,我们来看这部分
this.constructor.constructor(“return process”)()
此处的this指向当前sandbox的作用域,接下来通过两个constructor获取到Function对象构造函数,再构造一个函数,并立即执行,利用该函数返回process对象。
接下来看
result.mainModule.require('child_process').exec('calc')
接收到process对象后,利用该对象访问当前程序的入口模块mainModule,该模块一般挂载着require函数,利用require函数即可导入child_process模块,最终实现命令执行。
以上即通过原生链逃逸方式实现vm模块沙箱逃逸的过程。
(有黑客!我弹计算器了!)
vm2模块沙箱逃逸部分待续——
Comments | NOTHING