原型链污染

javascript 原型链

在javascript中,继承的整个过程就称为该类的原型链。

每个对象的都有一个指向他的原型(prototype)的内部链接,这个原型对象又有它自己的原型,一直到null为止。

在javascript中一切皆对象,因为所有的变量,函数,数组,对象 都始于object的原型即object.prototype,但只有类有对象,对象没有,对象有的是__proto__

like:

日期时:

f -> Data.prototype -> object.prototype->null

函数时:

d -> function.prototype -> object.prototype->null

数组时:

c -> array.prototype -> object.prototype->null

类时:

b -> a.prototype -> object.prototype->null

当要使用或输出一个变量时:首先会在本层中搜索相应的变量,如果不存在的话,就会向上搜索,即在自己的父类中搜索,当父类中也没有时,就会向祖父类搜索,直到指向null,如果此时还没有搜索到,就会返回 undefined。

原型链污染就是:在我们想要利用的代码之前的赋值语句如果可控的话,我们进行 ——__proto__ 赋值,之后就可以利用代码了。

原型链污染一般会出现在对象、或数组的键名或属性名可控,而且是赋值语句的情况下。

例一:

var mds = [];

for  (var i=0;i<3;i++){
mds[i]=[null,null,null];
}
Array(3) [ null, null, null ] var row="__proto__"
undefined var co="admin"
undefined mds[row][co]="sunsec"
"sunsec" var c=[]
undefined c[co]
"sunsec"

这里我们创建了两个数组,一个是mds,另一个是c,此时我们将mds的mds.__proto__上一条链的[co]为sunsec。

题一:
const express = require('express')         //关于require,require是一个函数
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 now var 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的条件就是user.admintoken && req.query.querytoken && md5(user.admintoken) === req.query.querytoken,但是我们无法掌控到admintoken。

但是在api这个接口的地方,是可以接收data,row,col所以此时我们可以进行原型链污染,在这里user.admintoken并没有被赋值,我们可以进行污染,只要将

matrix[client.row][client.col] = client.data

client.row设置为__proto__即可,再将col设为admintoken,此时data就是我们设置的值了。

此时在admin路由处传入querytoken。

