免责声明
本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者及本公众号不为此承担任何责任。
引言
最近在研究开源软件供应链安全问题时,发现一个有意思的漏洞:CVE-2019-10744。JavaScript的lodash
库在调用函数defaultsDeep
时,攻击者可以精心构造一个Json输入,实现对目标系统的DoS,属性注入,甚至是代码执行,这就是JS原型链污染漏洞。
进一步研究后我发现,不仅仅是lodash
库曾经存在过这个漏洞,许多使用了merge功能的JS库还有CTF比赛中也存在这个问题。熟悉原型链污染的原理和利用方法,以及防御手段,十分必要。
本文中用于自动化检测JS原型链污染的代码已上传至GitHub:https://github.com/fatmo666/Proton-pollution-check,也可以点击阅读原文获取。
JavaScript原型
原型和原型链,其实就是JS中对象的prototype,__proto__两个属性,可以如下表格帮助认识:
属性名 | 作用 | |
---|---|---|
原型 | prototype | 所有JS对象都有的属性,Object类型,可包含属性和方法 |
原型链 | proton | 所有JS对象都有的属性,Object类型,指向该对象构造函数的prototype |
可以把原型和原型链理解成JS用于实现继承的一种方式(JS中没有类似C++的继承机制)。我的构造函数这个对象(JS中,函数也是一个对象)的prototype中携带了通用的属性和方法,我使用构造函数New出一个新对象时,可以通过新对象的__proton__找到构造函数的protontype对象,从而使用构造函数中携带的属性和方法,实现继承。
文字叙述比较绕,用一个简单的例子说明:
-
我们都知道,JS的Array()类型的对象有map和filter两个方法:
let numbers = [1, 2, 3, 4, 5];
let doubled = numbers.map(n => n * 2);
console.log(doubled); // Outputs: [2, 4, 6, 8, 10]
let doubled1 = [1, 2, 4, 6, 7, 8, 10];
let even = doubled1.filter(n => n % 2 === 0);
console.log(even); // Outputs: [2, 4, 6, 8, 10]
2. 我们初始化了两个Array,分别是numbers和doubled1,它们就天然可以使用map和filter两个方法,就是因为Array()对象的protontype中实现了这两个方法:
3. 在代码里,我们执行了doubled1.filter(n => n % 2 === 0);,此时在doubled对象中不存在filter方法,就会顺着__proto__去找它构造函数是否有__proto__方法,如果没有,继续往上找,找到后,就会调用该方法,这就是原型链,通过__proto不断向上寻找而形成的链条。
总结
本章讲述了JavaScript中原型和原型链的原理,本质上就是prototype,__proto__两个属性,而这正是JavaScript中的关键属性。下一章我们将介绍如何利用原型链污染进行攻击。
原文始发于微信公众号(赛博安全狗):原型链污染:从原理分析到批量刷洞(一) —— 原型与原型链
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论