JavaScript原型链及其污染

一.什么是原型链?

1.JavaScript中,我们如果要define一个类,需要以define“构造函数”的方式来define:
function xluo() {				//定义类xluo()
this.a = 10086 //this.a是xluo类的一个属性
}
new xluo()
2.了解prototype and __proto__ , JavaScript里面'一切皆对象'。
(通用规则,JavaScript默认原型链指向逻辑)
  1. 对象有__proto__属性,函数有prototype属性;
  2. 对象由函数生成;
  3. 生成对象时,对象的__proto__属性指向函数的prototype属性。
var xluo = {}			//创建空对象时,we actually use Object fuction to generate
xluo.__proto__ === Object.prototype
//true var xluo = Object()
xluo.__proto__ === Object.prototype
//true ------------------------------------------------
//JavaScript一切皆对象,即函数也是对象的一种 function xluo(){} //function函数创建对象
xluo.__proto__ === Function.prototype
//true typeof xluo
//"function" Function.__proto__ === Function.prototype
//true
Object.__proto__ === Function.prototype
//true var xluogood = new xluo()
xluogood.__proto__ === xluo.prototype
//true
3.原型链继承

对象的属性时从generate他的函数的prototype那里得到的。

xluogood为何有xluo、Object的原型方法,其实就是通过原型链继承。

继承的过程可以表示为xluogood.__proto__ = xluo.prototype

对象.__proto__ = 构造器.prototype

xluogood为普通对象,它的构造器为xluo,以xluo为原型,

第一链为xluogood.__proto__ === xluo.prototype

xluo.prototype(注意这边不是xluo)为json对象,即普通对象,构造器为Object,以Object为原型,

第二链为xluo.prototype.__proto__ === Object.prototype;

Object.prototype以Null为原型,

第三链为Object.prototype.__proto__ === null

此时我们再看下面那张图是不是很容易理解呢。

[]

4.通过prototype链实现继承

一般函数默认的prototype是系统自动生成的一个对象

当js引擎执行对象的属性或方法时,先查找对象本身是否存在该方法,如果不存在则会在原型链上查找。

  1. 每个构造函数(constructor)都有一个原型对象(prototype)
  2. 对象的__proto__属性,指向类的原型对象prototype
  3. JavaScript使用prototype链实现继承机制

一般函数默认的prototype是一个类型为"object"的对象,它有两个属性:constructor__proto__

大多数情况下,__proto__可以理解为“构造器的原型”,即__proto__===constructor.prototype,但是通过 Object.create()创建的对象有可能不是。

其中constructor属性指向这个函数自身,__proto__属性指向Object.prototype,这说明一般函数的prototype属性是由Object函数生成的。

function xluo(){}
typeof xluo.prototype
//"object"
xluo.prototype.constructor === xluo
//true

特殊函数Function,Object

typeof Object.prototype
//"oject"

可以看到Object函数的prototype属性也是一个类型为"object"的对象,但和一般函数的默认prototype属性不一样的是,它多了一大堆方法,这些方法都是JavaScript对象的系统默认方法。

再仔细看,Object函数的prototype属性里没有__proto__属性,我们试着把它的__proto__属性打出来看看:

Object.prototype.__proto__
//null

Object.prototype.__proto__ === null,提前到达了终点。

typeof Object.prototype === "object",说明它是一个Object对象,如果它由Object函数生成,于是按照我们上面的通用规则,就该是Object.prototype.__proto__ === Object.prototype

问题出现了,Object.prototype.__proto__属性指向了它自身,这样以__proto__属性构成的原型链就再也没有终点了!所以为了让原型链有终点,在原型链的最顶端,JavaScript规定了Object.prototype.__proto__ === null

typeof Function.prototype			//有别于其他函数的object
//"function"
Function.prototype.__proto__ === Object.prototype
//true

一个"function"类型的对象,应该是由Function函数生成的,那它的prototype属性应该指向Function.prototype,也就是Function.prototype.__proto__ === Function.prototype

为了避免循环引用,所以JavaScript规定Function.prototype.__proto__ === Object.prototype,这样既避免了出现循环引用,又让__proto__构成的原型链指向了唯一的终点:Object.prototype.__proto__ === null

5.JavaScript原型链继承实践
function me() {
this.first_name = 'xu'
this.last_name = 'ruilong'
}
function you() {
this.first_name = 'nb'
}
you.prototype = new me()
you = new you() //通过you类建立对象you

you类继承了me类的last_name属性。

in fact,在调用you.last_name的时候,JavaScript执行以下操作:

​ 1.在对象you寻找last_name

​ 2.如果找不到,则在you.__proto__寻找last_name

​ 3.如果还找不到,则在you.__proto__.__proto__中寻找last_name

​ 4.本题you.__proto__.__proto__.__proto__.__proto__ === null

6.JavaScript污染实践(一)
var xluo = {
age : 3
}
xluo.__proto__.age = 18
xluoxluo = {}
console.log(xluoxluo.age) //已污染

因为我们修改了xluo的原型,而xluo和xluoxluo同样是Object类的实例,所以事实上我们修改了Object,给Object增加了属性age,值为18。

所以,in the same app,If an attacker controls and modifies the prototype of an object, it will be able to affect all objects that come from the same class as the object. This attack method is prototype chain pollution.

在JavaScript中访问一个对象的属性可以用a.b.c或者a["b"]["c"]来访问。由于对象是无序的,当使用第二种方式访问对象时,只能使用指明下标的方式去访问。因此我们可以通过a["__proto__"]的方式去访问其原型对象。

