自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JavaScript原型鏈污染

開(kāi)發(fā) 前端
js原型鏈污染可以說(shuō)原理并不是太難懂,關(guān)鍵是實(shí)際中如何去利用。關(guān)于這個(gè)漏洞也是看了很多大神的文章,它們的思路真的太厲害了,我還有很多需要學(xué)習(xí)的,跟大家一起共勉。

前言

在瀏覽某個(gè)論壇的時(shí)候,第一次看到了JavaScript原型鏈污染漏洞。當(dāng)時(shí)非常的好奇,當(dāng)時(shí)我一直以為js作為一種前端語(yǔ)言,就算存在漏洞也是針對(duì)前端,不會(huì)危害到后端,因此我以為這種漏洞危害應(yīng)該不大??僧?dāng)我看到他的漏洞危害還有可以執(zhí)行任意命令的時(shí)候,發(fā)現(xiàn)可能我想到有點(diǎn)簡(jiǎn)單了。js也是可以用來(lái)做后端語(yǔ)言的。這篇文章就來(lái)認(rèn)識(shí)一下這個(gè)漏洞。

JavaScript原型鏈?zhǔn)鞘裁矗?/h2>

既然漏洞名稱(chēng)是JavaScript原型鏈污染,那么首先就要先明白JavaScript原型鏈?zhǔn)鞘裁础?/p>

正如我們所知,Javascrip的復(fù)雜類(lèi)型都是對(duì)象類(lèi)型(Object),而js不是一門(mén)完全面對(duì)對(duì)象編程的語(yǔ)言。那么對(duì)于對(duì)象編程來(lái)說(shuō)要考慮對(duì)象的繼承。

js實(shí)現(xiàn)繼承的核心就是原型鏈。我理解的就是原型鏈的存在就是js中的繼承機(jī)制,保證函數(shù)或?qū)ο笾械姆椒?,屬性可以向下傳遞。

js使用了構(gòu)造函數(shù)來(lái)創(chuàng)建對(duì)象,如下,我們可以通過(guò)構(gòu)造函數(shù)來(lái)定義一個(gè)類(lèi):

// 構(gòu)造函數(shù)
function Person(name, age) {
    this.name = name;
    this.age = age;
}

// 生成實(shí)例
const p = new Person('zhangsan', 18);

1692167778_64dc6e62b659f0a4498b9.png!small?16921677793501692167778_64dc6e62b659f0a4498b9.png!small?1692167779350

可以看到這個(gè)類(lèi)除了我們定義的兩個(gè)屬性以外,還有一個(gè)prototype的屬性。prototype指向函數(shù)的原型對(duì)象,這是一個(gè)顯式原型屬性,只有函數(shù)才擁有該屬性。

prototype也擁有兩個(gè)屬性:

constructor:指向原型的構(gòu)造函數(shù)

prototype:指向了Object的原型

在prototype的屬性中有一個(gè)_proto_,那么這個(gè)_proto_與prototype又有什么關(guān)系?

1692167810_64dc6e826449231561148.png!small?16921678110881692167810_64dc6e826449231561148.png!small?1692167811088

原型prototype是類(lèi)的一個(gè)屬性,而所有用類(lèi)實(shí)例化的對(duì)象,都將擁有這個(gè)屬性中的所有內(nèi)容,包括變量和方法。比如上圖中的p對(duì)象,其天生就具有類(lèi)Person的屬性和方法。

我們可以通過(guò)Person.prototype來(lái)訪問(wèn)Person類(lèi)的原型,但Person實(shí)例化出來(lái)的對(duì)象,是不能通過(guò)prototype訪問(wèn)原型的。這時(shí)候,就該__proto__登場(chǎng)了。

也就是類(lèi)可以用prototype來(lái)訪問(wèn)類(lèi)的原型,而實(shí)例化的對(duì)象可以用_proto_來(lái)訪問(wèn)對(duì)象所在類(lèi)的prototype屬性。

總結(jié):

其實(shí)我們只要明白一點(diǎn)就可以了,JavaScript原型鏈?zhǔn)莏s中實(shí)現(xiàn)繼承的核心,js的對(duì)象都會(huì)執(zhí)行其它的原型,最后指向的原型為null。最后關(guān)于原型鏈再來(lái)總結(jié)一下

1)js是通過(guò)原型鏈來(lái)實(shí)現(xiàn)繼承的。

2)所有類(lèi)對(duì)象在實(shí)例化的時(shí)候?qū)?huì)擁有prototype中的屬性和方法

3)類(lèi)可以使用prototype來(lái)訪問(wèn)類(lèi)的原型對(duì)象,而實(shí)例化對(duì)象可以通過(guò)_proto_來(lái)訪問(wèn)類(lèi)的原型對(duì)象

let f = new Foo();
f.constructor === Foo;
f._proto_ === Foo.prototype
f._proto_ === Foo.prototype
Foo._proto_ === Function.prototype

