NodeJS - __proto__ & prototype Pollution
JavaScriptのオブジェクト
JavaScriptのオブジェクトは、本質的にキーと値のペアのコレクションであり、プロパティとして知られています。オブジェクトは、Object.create
を使用してnull
を引数に指定することで空のオブジェクトを生成できます。このメソッドは、継承されたプロパティなしでオブジェクトを作成することを可能にします。
空のオブジェクトは空の辞書に似ており、{}
として表されます。
JavaScriptの関数とクラス
JavaScriptでは、クラスと関数は密接に関連しており、関数はしばしばクラスのコンストラクタとして機能します。JavaScriptにはネイティブのクラスサポートがないにもかかわらず、コンストラクタはクラスの動作をエミュレートできます。
Prototypes in JavaScript
JavaScriptは、プロトタイプ属性の変更、追加、または削除をランタイムで許可します。この柔軟性により、クラス機能の動的拡張が可能になります。
toString
やvalueOf
のような関数は、その動作を変更するために変更可能であり、JavaScriptのプロトタイプシステムの適応性を示しています。
Inheritance
プロトタイプベースのプログラミングでは、プロパティ/メソッドはクラスからオブジェクトに継承されます。これらのクラスは、別のクラスのインスタンスまたは空のオブジェクトにプロパティ/メソッドを追加することで作成されます。
プロトタイプとして他のオブジェクトに機能するオブジェクト(例えばmyPersonObj
)にプロパティが追加されると、継承するオブジェクトはこの新しいプロパティにアクセスできることに注意が必要です。ただし、このプロパティは明示的に呼び出されない限り、自動的には表示されません。
__proto__ pollution
Exploring Prototype Pollution in JavaScript
JavaScriptオブジェクトはキーと値のペアによって定義され、JavaScriptオブジェクトプロトタイプから継承されます。これは、オブジェクトプロトタイプを変更することで、環境内のすべてのオブジェクトに影響を与える可能性があることを意味します。
別の例を使って説明しましょう:
Objectプロトタイプへのアクセスは、次の方法で可能です:
Objectプロトタイプにプロパティを追加することで、すべてのJavaScriptオブジェクトはこれらの新しいプロパティを継承します:
プロトタイプ汚染
__proto__
の使用が制限されているシナリオでは、関数のプロトタイプを変更することが代替手段です:
これは、Vehicle
コンストラクタから作成されたオブジェクトのみに影響を与え、beep
、hasWheels
、honk
、および isElectric
プロパティを与えます。
プロトタイプ汚染を通じてJavaScriptオブジェクトにグローバルに影響を与える2つの方法は次のとおりです:
Object.prototype
を直接汚染すること:
一般的に使用される構造体のコンストラクタのプロトタイプを汚染すること:
これらの操作の後、すべてのJavaScriptオブジェクトはgoodbye
およびgreet
メソッドを実行できます。
他のオブジェクトを汚染する
クラスからObject.prototypeへ
特定のオブジェクトを汚染でき、Object.prototype
に到達する必要があるシナリオでは、次のようなコードでそれを検索できます:
Array elements pollution
オブジェクトの属性を汚染できるように、JSで配列にアクセスして汚染できる場合、インデックスによってアクセス可能な配列の値も汚染できます(値を上書きすることはできないので、何らかの形で使用されているが書き込まれていないインデックスを汚染する必要があります)。
Html elements pollution
JSを介してHTML要素を生成する際、innerHTML
属性を上書きして任意のHTMLコードを書き込むことが可能です。この書き込みからのアイデアと例。
例
基本的な例
プロトタイプ汚染は、Object.prototype
のプロパティを上書きすることを許可するアプリケーションの欠陥によって発生します。これは、ほとんどのオブジェクトがObject.prototype
からプロパティを継承することを意味します。
最も簡単な例は、チェックされるオブジェクトの未定義の属性に値を追加することです。
もし属性 admin
が未定義 の場合、PPを悪用してTrueに設定することが可能です。
このメカニズムは、攻撃者が特定の入力を制御できる場合、アプリケーション内のすべてのオブジェクトのプロトタイプを変更できるようにプロパティを操作することに関係しています。この操作は通常、__proto__
プロパティを設定することを含み、JavaScriptではオブジェクトのプロトタイプを直接変更することと同義です。
この攻撃が成功裏に実行される条件は、特定の研究に概説されているように、以下を含みます:
再帰的マージを実行すること。
パスに基づいてプロパティを定義すること。
オブジェクトをクローンすること。
Override function
Proto Pollution to RCE
Prototype Pollution to RCE他のペイロード:
クライアントサイドのプロトタイプ汚染からXSSへ
Client Side Prototype PollutionCVE-2019–11358: jQuery $ .extendを通じたプロトタイプ汚染攻撃
詳細についてはこの記事を参照してください jQueryでは、$ .extend
関数が深いコピー機能を不適切に利用するとプロトタイプ汚染を引き起こす可能性があります。この関数は、オブジェクトのクローンやデフォルトオブジェクトからのプロパティのマージによく使用されます。しかし、誤って設定された場合、新しいオブジェクト用のプロパティがプロトタイプに割り当てられることがあります。例えば:
この脆弱性はCVE-2019–11358として特定されており、ディープコピーがプロトタイプを意図せずに変更する方法を示しています。これにより、isAdmin
のようなプロパティが適切な存在確認なしにチェックされると、未承認の管理者アクセスなどの潜在的なセキュリティリスクが生じる可能性があります。
CVE-2018–3721、CVE-2019–10744: lodashによるプロトタイプ汚染攻撃
Lodashは、同様のプロトタイプ汚染脆弱性(CVE-2018–3721、CVE-2019–10744)に直面しました。これらの問題はバージョン4.17.11で対処されました。
CVEを含む別のチュートリアル
プロトタイプ汚染を検出するためのツール
Server-Side-Prototype-Pollution-Gadgets-Scanner: ウェブアプリケーションにおけるサーバーサイドのプロトタイプ汚染脆弱性を検出および分析するために設計されたBurp Suite拡張機能。このツールは、リクエストをスキャンして潜在的なプロトタイプ汚染の問題を特定するプロセスを自動化します。既知のガジェット - プロトタイプ汚染を利用して有害なアクションを実行する方法 - を悪用し、特にNode.jsライブラリに焦点を当てています。
server-side-prototype-pollution: この拡張機能は、サーバーサイドのプロトタイプ汚染脆弱性を特定します。サーバーサイドプロトタイプ汚染で説明されている技術を使用しています。
NodeJSにおけるASTプロトタイプ汚染
NodeJSは、テンプレートエンジンやTypeScriptなどの機能のためにJavaScriptで抽象構文木(AST)を広範に利用しています。このセクションでは、特にHandlebarsとPugのテンプレートエンジンに関連するプロトタイプ汚染に関する脆弱性を探ります。
Handlebars脆弱性分析
Handlebarsテンプレートエンジンは、プロトタイプ汚染攻撃に対して脆弱です。この脆弱性は、javascript-compiler.js
ファイル内の特定の関数から生じます。例えば、appendContent
関数は、pendingContent
が存在する場合にそれを連結し、pushSource
関数はソースを追加した後にpendingContent
をundefined
にリセットします。
悪用プロセス
悪用は、Handlebarsによって生成されたAST(抽象構文木)を利用し、以下の手順に従います:
パーサーの操作: 最初に、
NumberLiteral
ノードを介してパーサーは値が数値であることを強制します。プロトタイプ汚染はこれを回避でき、非数値の文字列を挿入することが可能になります。コンパイラによる処理: コンパイラはASTオブジェクトまたは文字列テンプレートを処理できます。
input.type
がProgram
に等しい場合、入力は事前に解析されたものとして扱われ、これを悪用できます。コードの注入:
Object.prototype
の操作を通じて、テンプレート関数に任意のコードを注入でき、リモートコード実行につながる可能性があります。
Handlebarsの脆弱性を悪用する例:
このコードは、攻撃者がHandlebarsテンプレートに任意のコードを注入する方法を示しています。
外部参照: プロトタイプ汚染に関連する問題が「flat」ライブラリで見つかりました。詳細はこちら: GitHubの問題。
外部参照: 「flat」ライブラリにおけるプロトタイプ汚染に関連する問題
Pythonにおけるプロトタイプ汚染の悪用の例:
Pugの脆弱性
Pugは、別のテンプレートエンジンであり、プロトタイプ汚染の同様のリスクに直面しています。詳細な情報は、PugにおけるASTインジェクションの議論で入手できます。
Pugにおけるプロトタイプ汚染の例:
予防策
プロトタイプ汚染のリスクを減らすために、以下の戦略を採用できます:
オブジェクトの不変性:
Object.prototype
をObject.freeze
を適用することで不変にできます。入力検証: JSON入力はアプリケーションのスキーマに対して厳密に検証する必要があります。
安全なマージ関数: 再帰的なマージ関数の安全でない使用は避けるべきです。
プロトタイプのないオブジェクト: プロトタイププロパティのないオブジェクトは
Object.create(null)
を使用して作成できます。Mapの使用: キーと値のペアを保存するために
Object
の代わりにMap
を使用すべきです。ライブラリの更新: 定期的にライブラリを更新することでセキュリティパッチを組み込むことができます。
リンターと静的解析ツール: プロトタイプ汚染の脆弱性を検出し防止するために、適切なプラグインを持つESLintなどのツールを使用します。
コードレビュー: プロトタイプ汚染に関連する潜在的なリスクを特定し修正するために徹底的なコードレビューを実施します。
セキュリティトレーニング: 開発者にプロトタイプ汚染のリスクと安全なコードを書くためのベストプラクティスについて教育します。
ライブラリの使用に注意: サードパーティのライブラリを使用する際は注意が必要です。特にオブジェクトを操作するものについては、そのセキュリティ姿勢を評価し、コードをレビューします。
ランタイム保護: プロトタイプ汚染攻撃を検出し防止できるセキュリティ重視のnpmパッケージを使用するなど、ランタイム保護メカニズムを採用します。
参考文献
Last updated