7.JavaScript污染实践(二)

现在我们大概弄清了有关原型链污染的基础知识,那么现在构建一串代码

function merge(a,b){				//merge(a,b)意为合并a,b
for (flag in b){
if(flag in a && flag in b){
merge(a[flag],b[flag])
}
else{
a[flag] = b[flag]
}
}
}
xluo = {}
xluoxluo = JSON.parse('{"flag":1,"__proto__":{"flagflag":2}}')
merge(xluo,xluoxluo)
console.log(xluo.flag,xluo.flagflag) xluogood = {}
console.log(xluogood.flagflag)

JSON.parse() 方法用于将一个 JSON 字符串转换为对象。

此时通过__proto__污染Object。

7.JavaScript污染实践(三)ctf

以下是来自 hackit 2018 的一道题目

(该题目原文链接https://www.smi1e.top/javascript-%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93/)

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 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('/static', express.static('static'));
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 ??*/ 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;
console.log(matrix);
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!')
})

对于以上的代码,我们首先关注到if语句,这是一个很明显的判断语句。

我们可以发现访问admin获取flag需要user.admintoken===req.query.querytoken

user = [],他是Array的实例,继承自Array.prototype

api接口处有一处赋值操作,我们可以通过__proto__Array.prototype进行赋值。


JavaScript原型链及其污染的更多相关文章

  1. JavaScript学习总结(十七)——Javascript原型链的原理

    一.JavaScript原型链 ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法.其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.在JavaScript中, ...

  2. javascript原型链中 this 的指向

    为了弄清楚Javascript原型链中的this指向问题,我写了个代码来测试: var d = { d: 40 }; var a = { x: 10, calculate: function (z) ...

  3. 明白JavaScript原型链和JavaScrip继承

    原型链是JavaScript的基础性内容之一.其本质是JavaScript内部的设计逻辑. 首先看一组代码: <script type="text/javascript"&g ...

  4. Javascript 原型链资料收集

    Javascript 原型链资料收集 先收集,后理解. 理解JavaScript的原型链和继承 https://blog.oyanglul.us/javascript/understand-proto ...

  5. 资料--JavaScript原型链

    JavaScript原型链 原文出处:https://www.cnblogs.com/chengzp/p/prototype.html 目录 创建对象有几种方法 原型.构造函数.实例.原型链 inst ...

  6. JavaScript原型链:prototype与__proto__

    title: 'JavaScript原型链:prototype与__proto__' toc: false date: 2018-09-04 11:16:54 主要看了这一篇,讲解的很清晰,最主要的一 ...

  7. javascript 原型链污染

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

  8. 初探JavaScript原型链污染

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

  9. 图解Javascript原型链

    本文尝试阐述Js中原型(prototype).原型链(prototype chain)等概念及其作用机制.上一篇文章(图解Javascript上下文与作用域)介绍了Js中变量作用域的相关概念,实际上关 ...

随机推荐

  1. Linux系统目录简介

    Linux系统目录简介 boot 系统启动 grub(内核加载程序,内核≈操作硬件) 界面 自检程序 bin 系统可执行文件 bash=终端程序 sbin 超级用户的可执行文件 root root家目 ...

  2. jar文件无法双击打开

    1.  jdk安装后环境变量未设置好 (无jdk先自行下载) 我的电脑-属性-高级系统设置-环境变量-系统变量 找到path:添加环境变量为"java/jdk/bin"文件夹路径( ...

  3. Linux开机启动顺序启动顺序及配置开机启动

    Linux:开机启动顺序启动顺序及配置开机启动 开机启动顺序 1.加载内核 2.启动 init(/etc/inittab) pid=1 3.系统初始化 /etc/rc.d/rc.sysinit 4.运 ...

  4. linux开机启动设置的几种方法

    Linux开机自启动的几种方式: 1.chkconfig 以supervisord服务脚本为例: 第1步:把上面的脚本放在/etc/init.d/文件 ln -s ./supervisord  /et ...

  5. day85:luffy:购物车根据有效期不同切换价格&购物车删除操作&价格结算&订单页面前戏

    目录 1.购物车有效期切换 2.根据有效期不同切换价格 3.购物车删除操作 4.价格结算 5.订单页面-初始化 1.购物车有效期切换 1.关于有效期表结构的设计 1.course/models.py ...

  6. 直播带货APP源码开发为什么选择云服务器

    云服务器可以为直播带货APP源码提供弹性计算以及更高的运行效率,避免资源浪费,随着直播带货APP源码业务需求的变化,可以实时扩展或缩减计算资源.CVM支持按实际使用的资源计费,可以节约计算成本. 一. ...

  7. 测试php

    /** * 测试guzzle * * @return void */ public function index() { $client = new GuzzleHttp\Client(); //12 ...

  8. 7 apache和nginx的区别

    7 apache和nginx的区别 nginx 相对 apache 的优点: 轻量级,同样起web 服务,比apache 占用更少的内存及资源 抗并发,nginx 处理请求是异步非阻塞的,支持更多的并 ...

  9. CentOS6.x 安装 nginx-1.19.4

    1.下载nginx http://nginx.org/en/download.html wget  http://nginx.org/download/nginx-1.19.4.tar.gz 2.解压 ...

  10. Flutter 开发从 0 到 1(五)源码

    Flutter 开发从 0 到 1 明天开始又要上班了,你的假期任务完成如何啊?由于平时加班太多了,实在挤不出更多时间,从开始想用 Flutter <Flutter 开发从 0 到 1(一)需求 ...