原型鏈污染

在了解了原型鏈的相關(guān)知識(shí)以后,可以來(lái)看看竟然什么是原型鏈污染漏洞。

上面說(shuō)過(guò)實(shí)例化對(duì)象的__proto__指向了類(lèi)的prototype。那么,如果我們修改了實(shí)例化對(duì)象__proto__中的值,是不是就可以修改類(lèi)中的值呢?是否可以影響所有和這個(gè)對(duì)象來(lái)自同一個(gè)類(lèi)、父祖類(lèi)的對(duì)象?

其實(shí)這就是原型鏈污染的原理。我們通過(guò)修改實(shí)例化對(duì)象的__proto__中的值,污染了類(lèi)本體,進(jìn)而影響所有和這個(gè)對(duì)象來(lái)自同一個(gè)類(lèi)、父祖類(lèi)的對(duì)象。

p神的博客上有一個(gè)這樣的例子,用來(lái)說(shuō)明原型鏈污染:

1692167987_64dc6f332874455dd5d81.png!small?16921679878361692167987_64dc6f332874455dd5d81.png!small?1692167987836

實(shí)際情況下利用分析

在實(shí)際的情況中,我們可能只能控制部分參數(shù),那么我們?cè)趺床拍転開(kāi)_proto__賦值呢?

要為_(kāi)_proto__賦值就要求__proto__作為變量傳進(jìn)去并且作為鍵名,這種情況一般出現(xiàn)在下面的三種場(chǎng)景中:

  • 對(duì)象merge
  • 對(duì)象clone(其實(shí)內(nèi)核就是將待操作的對(duì)象merge到一個(gè)空對(duì)象中)
  • 路徑查找屬性然后修改屬性的時(shí)候

下面借用p神文章中的一個(gè)例子來(lái)看看具體操作,原文鏈接為:https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html

以對(duì)象merge為例,我們想象一個(gè)簡(jiǎn)單的merge函數(shù):

function merge(target, source) {
    for (let key in source) {
        if (key in source && key in target) {
            merge(target[key], source[key])
        } else {
            target[key] = source[key]
        }
    }
}

在合并的過(guò)程中,存在賦值的操作target[key] = source[key],那么,這個(gè)key如果是__proto__,是不是就可以原型鏈污染呢?

let o1 = {}
let o2 = {a: 1, "__proto__": {b: 2}}
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)

結(jié)果是,合并雖然成功了,但原型鏈沒(méi)有被污染:

1692168050_64dc6f7280e79c362a397.png!small?16921680511941692168050_64dc6f7280e79c362a397.png!small?1692168051194

這是因?yàn)?,我們用JavaScript創(chuàng)建o2的過(guò)程(let o2 = {a: 1, "__proto__": {b: 2}})中,__proto__已經(jīng)代表o2的原型了,此時(shí)遍歷o2的所有鍵名,你拿到的是[a, b],__proto__并不是一個(gè)key,自然也不會(huì)修改Object的原型。從下面的圖中也可以看出,在o1中,參數(shù)b并沒(méi)有出現(xiàn)在原型中。

1692168062_64dc6f7e3ea57daf7bf33.png!small?16921680629431692168062_64dc6f7e3ea57daf7bf33.png!small?1692168062943

那么,如何讓__proto__被認(rèn)為是一個(gè)鍵名呢?

我們將代碼改成如下:

let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge(o1, o2)
console.log(o1.a, o1.b)

o3 = {}
console.log(o3.b)

可見(jiàn),新建的o3對(duì)象,也存在b屬性,說(shuō)明Object已經(jīng)被污染

1692168090_64dc6f9ae493107bec1d4.png!small?16921680914831692168090_64dc6f9ae493107bec1d4.png!small?1692168091483

這是因?yàn)?,JSON解析的情況下,__proto__會(huì)被認(rèn)為是一個(gè)真正的“鍵名”,而不代表“原型”,所以在遍歷o2的時(shí)候會(huì)存在這個(gè)鍵。

再來(lái)看看o1發(fā)現(xiàn),b屬性是定義在原型之中的。

1692168096_64dc6fa0980dab3967fd7.png!small?16921680972121692168096_64dc6fa0980dab3967fd7.png!small?1692168097212

merge操作是最常見(jiàn)可能控制鍵名的操作,也最能被原型鏈攻擊,很多常見(jiàn)的庫(kù)都存在這個(gè)問(wèn)題。

js原型鏈污染漏洞分析

接下來(lái)用一個(gè)cve漏洞來(lái)具體再看一下這個(gè)漏洞。

3.4.0版本之前的jQuery存在一個(gè)原型污染漏洞CVE-2019-11358,PoC如下。

//代碼如下,如果從前端接收一個(gè)json內(nèi)容,傳到后端。
//json內(nèi)容:JSON.parse('{"__proto__": {"z": 123}}')