题二
'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));
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}`);

flag获取条件: admin.аdmin == 1)

看到这处路由可以发现admin的admin属性是不存在的。

看到函数merge:

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
}

这里进行了对象的合并,但是键值是可以被控制的。

注意:在创建字典的时候,__proto__,不是作为一个键名,而是已经作为__proto__给其父类进行赋值

所以当我们设置:

var test = {"test":"aa","__proto__":{"admin":1}}

此时:test有两个键值,分别为test以及admin。

那么我们再将其跟另一个test1进行对象的合并,此时看一下test1,会发现他不具备admin属性。

如何避免:

利用JSON.parse,JSON.parse 会把一个json字符串 转化为 javascript的object。

Nodejs-原型链污染的更多相关文章

  1. 【web安全】Nodejs原型链污染分析

    Nodejs原型链污染分析 什么是js原型? 可以将js原型理解为其他OOP语言中的类,但还是有细微区别. 1. function F(){...} 2. var f = new F(); 分析: 1 ...

  2. redpwnctf-web-blueprint-javascript 原型链污染学习总结

    前几天看了redpwn的一道web题,node.js的web,涉及知识点是javascript 原型链污染,以前没咋接触过js,并且这个洞貌似也比较新,因此记录一下学习过程 1.本机node.js环境 ...

  3. 原型链污染(Node.js污染,javasrcipt原型链污染的)

    学习链接: https://www.jianshu.com/p/6e623e9debe3 关于NJS  https://xz.aliyun.com/t/7184 相关题是 GYCTF  ez_expr ...

  4. javascript 原型链污染

    原理①javascript中构造函数就相当于类,并且可以将其实例化 ②javascript的每一个函数都有一个prototype属性,用来指向该构造函数的原型同样的javascript的每一个实例对象 ...

  5. 初探JavaScript原型链污染

    18年p师傅在知识星球出了一些代码审计题目,其中就有一道难度为hard的js题目(Thejs)为原型链污染攻击,而当时我因为太忙了(其实是太菜了,流下了没技术的泪水)并没有认真看过,后续在p师傅写出w ...

  6. JavaScript原型链及其污染

    JavaScript原型链及其污染 一.什么是原型链? 1.JavaScript中,我们如果要define一个类,需要以define"构造函数"的方式来define: functi ...

  7. 【nodejs原理&源码赏析(3)】欣赏手术级的原型链加工艺术

    目录 一. 概述 二. 原型链基础知识 三. Worker类的原型链加工 四. 实例的生成 五. 最后一个问题 六. 一些心得 示例代码托管在:http://www.github.com/dashno ...

  8. 【nodejs原理&源码赏析(3)】欣赏手术级的原型链加工艺术

    [摘要] 学习经典代码中的prototype加工 示例代码托管在:http://www.github.com/dashnowords/blogs 好的代码都差不多,烂的代码却各有各的烂法. 一. 概述 ...

  9. Javascript的原型链图

    90%的前端或者js程序员或者老师们对Javascript懂得不比这个多 给手机看的 但是这个图里的所有褐色单向箭头链就是Javascript的原型链(颜色标注对理解js原型链很关键) 这图中的各个_ ...

随机推荐

  1. Docker-Docker与IPV6

    公司计划在2020年前完成IPV6化改造,于是我先行查阅了一些资料了解Docker进行IPv6化的可能性. 预计明年正式开始测试. 方法一.使容器中的服务支持IPv6地址 不为容器中的服务特别分配IP ...

  2. python编程中的并发------多线程threading模块

    任务例子:喝水.吃饭动作需要耗时1S 单任务:(耗时20s) for i in range(10): print('a正在喝水') time.sleep(1) print('a正在吃饭') time. ...

  3. ms-data(转载)

    转载:https://www.cnblogs.com/zll-52011/p/10960905.html 1.从美国矿物数据库下载矿物CIF(有晶格) 2.晶胞CIF导入MS 3.选择display ...

  4. 3、Entity Framework Core 3.1入门教程-设定字段属性

    本文章是根据 微软MVP solenovex(杨旭)老师的视频教程编写而来,再加上自己的一些理解. 视频教程地址:https://www.bilibili.com/video/BV1xa4y1v7rR ...

  5. PHP学习中的一些总结(持续更新)

    文件上传部分 在前台的<form>表单中 hidden隐藏域的MAX_FILE_SIZE可以起到实质性的控制作用,即在文件上传之前就可以判断文件的大小,格式为: <form acti ...

  6. 焦大:做seo需要的三心二意

    http://www.wocaoseo.com/thread-92-1-1.html        读过一些外国人写的教程之后,愈发觉得国外人写的教程甚是有趣,比起国内学习的课本来,真是不可同日而语. ...

  7. WPF新手快速入门系列 1.布局

    [概要] 该系列文章主要描述,新手如何快速上手做wpf开发.看过网上部分的教程,主要讲述的是介绍控件.这并没有问题,但是没有把自己的使用经验也完整的描述出来. 所以特此编写此系列文章希望能帮助到,因为 ...

  8. 详细分析链表的数据结构的实现过程(Java 实现)

    目录 链表的数据结构的实现过程(Java 实现) 前言 基本概念 链表的基本结构 链表的基本操作的实现 在链表中添加元素 在链表头添加元素 在链表指定位置处添加元素 链表的虚拟头节点 链表的查询和修改 ...

  9. js中使用const声明变量时需要注意

    const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址(初始化的内容)不得改动.对于简单类型的数据(数值.字符串.布尔值),值就保存在变量指向的那个内存地址,因此等同于常量. 简单 ...

  10. 使用OpenCV和Python构建自己的车辆检测模型

    概述 你对智慧城市的想法感到兴奋吗?如果是的话,你会喜欢这个关于建立你自己的车辆检测系统的教程的 在深入实现部分之前,我们将首先了解如何检测视频中的移动目标 我们将使用OpenCV和Python构建自 ...