fbpx

CVE-2022-32223:npm CLIによるDLLハイジャック #aqua #セキュリティ #CVE202232223

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

New call-to-action

本ブログは「Aqua Security」社の技術ブログで2022年7月12日に公開された「 CVE-2022-32223 Discovery: DLL Hijacking via npm CLI 」の日本語翻訳です。

CVE-2022-32223:npm CLIによるDLLハイジャック


Aqua のセキュリティ研究チームである Team Nautilus は、Windows 版 Node.js の 16.16.0(LTS)以前のすべての バージョンと14.20.0 において、動的リンクライブラリ(DLL)のハイジャックされる脆弱性を発見しました。この脆弱性は、OpenSSL がインストールされている環境で発生します。攻撃者は、この脆弱性を悪用して特権を昇格させ、標的の環境での永続性を確立できます。また、この脆弱性は、パッケージに悪意のあるコードを埋め込むための足掛かり可能性があります。

この脆弱性は、Node.js チームに報告され、最新のセキュリティリリースでパッチが適用されました。このリスクを軽減するために、Node.js の Windows ユーザは最新バージョンにアップグレードする必要があります。

このブログでは、CVE-2022-32223、DLL ハイジャックとは何か、私たちが新しい脆弱性を発見した方法、リポジトリのバイナリアーティファクトが危険である方法について説明します。

DLL ハイジャックとは

DLL ハイジャック攻撃は、バイナリプランティング攻撃またはプリロード攻撃とも呼ばれ、動的にロードされる共有ライブラリまたは共有オブジェクトをサポートするすべてのオペレーティングシステムに共通した手法です。これらの攻撃がどのように機能するかを見てみましょう。

アプリケーションが完全修飾パスを指定せずに DLL をロードすると、Windows はあらかじめ定義されたディレクトリパスから特定の順序で検索し、目的の DLL を見つけます。

もし攻撃者がディレクトリの1つを制御できるようになれば、アプリケーションに期待される DLL ではなく悪意のある DLL のコピーを使用させることができます。その意味で、DLL ハイジャックは、攻撃者がアプリケーションを実行するユーザのコンテキスト下でコードを実行可能にできます。

アプリケーションが管理者や高い権限で実行されている場合、これはローカルでの権限昇格につながる可能性があります。さらに、悪意のある攻撃者は、ファイル実行の制限を回避するため、または環境における永続性を確立するために、DLL ハイジャックを使用する可能性があります。

例えば、ロシアを拠点とする脅威グループ Turla が使用するバックドア「Crutch」は、Google Chrome、Mozilla Firefox、Microsoft OneDrive 上で DLL ハイジャックを介して永続化できます。

Windows検索順:概要

あるアプリケーションが DLL を読み込もうとする場合を考えてみましょう。安全な DLL 検索モードが有効で(デフォルトで SafeDllSearchMode は true に設定されています)、アプリケーションが別の検索順序を使用していない場合、次のようにディレクトリが検索されます

  1. アプリケーションがロードされているディレクトリ
  2. システムディレクトリ
  3. Windows ディレクトリ
  4. カレントワーキングディレクトリ
  5. PATH 変数に含まれるディレクトリ

DLL ハイジャックは、攻撃者が検索順序で検索されたディレクトリのいずれかに悪意のある DLL を配置し(書き込みアクセス権が必要)、目的の DLL が以前の検索で見つからなかった場合に発生します。

DLL ハイジャックは攻撃者にとって好都合です。DLL がロードされた直後に DllMain() が呼び出されるため、簡単にコードを実行できます。また、アプリケーションが署名されていないバイナリのロードを許可している場合、攻撃者は回避することを心配する必要はありません。

DLL の検索順序のどこに悪意のある DLL が仕込まれるかに基づいて、この脆弱性は3つのカテゴリのいずれかに分類されます。

  1. アプリケーションディレクトリ(App Dir)DLL プランティング
  2. カレントワーキングディレクトリ(CWD)の DLL 設置(今回発見した脆弱性はこれに該当する)
  3. PATH ディレクトリの DLL 設置(管理者権限が必要)

マイクロソフトセキュリティレスポンスセンターによると、CWD DLL プランティングは重要なセキュリティ問題であり、マイクロソフトはこの問題に対するパッチを発行するとのことです。

