网络安全之原型链污染

目录:

目录:

一、概念

二、举例

三、 实操了解

总结

四、抛出原题,历年原题复现

第一题:

五、分析与原理

 第二题:

八、分析与原理

九、具体操作,payload与结果

结果: 


一、概念

  JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……

cat.color--->Animal.prototype--->aaa.prototype--->xxx.--->object.protoype--->null

如果一层层地上溯,所有对象的原型最终都可以上溯到`Object.prototype`,即`Object`构造函数的`prototype`属性。也就是说,所有对象都继承了`Object.prototype`的属性。这就是所有对象都有`valueOf`和`toString`方法的原因,因为这是从`Object.prototype`继承的。`Object.prototype`的原型是`null`。`null`没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是`null`。

二、举例

三、 实操了解

在我们了解到了具体的“子类继承父类”的关键点后,我们进行实操看一道题

function P() {}
var p = new P();console.info(p.constructor === P)console.info(p.constructor === P.prototype.constructor)console.info(p.hasOwnProperty('constructor'))

思路:三小问的具体思路:

  1. console.info(p.constructor === P);: 这行代码比较了对象 p 的构造函数是否等于构造函数 P。由于 p 是通过构造函数 P 创建的,所以 p.constructor 应该指向 P,因此这里的比较结果为 true

  2. console.info(p.constructor === P.prototype.constructor);: 这行代码比较了对象 p 的构造函数是否等于构造函数 P.prototype.constructor。在这里,P.prototype.constructor 默认指向 P,因为 P.prototype 是从构造函数 P 继承而来的。因此这里的比较结果也为 true

  3. console.info(p.hasOwnProperty('constructor'));: 这行代码检查对象 p 是否直接拥有自己的属性 'constructor'。然而,'constructor' 实际上是从 P.prototype 继承而来的,因为 p 是通过 new P() 创建的,它的原型是 P.prototype。因此,这里的比较结果为 false

  4. 总结:代码展示了对象 p 与构造函数 P 及其原型之间的关系。对象 p 是通过构造函数 P 创建的,它的原型指向了 P.prototype。这些比较和检查操作说明了原型链在 JavaScript 中的工作方式。

总结

从以上的简单抛出和讲解我们不难看出原型链污染玩的就是两个重要的概念1.原型继承2.属性查找机制,让我们维持着这两个理念看看题型,在题型中理解原型链污染

  1. 原型继承: JavaScript中的对象可以通过原型继承从其他对象继承属性和方法。每个对象都有一个指向其原型的链接,通过这个链接可以访问原型对象的属性和方法。

  2. 属性查找机制: 当访问一个对象的属性或方法时,JavaScript引擎会首先在对象本身查找,如果找不到,它会沿着原型链向上查找,直到找到属性或方法或者到达原型链的末端。

四、抛出原题,历年原题复现

第一题:

const express = require('express')
var hbs = require('hbs');
var bodyParser = require('body-parser');
const md5 = require('md5');
var morganBody = require('morgan-body');
const app = express();
var user = []; //empty for nowvar matrix = [];
for (var i = 0; i < 3; i++){matrix[i] = [null , null, null];
}function draw(mat) {var count = 0;for (var i = 0; i < 3; i++){for (var j = 0; j < 3; j++){if (matrix[i][j] !== null){count += 1;}}}return count === 9;
}app.use(express.static('public'));
app.use(bodyParser.json());
app.set('view engine', 'html');
morganBody(app);
app.engine('html', require('hbs').__express);app.get('/', (req, res) => {for (var i = 0; i < 3; i++){matrix[i] = [null , null, null];}res.render('index');
})app.get('/admin', (req, res) => { /*this is under development I guess ??*/console.log(user.admintoken);if(user.admintoken && req.query.querytoken && md5(user.admintoken) === req.query.querytoken){res.send('Hey admin your flag is <b>flag{prototype_pollution_is_very_dangerous}</b>');} else {res.status(403).send('Forbidden');}    
}
)app.post('/api', (req, res) => {var client = req.body;var winner = null;if (client.row > 3 || client.col > 3){client.row %= 3;client.col %= 3;}matrix[client.row][client.col] = client.data;for(var i = 0; i < 3; i++){if (matrix[i][0] === matrix[i][1] && matrix[i][1] === matrix[i][2] ){if (matrix[i][0] === 'X') {winner = 1;}else if(matrix[i][0] === 'O') {winner = 2;}}if (matrix[0][i] === matrix[1][i] && matrix[1][i] === matrix[2][i]){if (matrix[0][i] === 'X') {winner = 1;}else if(matrix[0][i] === 'O') {winner = 2;}}}if (matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2] && matrix[0][0] === 'X'){winner = 1;}if (matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2] && matrix[0][0] === 'O'){winner = 2;} if (matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0] && matrix[2][0] === 'X'){winner = 1;}if (matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0] && matrix[2][0] === 'O'){winner = 2;}if (draw(matrix) && winner === null){res.send(JSON.stringify({winner: 0}))}else if (winner !== null) {res.send(JSON.stringify({winner: winner}))}else {res.send(JSON.stringify({winner: -1}))}})
app.listen(3000, () => {console.log('app listening on port 3000!')
})

