原型链污染笔记
个人总结
参考:https://portswigger.net/web-security/prototype-pollution
- name: 个人总结
desc: 参考:https://portswigger.net/web-security/prototype-pollution
bgColor: '#F0DFB1'
textColor: 'green'
2
3
4
# 原型链污染笔记
# 1JavaScript原型和继承基本知识
笔者建议先去学习一下 JavaScript 这门程序设计语言,以更好地理解 JavaScript 中的原型和继承。
# 1、JavaScript语言中的原型继承模型
答案
在实现面向对象编程时
- 许多其他语言使用的是 “基于类的模型”
- 而 JavaScript 则使用 “原型继承模型”
# 2、JavaScript对象?
答案
JavaScript 对象实际上只是一个被称为 “属性” 的键值对集合。注意,JavaScript 中没有 “类” 的概念,它可以直接创建一个对象:
// 直接创建 “对象”
const user = {
username: "wiener",
userId: 01234,
isAdmin: false
}
2
3
4
5
6
以下是 PHP 语言中的一个 “类” 和 “对象”:
// 需要先创建 “类” 才能创建 “对象”
class user {
var $username;
var $userId;
var $isAdmin;
}
$myUser = new user;
$myUser->username = "wiener";
$myUser->userId = 01234;
$myUser->isAdmin = false;
2
3
4
5
6
7
8
9
10
11
# 3、JavaScript原型?
答案
JavaScript 中的每个对象都拥有一个 “原型”,原型可以理解为这个对象的 “祖宗”,对象会从自己的原型(祖宗)身上继承一些属性和方法。
- 例如,当你在 JavaScript 中创建一个字符串时,这个字符串会自动从
String
原型(字符串原型)身上继承一些默认属性,以及用于处理字符串的各种内置方法。
另外,如果当前对象的身上已经定义了一个 “同名” 的属性或方法,则它不会从原型那里继承该属性 / 方法。(对象自身的属性 优先于 原型身上的属性)
# 4、对象继承在JavaScript中的工作方式?
答案
当你创建了一个对象,并试图访问该对象上的某个属性时:
- JavaScript 引擎首先会在对象自身上寻找这个属性,如果存在该属性,则返回给用户。
- 如果对象自身没有这个属性,那么 JavaScript 就会访问该对象的原型(祖宗),如果原型身上存在该属性,则将原型上的对应属性返回给用户。
- 如果对象自身 和 该对象的原型,两者都没有这个属性,则 JavaScript 会抛出错误信息 “找不到该属性” 或者 “该属性未定义” 并终止程序的运行
# 5、原型链
答案
一个对象的原型 其实就是 另一个对象,而这个对象也应该有自己的原型,以此类推。
- 例如,
A
对象的原型是B
对象,B
对象的原型是X
对象,X
对象的原型是Y
对象(A -> B -> X -> Y
) A
对象会从Y
对象(最远的祖宗)开始,一层一层往下继承属性,后继承的属性 会覆盖掉 先继承的属性(A
自身的属性优先级最高,Y
原型的属性优先级最低)- 这些对象互相链接,构成了一条 “原型链”
一般来说,在 JavaScript 中这条原型链最终会回到顶级的Object.prototype
身上,其原型是一个null
(空原型,它已经没有祖宗了)
# 6、如何访问原型
答案
每个对象都具有一个特殊的属性,你可以通过该属性来访问该对象的原型。虽然这个特殊属性还没有一个正式的标准化名称,但__proto__
是大多数浏览器支持的事实标准。
与任何属性一样,你可以使用括号或点号表示法来访问__proto__
:
username.__proto__
username['__proto__']
2
你甚至可以将__proto__
的引用全部链接在一起,从而沿着原型链访问上一层级:
username.__proto__ // String.prototype
username.__proto__.__proto__ // Object.prototype
username.__proto__.__proto__.__proto__ // null
2
3
# 7、如何修改原型
原型实际上也是一个对象,和修改对象的方式是一样的。
笔记
# 2原型链污染基本知识
# 1、什么是原型链污染?
答案
原型链污染是一种 JavaScript 漏洞,攻击者可以向全局对象的原型添加任意属性,然后这些属性可能会被用户定义的对象所继承。
# 2、原型链污染可以作为一个独立的漏洞来利用?
判断
答案
不可以。尽管 原型链污染 通常无法作为一个独立漏洞来利用,但它允许攻击者控制原本无法访问的对象属性。随后,如果应用程序以不安全的方式来处理攻击者所控属性,则这可能会链接其他漏洞。
- 在客户端 JavaScript 中,这通常会导致 DOM型XSS
- 而在服务端原型链污染中,这甚至会导致远程代码执行
# 3、原型链污染漏洞是如何产生的?
答案
攻击者传递一个带有__proto__
属性的恶意对象,应用程序没有过滤危险的键名称,直接将这个恶意属性 合并到了 现有的对象当中。
- 现有对象将
__proto__
解析为自身的原型,然后将恶意的属性值赋给了原型。 - 由于 “继承” 特性的存在,在这个原型链中,后续创建的任何新对象,都会从这个原型身上继承恶意属性。
- 随后,应用程序不规范地使用新对象上的恶意属性,产生实际的漏洞利用。
# 4、原型链污染的组成部分?
答案
成功的原型链污染需要以下关键组成部分:
# 5、原型污染源
答案
- 通过URL污染原型
- 通过JSON输入污染原型
- Web 消息(这个没有链接,官方资料中没提到)
# 6、原型污染接收器
答案
原型污染接收器本质上只是一个 JavaScript 函数或 DOM 元素,你可以通过被污染的原型来访问它,它能够使你执行任意 JavaScript 或系统命令。我们在 DOM XSS (opens new window) 主题中广泛介绍了一些客户端接收器。
# 7、原型污染小工具
答案
原型污染小工具实际上就是一个 “攻击者可控的属性”。
- 攻击者污染一个原型(污染源)
- 某个对象从该原型身上继承被污染的属性,从而产生一个恶意版本的对象(小工具)
- 然后这个对象属性被传递到不安全的接收器当中(接收器)
# 3客户端原型链污染漏洞
# 1、客户端原型链污染的执行步骤?
# 2、__proto__属性的替代品?
答案
- 在当前对象上,一般会使用
__proto__
属性来访问原型。 - 如果关键字 “__proto__” 被过滤,则可以先通过
constructor
属性得到当前对象的 “构造函数”,然后在构造函数上通过prototype
属性来获得 “构造函数的原型”。而 “构造函数的原型” 就是 “当前对象的原型”。
// 两种方式都可以引用当前对象的原型
let myObject = {};
myObject.__proto__ // 直接得到原型 “当前对象 >> 原型”
myObject.constructor.prototype // 间接得到原型 “当前对象 >> 构造函数 >> 原型”
2
3
4
5
# 3、什么是构造函数?
答案
用来创建当前对象的函数,被称为这个对象自身的构造函数。例如:
- 创建了一个字符串对象
- 该字符串的原型为
String
- 该字符串的构造函数为
String()
- 构造函数
String()
的原型又为String
- 该字符串的原型为
- 可以理解为 “字符串对象” 的爹是
String()
,而他俩共同的祖先是String
# 4、一些绕过脆弱防御措施的方式
# 5、DOM Invader的使用
# 4通过浏览器APIs实现客户端原型链污染
# 1、一些常用的浏览器APIs
实际上就是 JavaScript 中的一些内置函数。
答案
fetch()
,一种使用 JavaScript 发起 HTTP 请求的简单方式。Object.defineProperty()
,可以将某个对象上的属性设置为 “不可配置”、“不可写” 等,从而阻止该对象自动继承属性。
# 2、通过浏览器APIs实现客户端原型链污染
# 5服务器原型链污染漏洞
# 1、服务端上的JavaScript?
答案
JavaScript 最初是一种客户端语言,被设计在浏览器中运行。
然而,由于服务端运行时的出现,例如非常流行的 Node.js,致使 JavaScript 现在被广泛用于构建服务器、APIs 和其他后端应用程序。从逻辑上讲,这意味着 原型链污染漏洞 也可能出现在服务器端环境中。
# 2、为什么服务端原型链污染更难被检测到?
答案
出于多种原因,服务端原型链污染 通常比客户端变体更难检测:
- 无法访问源代码 - 与客户端漏洞不同,你通常无法访问服务器上的易受攻击 JavaScript。这意味着,无法简单地了解到目标存在哪些接收器,又或是发现潜在的小工具属性。
- 缺乏开发者工具 - 由于 JavaScript 运行在远程系统上,因此你无法像使用浏览器的 DevTools 检查 DOM 时那样在运行时检查对象。这意味着,你很难判断你是否已经成功地污染了原型,除非你已经造成了网站行为的明显变化。显然,在白盒测试中不会受到这个限制。
- DoS 问题 - 在服务端环境中,如果使用真实的属性来污染其上的对象,通常会破坏应用程序功能 或 使服务器完全瘫痪。这很容易在无意中导致拒绝服务(DoS),因此,在生产环境中进行测试可能很危险。就算你真的发现了一个污染,但你在此过程中已经破坏了网站,接下来想要将其构造成漏洞利用会变得非常棘手。
- 污染持久性 - 在浏览器中进行测试时,你只需要简单地刷新页面,即可撤消所有更改 并 重新获得干净的环境。一旦污染了服务端原型,这种更改将在 Node 进程的整个生命周期内持续存在,并且你无法重置它。
# 3、一些检测服务端原型链污染的技术
# 4、自动扫描服务端原型污染源
# 5、一些绕过脆弱防御措施的方式
这部分内容和 “客户端原型链污染” 是相同的。