CVE-2022-32223の発見:詳細

私たちは、コマンドラインから npm コマンドを実行したときのある異常な動作に気づき、調査を開始しました。


プロセスモニター(Sysinternals)で、"Process Name" = "node.exe" と "NOT FOUND" 含む "Result" のフィルタリングを実施

上図では、npm コマンドを実行した後、node.exe は providers.dll という DLL を検索しています。

providers.dll は上で説明した DLL 検索順のどのパスにも存在しないため、現在の作業ディレクトリ内に仕込んでおけば、アプリケーションが検索順序にしたがって「悪意のある」providers.dll を読み込むことになります。

私たちは、この発見を実証するために概念実証(PoC)を用意しました。悪意のある DLL ファイル(providers.dll)を作成し、それをコンパイルしました。私たちの場合、calc.exe を開きます。以下のコードをご覧ください。

再び npm コマンド(例えば npm --version)を実行すると、「悪意のある」DLL のコードが実行されます。

根本的な原因を探る

そこで、再現手順と共に、新たな脆弱性として報告しました。しかし、この脆弱性の原因が一体何なのかは、依然として不明なままでした。この時点では、いくつかの未解決の問題がありました。

  • npm コマンドラインインタフェース(CLI)が providers.dll を検索する原因は何なのか
  • providers.dllが検索される前提条件はあるのか

npm CLIがproviders.dllを検索する理由

最初の疑問は、Node.js エンジンを使っていて、脆弱性を再現できないときに生じました。例えば、単純なコマンド、例えば console.log("*") を入力すると、Node.js は providers.dll ファイルを検索しません。このことから、Node.js はこの脆弱性の根本的な原因ではないと考えられました。

次に、この脆弱性は npm CLI が原因であると仮定しました。さらに、npm CLI の依存関係の流れを分析することで、この考えを検証しました。その結果、npm CLI は crypto、https、tls という3つの Node.js の組み込みモジュールを読み込もうとしていることがわかりました。

その結果、これら3つの Node.js 組み込みモジュールのそれぞれが、providers.dll ファイルを探していることが判明しました。つまり、脆弱性は npm CLI に起因するものではなく、Node.js エンジンのこれらのモジュールが、npm CLI を脆弱にする原因となっているのです。

以下は、npm CLI の依存関係のトレース分析です。

これらのモジュールに共通することは何でしょうか。これらはすべて OpenSSL に依存していることです。

まとめると、npm CLI が providers.dll を探す原因は、OpenSSL に関連する Node.js の3つの組み込みモジュールであることがわかりました。

CVE-2022-32223の条件を特定する

Node.js のみを搭載した Windows イメージのクリーンインストールでは、この脆弱性が再発しなかったことから、2つ目の疑問が浮かびました。

この挙動を発見した同じ Windows マシンで、Windows 用のオープンソースデバッガーである x64dbg を起動し、CLI から crypto モジュールを要求した後に Node.js をデバッグしてみました。

この後、kernel32.dll の LoadLibraryA にブレークポイントを設定し、provider.dll をロードしようとするすべての試みを捕捉するようにします。

次に、node.exe の呼び出し履歴を確認しました。ここで、2つの興味深い値を見ることができます。1つは provider_sect で、もう1つはパス C:\Program Files\Common Files\SSL\openssl.cn です。

次に、node.exe のフローを詳しく見てみました。プログラムは openssl.conf ファイルを読み込み、provider_sect に定義されている値を探します。この場合、この値は providers なので、デフォルトで providers.dll というファイルを探します。

さらに、provider_sect の値は任意の値に変更でき、node.exe がトリガーされると、カスタム DLL 名のロードを試行します。openssl.cnf の編集には管理者権限が必要なので、永続性が確立されてしまう可能性が濃厚となるでしょう。

上記の調査結果に基づき、Node.js 動作時の脆弱性の発生条件が分かりました。

  • バージョン 16.16.0(LTS)または 14.20.0 以下の Node.js がインストールされている。
  • crypto、https、tls の3つの組み込みモジュールのうち、1つがロードされている。
  • デフォルトの OpenSSL 設定ファイル(openssl.cnf)が、パス C:/Program Files/Common Files/openssl.cnf にある。(ほとんどの場合、上記のプログラムがインストールされていると思われる Node.js を使用するのは開発者のコンピュータなので、この仮定は妥当だと思われます)

