JS原型链污染
js原型链污染
什么是js原型(prototype)
要弄清这个问题,就要先弄清什么事类和对象。
类和对象是面向对象的编程语言中的几本概念。这里不进行详细阐述,简单的说,类可以实例化成为对象。二者内部都存在属性和方法。
现在来说原型。原型分为显式原型(prototype)和隐式原型(_proto_)。现在假定有一个类Foo和一个Foo类实例化得出的对象foo。我们可以通过
1 | Foo.prototype.FunctionName = |
来定义原型。完成了定义后,就可以通过
1 | foo.FunctionName(); |
来对定义好的函数来进行调用了。
而__proto__和prototype的关系为:foo.__proto__ == Foo.prototype
总的来说,prototype是类的一个属性,而由该类实例化得到的对象都会拥有prototype的属性和方法。
什么是js原型链
这张图中可以看到,通过 __proto__ 可以一直往前找对象的原型,就形成了原型链。
而js在寻找属性时,如果在当前的对象中找不到,则会去对象的 __proto__ 中寻找。这个寻找机制就是原型继承链。
原型链污染
前文中已经提到,我们可以通过对象的 __proto__ 来访问类的原型。那么如果我门修改一个类的对象的 __proto__ ,是否就可以控制该类的其他对象的属性了呢
1 | let foo = {bar : 1}; |
运行这段代码可以发现,虽然zoo为一个空属性,但是输出其bar属性会发现结果为2。这就意味着我们通过一个对象来修改原型链,从而影响了其他的对象的属性。这就是js原型链污染的基本原理。
利用条件
1.merge/copy函数
merge函数合并两个对象时,对于属性的值时对象或者数组的,merge会把他们的引用复制给目标对象。因此,在merge完成后,修改源对象的属性,目标对象的属性也会发生变化。
这里用ctfshow的题目做例子
1 | var express = require('express'); |
这是题目登陆界面的源码,可以看到,这里把req.body也就是用户的请求内容copy到了user中,进行登陆。但是利用刚才的知识,如果传入一个
1 | "__proto__" : { |
就可以做到就该secret的对象的效果,从而得到flag。