五、分析与原理

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

 结果:

 第二题:

'use strict';const express = require('express');
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser');
const path = require('path');const isObject = obj => obj && obj.constructor && obj.constructor === Object;function merge(a, b) {for (var attr in b) {if (isObject(a[attr]) && isObject(b[attr])) {merge(a[attr], b[attr]);} else {a[attr] = b[attr];}}return a
}function clone(a) {return merge({}, a);
}// Constants
const PORT = 8080;
const HOST = '0.0.0.0';
const admin = {};// App
const app = express();
app.use(bodyParser.json())
app.use(cookieParser());app.use('/', express.static(path.join(__dirname, 'views')));
app.post('/signup', (req, res) => {var body = JSON.parse(JSON.stringify(req.body));  {"__proto__": {"admin":1}}var copybody = clone(body)if (copybody.name) {res.cookie('name', copybody.name).json({"done": "cookie set"});} else {res.json({"error": "cookie not set"})}
});
app.get('/getFlag', (req, res) => {var аdmin = JSON.parse(JSON.stringify(req.cookies))if (admin.аdmin == 1) {res.send("hackim19{}");} else {res.send("You are not authorized");}
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

八、分析与原理

分析:小例题:obj[a][b] = value。如果攻击者可以控制avalue,则可以将a的值设置为__proto__,并且将使用值value为应用程序的所有现有对象定义属性b

分析整个代码:首先定义一个函数merge,关于合并两个对象的设计是非常不安全的。由于执行merge()的库的最新版本已经打了补丁,这道题目使用了旧方法合并对象,从而易受到攻击。
在上面的代码中,我们可以快速注意到的一点是将2 个“admins”定义为const adminvar admin。理想情况下,js中不允许将const变量再次定义为var,所以在题目中有一个需要我们搞懂的点便是,其中一个是正常的a,而另一个是其他的a(同形异义字)。

原理:对象递归合并、按路径定义属性、对象克隆

九、具体操作,payload与结果

从源代码入手:
  Merge()函数是以一种可能发生原型污染的方式编写的。这是问题分析的关键。
    易受攻击的函数是在通过clone(body)访问/signup时被调用的,因此我们可以在注册时发送JSON有效负载,这样就可以添加admin属性并立即调用/getFlag来获取Flag。
   如前所述,我们可以使用__proto__(points to constructor.prototype)来创建值为1的admin属性。
执行相同操作的最简单的payload:

{"__proto__": {"admin": 1}}

结果: 

 

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

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

相关文章

Prometheus实现系统监控报警邮件

Prometheus实现系统监控报警邮件 简介 Prometheus将数据采集和报警分成了两个模块。报警规则配置在Prometheus Servers上&#xff0c; 然后发送报警信息到AlertManger&#xff0c;然后我们的AlertManager就来管理这些报警信息&#xff0c;聚合报警信息过后通过email、PagerDu…

ClickHouse SQL与引擎--基本使用(一)

1.查看所有的数据库 show databases; 2.创建库 CREATE DATABASE zabbix ENGINE Ordinary; ATTACH DATABASE ck_test ENGINE Ordinary;3.创建本地表 CREATE TABLE IF NOT EXISTS test01(id UInt64,name String,time UInt64,age UInt8,flag UInt8 ) ENGINE MergeTree PARTI…

webpack复习

webpack webpack复习 webpack基本配置 拆分配置 - 公共配置 生产环境配置 开发环境配置 使用merge webpack-dev-server 启动本地服务 在公共中引入babel-loader处理es6 webpack高级配置 多入口文件 enty 入口为一个对象 里面的key为入口名 value为入口文件路径 例如 pa…

图像处理库(Opencv, Matplotlib, PIL)以及三者之间的转换

文章目录 1. Opencv2. Matplotlib3. PIL4. 三者的区别和相互转换5. Torchvision 中的相关转换库5.1 ToPILImage([mode])5.2 ToTensor5.3 PILToTensor 1. Opencv opencv的基本图像类型可以和numpy数组相互转化&#xff0c;因此可以直接调用torch.from_numpy(img) 将图像转换成t…

使用Exe4j将jar文件打包成可执行.exe程序[详细]

1. 下载Exe4j EXE4j破解版下载http://www.sd173.com/soft/10717.html 不破解的话&#xff0c;运行打包的exe会有exe4j的欢迎语。关于Exe4j的破解教程可自行百度搜索。 2. 准备jar包 打包前首先确保jar能运行。可以将所有的以来包放在一个目录下&#xff0c;如lib目录&#…

TOPSIS法

TOPSIS法 文章目录 TOPSIS法TOPSIS法的三点解释增加指标个数1.统一指标类型极小型指标转换为极大型指标的公式中间型指标转换为极大型指标的公式区间型指标转换为极大型指标的公式 2.正向化矩阵标准化3.计算得分并归一化类比只有一个指标计算得分 TOPSIS法代码统一指标类型判断…

f12 CSS网页调试_css样式被划了黑线怎么办

我的问题是这样的 class加上去了,但是样式不生效,此时可能是样式被其他样式覆盖了, 解决方案就是 给颜色后边添加一个!important

软工导论知识框架(四)结构化系统的实现

一.编码 编码和测试统称为系统实现。 1.目的&#xff1a;把模块的过程性描述翻译为用选定的程序设计语言书写的源程序&#xff08;源代码&#xff09;。 &#xff08;真正交付给用户使用的&#xff0c;并不是源代码&#xff0c;而是经过编译链接生成的可执行的代码&#xff…

Go语言time库,时间和日期相关的操作方法

time库 用于处理时间、日期和时区的核心库。在实际开发中&#xff0c;常常需要与时间打交道&#xff0c;例如记录日志、处理时间差、计算时间间隔等等。因此&#xff0c;掌握time库的使用方法对于Go开发者来说非常重要。 在Go语言中&#xff0c;时间表示为time.Time类型&…

贝叶斯学习

贝叶斯 贝叶斯学习的背景贝叶斯定理举例 概览选择假设— MAPMAP举例 选择假设 — 极大似然 MLML 举例: 抛硬币问题 极大似然 & 最小二乘Nave Bayesian Classifier (朴素贝叶斯分类器)举例1&#xff1a;词义消歧 (Word Sense Disambiguation)举例 2: 垃圾邮件过滤 从垃圾邮件…

一个.NET开发的Web版Redis管理工具

今天给大家推荐一款web 版的Redis可视化工具WebRedisManager&#xff0c;即可以作为单机的web 版的Redis可视化工具来使用&#xff0c;也可以挂在服务器上多人管理使用的web 版的Redis可视化工具。 WebRedisManager基于SAEA.Socket通信框架中的SAEA.RedisSocket、SAEA.WebApi两…

【Linux】进程信号中的 core dump 标记位

进程信号中的 core dump 标记位 一、什么是core dump二、core dump的使用1、开启core dump2、生成core file文件3、验证进程退出码里面的core dump标志位 三、 core dump的应用 一、什么是core dump 我们知道所有的程序最终运行起来&#xff0c;都会变成进程&#xff0c;进程在…