これらの条件により、脆弱性が再現されます。

CVE-2022-32223に対するパッチ

この脆弱性に対応するため、パッチを適用したバージョンがリリースされました。今後、Node.js は環境変数 OPENSSL_CONF を指定するか、コマンドラインオプション --openssl-conf を使用することで、OpenSSL 設定ファイルを使用できます。いずれも指定されない場合は、デフォルトの OpenSSL 設定ファイル openssl.cnf を読み込みます。Node.js は、デフォルトで nodejs_conf という名前のセクションのみを読み取ります。

インストール時にデフォルトの openssl.cnf ファイルを使用していて、この変更の影響を受ける場合は、次の方法で以前の動作に戻すことができます。

  • コマンドラインに --openssl-shared-config を追加する(Node.js 18.5.0 のみ)。
  • そのファイルに新しい nodejs_conf セクションを作成し、デフォルトセクションの内容を新しい nodejs_conf にコピーする。

脆弱性の技術的な詳細と修正方法については、GitHub のドキュメントをご覧ください。

JSパッケージ内の脆弱性を利用したユースケース

攻撃者が悪意のある DLL を含むパッケージを npm や他のパッケージマネージャにアップロードする次のようなシナリオを考えてみましょう。

まず、npm -version、npm bug、npm audit といった、疑う余地のない npm コマンドを含む postinstall コマンドで package.json を作成します。

また、「悪意のある」DLL を同じフォルダにコピーし、パッケージを公開します。

そして、providers-win-package を新しいプロジェクトフォルダにインストールします。ご覧のように、DLL からのコードが実行されています。

明らかに、悪意のあるコードは常に js ファイルの1つに書かれる可能性がありますし、悪意のあるパッケージコードでリモートの悪意のある DLL アドオンへの呼び出しが行われる可能性もあります。

さらに、npm のセキュリティモデル、あるいは他のパッケージレジストリは、インストールで要求したものは明示的に信頼するということを覚えておく必要があります。

また、この脆弱性は、攻撃者が悪意のあるコードをパッケージに埋め込むための別の方法を提供し、DLL ハイジャックに慣れていない開発者は気づかない可能性があります。

そのため、この DLL を含むパッケージの脅威を検出するのは難しいです。この DLL はパッケージ内のどのコードからも全く参照されないため、開発者はこの DLL がロードされないと考えるでしょう。

緩和策とまとめ


本ブログでは、最近発見された Node.js の脆弱性 CVE-2022-32223 について検証しました。この問題は修正されています。したがって、Node.js の Windows ユーザは、パッチが適用されたバージョンにアップグレードすることを強く推奨します。

最近、多くのリポジトリにバイナリアーティファクトが含まれています。開発者は、ソースリポジトリやパッケージに含まれている場合、実行ファイルが直接使用されるケースが多いことを忘れてはいけません。

開発者は、これらの実行可能ファイルのコードを簡単に見ることができませんし、場合によってはリポジトリで提供されないので、これらのアーティファクトの中には悪意のあるコードが含まれている可能性があります。

ユーザの安全を確保するために、リポジトリやパッケージに実行可能ファイルを埋め込まないようにすることを強くお勧めします。

最終的には、開発者がアプリケーションを構築する際に、どのようなオープンソースプロジェクトやパッケージを使用するかについて責任を持つことになります。そのため、サードパーティのコンポーネントには信頼できるソースを使用し、リポジトリやパッケージ内の疑わしいバイナリを含むソフトウェアのサプライチェーンの脅威を検出できるソリューションを使用して、環境を保護することが重要です。

時系列

  • 2022年1月12日:この問題は、HackerOne の Node.js プログラムへ報告されました。
  • 2022 年 1 月 13 日:Node.js からこの問題の調査を開始したという最初の応答がありました。
  • 2022 年 2 月 7 日:Node.js のセキュリティチームによって脆弱性が確認されました。
  • 2022年7月7日:Node.js の7月7日のセキュリティリリースで脆弱性が修正されました。

New call-to-action

New call-to-action

新規CTA