浅谈原型链污染

发布于 2021-03-01  372 次阅读


JS原型链

在JavaScript中,万物皆为对象。有对象就有继承,通常我们将类的实例化也看做js中的继承。

如图,我们使用构造函数定义了一个类test,并在其中定义了属性a='hello,world'。而后我们又将test类实例化为test1。在test1中我们发现仍然存在属性a。

prototype是js类中自带的一个属性,通常我们可以通过prototype这个属性来对对象的父类进行访问和修改。但是当类实例化为对象之后,我们也同样可以通过对象中自带的__proto__属性来对“类”的父类进行访问或修改。

如图:

我们不难发现对于一个类来讲,其本身prototype属性与其实例化后的对象本身的__proto__属性是等价的。

如图,我们通过向FOO的父类中添加了一个b属性,使得原本未声明的b属性也出现在对象foo中。即我们通过修改父类属性影响到了子类属性的访问(还记得前面讲的类的实例化就是对象的继承吗),由此我们不难看出js访问对象属性的逻辑:

  • 在该对象中寻找属性
  • 在对象的父类中寻找属性
  • 在对象父类的父类中寻找该属性
  • .......
  • 直到null为止

以上整个过程就是围绕js对象的原型链展开的操作。

除此之外,我们还可以通过数组的形势来访问js中对象的属性。

如图所示,我们通过数组的形式访问了test1实例当中的a属性,当然,我们甚至可以用二维数组,三维数组,甚至更高维的数组来访问多重父类关系当中的属性。

如图:

a,b当中本没有sucess这个元素,但是我们利用了数组的形式向a的父类添加了sucess这个属性。由于a,b属于同一类型,拥有共同祖先,所以b中也就有了sucess属性。这就造成了原型链污染,整个过程大致为:

1.在b中寻找sucess(未找到)

2.在b.__proto__中寻找sucess(找到)

3.返回父类中sucess。

在ctf比赛中的js代码,我们需要特别留意数组的操作。因为js的原型链污染往往发生在数组可控的部分代码,我们通过上传json等格式的数据也许能达到攻击的目的。


业精于勤,荒于嬉;行成于思,毁于随