const json1 = ajax();  
jQuery.extend(true, {}, JSON.parse(json1));
console.log( "test" in {} ); // true

jQuery.extend () 函數(shù)用于將一個(gè)或多個(gè)對(duì)象的內(nèi)容合并到目標(biāo)對(duì)象

$.extend( [deep ], target, object1 [, objectN ] )

參數(shù)

描述

deep

可選。 Boolean類(lèi)型 指示是否深度合并對(duì)象,默認(rèn)為false。如果該值為true,且多個(gè)對(duì)象的某個(gè)同名屬性也都是對(duì)象,則該"屬性對(duì)象"的屬性也將進(jìn)行合并。

target

Object類(lèi)型 目標(biāo)對(duì)象,其他對(duì)象的成員屬性將被附加到該對(duì)象上。

object1

可選。 Object類(lèi)型 第一個(gè)被合并的對(duì)象。

objectN

可選。 Object類(lèi)型 第N個(gè)被合并的對(duì)象。

再來(lái)看看實(shí)際的代碼是如何去寫(xiě)入的。

首先下載jQuery,這里下載的是3.3.0版本

https://github.com/jquery/jquery/tree/3.3.0

在src/core.js中文件中可以找到該extend函數(shù)??催^(guò)源碼,可以發(fā)現(xiàn)該函數(shù)的正好符合上面說(shuō)的合并數(shù)據(jù)的概念,那么來(lái)看看它到底會(huì)不會(huì)被污染?

1692168161_64dc6fe1e3ff617f47974.png!small?16921681626551692168161_64dc6fe1e3ff617f47974.png!small?1692168162655

我們來(lái)動(dòng)態(tài)調(diào)試一下這個(gè)程序:

引入jQuery腳本,并設(shè)置斷點(diǎn),進(jìn)行調(diào)試

1692168167_64dc6fe7b978b4973c2cd.png!small?16921681683931692168167_64dc6fe7b978b4973c2cd.png!small?1692168168393

首先根據(jù)第一個(gè)參數(shù)判斷是否進(jìn)行深度拷貝,然后進(jìn)行第一次循環(huán),取得參數(shù)為_(kāi)_proto__

1692168172_64dc6fecc462985824a7e.png!small?16921681735221692168172_64dc6fecc462985824a7e.png!small?1692168173522

第二次循環(huán),在__proto__中去參數(shù)進(jìn)行賦值

1692168177_64dc6ff18c0335618e4f2.png!small?16921681781851692168177_64dc6ff18c0335618e4f2.png!small?1692168178185

此時(shí)再看原型已經(jīng)被污染了

1692168182_64dc6ff620c4ded5d0a06.png!small?16921681827161692168182_64dc6ff620c4ded5d0a06.png!small?1692168182716

總結(jié)

js原型鏈污染可以說(shuō)原理并不是太難懂,關(guān)鍵是實(shí)際中如何去利用。關(guān)于這個(gè)漏洞也是看了很多大神的文章,它們的思路真的太厲害了,我還有很多需要學(xué)習(xí)的,跟大家一起共勉。

由于本人水平有限,文章中可能會(huì)出現(xiàn)一些錯(cuò)誤,歡迎各位大佬指正,感激不盡。如果有什么好的想法也歡迎交流,謝謝大家了~~

參考鏈接

https://www.freebuf.com/articles/web/275619.html

https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html

https://xz.aliyun.com/t/7025

https://www.freebuf.com/articles/web/264966.html

本文作者:, 轉(zhuǎn)載請(qǐng)注明來(lái)自FreeBuf.COM

責(zé)任編輯:武曉燕 來(lái)源: FreeBuf.COM
相關(guān)推薦

2020-02-20 14:00:15

JavaScript原型原型鏈

2016-06-07 14:28:39

Javascript原型

2023-04-07 09:07:11

2017-04-07 11:15:49

原型鏈原型Javascript

2012-11-08 10:40:47

JavaScript原型鏈

2020-10-20 08:35:34

JS基礎(chǔ)進(jìn)階

2022-05-26 09:20:01

JavaScript原型原型鏈

2021-05-10 06:11:24

前端原型鏈污染漏洞服務(wù)器shell

2012-01-05 15:07:11

JavaScript

2016-05-06 14:02:18

JavaScript原型鏈

2024-08-09 12:44:45

JavaScript原型鏈鏈條

2017-05-05 10:31:35

JavaScriptprototype__proto__

2022-03-29 09:15:55

Javascript函數(shù)屬性

2016-12-27 09:10:29

JavaScript原型鏈繼承

2011-08-31 14:48:33

JavaScript

2020-09-10 07:04:30

JSJavaScript 原型鏈

2024-08-27 12:36:33

2021-11-15 06:00:14

JSPanda掃描漏洞

2019-02-27 16:00:48

JS原型原型鏈對(duì)象

2024-06-18 08:31:33

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)