JavaScript オブジェクトのプロトタイプの操作による Node.js への攻撃

ヘルムホルツ情報セキュリティセンター (CISPA) と王立工科大学 (スウェーデン) の研究者は、Node.js プラットフォームとそれに基づく一般的なアプリケーションに対する攻撃を作成し、コードの実行につながる JavaScript プロトタイプ汚染手法の適用可能性を分析しました。

プロトタイプ汚染メソッドは、任意のオブジェクトのルート プロトタイプに新しいプロパティを追加できる JavaScript 言語の機能を使用します。 アプリケーションには、置換されたプロパティによって動作が影響を受けるコード ブロック (ガジェット) が含まれる場合があります。たとえば、コードには 'const cmd = options.cmd || のような構成が含まれる場合があります。 「/bin/sh」。攻撃者がルート プロトタイプの「cmd」プロパティを置き換えることができた場合、ロジックが変更されます。

攻撃が成功するには、アプリケーションが外部データを使用してオブジェクトのルート プロトタイプに新しいプロパティを作成できること、および実行時に変更されたプロパティに依存するガジェットが発生することが必要です。 プロトタイプの変更は、Node.js の「__proto__」および「constructor」サービス プロパティを処理することで実現されます。 「__proto__」プロパティはオブジェクトのクラスのプロトタイプを返し、「constructor」プロパティはオブジェクトの作成に使用される関数を返します。

アプリケーションコードに「obj[a][b] = value」という割り当てが含まれており、その値が外部データから設定されている場合、攻撃者は「a」を値「__proto__」に設定し、独自のプロパティのインストールを達成することができます。オブジェクトのルート プロトタイプ (obj.__proto__.b = value;) に名前「b」と値「value」が設定されており、プロトタイプに設定されたプロパティはすべてのオブジェクトで表示されます。 同様に、コードに「obj[a][b][c] = value」のような式が含まれている場合は、既存のすべてのオブジェクトで「a」を「constructor」の値に、「b」を「prototype」に設定することで、次のことができます。名前「c」と値「value」を持つ新しいプロパティを定義します。

プロトタイプの変更例: const o1 = {}; const o2 = 新しいオブジェクト(); o1.__proto__.x = 42; // ルート プロトタイプ console.log (o2.x) にプロパティ「x」を作成します。 // 別のオブジェクトからプロパティ「x」にアクセスします // ルート プロトタイプはオブジェクト o42 を通じて変更されており、オブジェクト o1 でも使用されているため、出力は 2 になります

脆弱なコードの例: functionentryPoint (arg1, arg2, arg3){ const obj = {}; const p = obj[arg1]; p[arg2] = arg3; p を返します。 }

entryPoint 関数の引数が入力データから形成されている場合、攻撃者は値「__proto__」を arg1 に渡し、ルート プロトタイプに任意の名前のプロパティを作成できます。 arg2 に値「toString」を渡し、arg3 に値 1 を渡すと、「toString」プロパティ (Object.prototype.toString=1) を定義して、toString() の呼び出し中にアプリケーションをクラッシュさせることができます。

攻撃者のコード実行につながる可能性のある状況の例には、「main」、「shell」、「exports」、「contextExtensions」、および「env」プロパティの作成が含まれます。 たとえば、攻撃者はオブジェクトのルート プロトタイプに「main」プロパティを作成し、そこにスクリプトへのパス (Object.prototype.main = “./../../pwned.js”) を書き込むことができます。このプロパティは、含まれるパッケージが package.json で "main" プロパティを明示的に定義していない場合 (プロパティが定義されていない場合、ルート プロトタイプから取得されます)。 「shell」、「exports」、および「env」プロパティも同様に置き換えることができます。 rootProto["exports"] = {".":"./changelog.js"}; rootProto["1"] = "/path/to/npm/scripts/"; // トリガー呼び出し require("./target.js"); Object.prototype.main = "/path/to/npm/scripts/changelog.js"; Object.prototype.shell = "ノード"; Object.prototype.env = {}; Object.prototype.env.NODE_OPTIONS = "—inspect-brk=0.0.0.0:1337"; // トリガー呼び出し require("bytes");

研究者らは、最も多くの依存関係を持つ 10 個の NPM パッケージを分析したところ、そのうち 1958 個が package.json に main プロパティを持たず、4420 個が require ステートメントで相対パスを使用し、355 個がコマンド置換 API を直接使用していることを発見しました。

実用的な例は、evalFunctions プロパティをオーバーライドする Parse Server バックエンドを攻撃するためのエクスプロイトです。 このような脆弱性の特定を簡素化するために、静的分析方法と動的分析方法を組み合わせたツールキットが開発されました。 Node.js のテスト中に、攻撃者のコードの実行につながる攻撃を組織するために使用できる 11 個のガジェットが特定されました。 Parse Server に加えて、NPM CLI にも XNUMX つの悪用可能な脆弱性が確認されました。

出所: オープンネット.ru

コメントを追加します