nodejs沙箱逃逸漏洞

目录

一:沙箱绕过

1:概念

2:核心原理

3:例题分析

3.1 this去获取一个toString方法,再通过toString方法来获取构造函数,拿到process模块

问题1:为什么我们不直接使用{}.toString.constructor('return process')(),却要使用this呢?

问题2:m和n也是沙盒外的对象,为什么也不能用m.toString.constructor('return process')()呢?

问题3:想一想能不能把mn的值引用变成类型引用呢?


一:沙箱绕过

1:概念

Node.js沙箱逃逸漏洞是一种安全漏洞,它允许攻击者通过利用Node.js沙箱环境中的漏洞来逃逸出沙箱,并访问或控制沙箱之外的系统资源。

沙箱是一种隔离技术,用于限制代码运行的环境,以防止恶意代码对系统造成损害。在Node.js中,沙箱通常用于运行不受信任的代码,例如第三方模块或用户提交的代码。

2:核心原理

只要我们能在沙箱内部,找到一个沙箱外部的对象,借助这个对象内的属性即可获得沙箱外的函数,进而绕过沙箱。

3:例题分析

3.1 this去获取一个toString方法,再通过toString方法来获取构造函数,拿到process模块

vm是 Node.js 的内置模块,用于在本机代码中执行 JavaScript 代码。使用 vm 模块,可以创建一个隔离的环境,以执行不受信任的代码,从而避免对主机环境的直接访问和潜在风险。

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)

创建了一个名为 sandbox 的对象,它具有两个属性:m 和 n,分别被初始化为 1 和 2。这个对象代表了一个隔离的环境,我们的代码将在其中执行。

然后,我们使用 vm.createContext() 创建了一个新的上下文对象 context,并将 sandbox 作为参数传递给它。这样,context 就成为了一个与 sandbox 具有相同属性和方法的对象。

最后,我们使用 vm.runInContext() 方法来在指定的上下文中执行代码。我们将 script 和 context 作为参数传递给这个方法,它会返回执行结果。

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

通过this去获取一个toString方法,再通过toString方法来获取构造函数

怎么获取Function,通过toString函数和constructor 属性来获取Function这个属性

this.toString.constructor  因为constructor本身就是指向它的构造函数

先拿到个process模块,通过this(这个this指向的是sandbox全局).toString.constructor拿到所有函数的构造函数Function,接着拿到process模块,最终拿到子模块child_process调用命令执行

问题1:为什么我们不直接使用{}.toString.constructor('return process')(),却要使用this呢?

空对象调用toString.constructor也能拿到Function,但是空对象是沙盒内部的,沙盒逃逸就是要把外部的对象元素引入进来才行,不把外部元素引入进来的话,逃逸不出来。

这两个的一个重要区别就是,{}是在沙盒内的一个对象,而this是在沙盒外的对象(注入进来的)。沙盒内的对象即使使用这个方法,也获取不到process,因为它本身就没有process。

问题2:m和n也是沙盒外的对象,为什么也不能用m.toString.constructor('return process')()呢?

m和n也是在外部定义的,也有toString方法,不能的原因是原始类型是值引用而不是类型引用

如果是值引用,外部的m和n和沙盒内部的mn是两个数据,如果是类型引用,那就是外部的m把内存地址传给内部,内部直接调用外部的内存地址,那这俩就是一样的

这个原因就是因为primitive types,数字、字符串、布尔等这些都是primitive types,他们的传递其实传递的是值而不是引用,所以在沙盒内虽然你也是使用的m,但是这个m和外部那个m已经不是一个m了,所以也是无法利用的

问题3:想一想能不能把mn的值引用变成类型引用呢?

可以把mn改成空对象或者空数组甚至正则表达式,这样在外部就是类型引用了,这样内部就直接调用的是内存地址 那内外的mn就是一样的了

context:{m: [], n: {}, x: /regexp/}

这边就能看到执行了任意命令了,这里的whoami执行就是我的主机名。逃逸出沙箱就一种方法,就是拿到沙箱外部的变量或对象,然后用.toString方法和.constructor 属性来获取Function这个属性,然后拿到process,之后就可以执行任意代码了

 命令随便执行的,给个ipconfig也是可以执行的

 

 这就是典型的沙箱逃逸来执行命令,如果创建木马啥的,那就会造成危害了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值