サイバー脅威
Shai-hulud 2.0キャンペーンがクラウドと開発者エコシステムを標的に
Shai-hulud 2.0キャンペーンでは、主要なクラウド基盤や開発者向けサービスから認証情報やシークレットを盗み取る高度な亜種が使われています。被害者が管理するNPMパッケージに自動でバックドアを仕掛ける機能も備えており、攻撃者はソフトウェアサプライチェーン全体で迅速かつ秘匿性の高い拡散を実現します。この挙動により、多くの下流利用者が影響を受ける危険性が生じています。
- Shai-hulud 2.0は、初期の亜種が行っていたクラウド基盤からの認証情報窃取に加え、主要クラウドの認証情報やシークレット、NPMトークン、GitHub認証情報を盗み出し、新たにバックドア機能を導入しています。
- マルウェアは、被害者が管理するすべてのNPMパッケージに自動でバックドアを仕掛け、悪意あるペイロードを組み込んだ状態で再公開します。このペイロードはインストール時に実行され、高い自己増殖性を持つ脅威となり、数千の下流利用者に影響が及ぶ可能性があります。
- マルウェアは窃取したクラウド認証情報を使い、クラウドネイティブなシークレット管理サービスへアクセスします。また、必要な情報を取得できなかった場合にユーザデータを消去する破壊的なコードも含んでいます。
- Trend Vision One™は、本稿で示した侵入の痕跡(IOC)を検知・遮断し、利用者向けにスレット(脅威)ハンティングクエリ、関連インサイト、インテリジェンスレポートを提供します。
本稿は、9月15日に発生したNode Package Manager(NPM)のサプライチェーン攻撃に関する調査の続報です。攻撃者は高度に絞り込んだフィッシングを実行し、NPMパッケージ管理者のアカウントを侵害しました。前回のブログ記事では、JavaScriptパッケージに仕込まれた悪意あるコードが、Web APIの乗っ取りやネットワークトラフィック操作によって暗号資産を奪い取る仕組み、さらに攻撃ペイロード内のShai-huludワームがクラウドサービスのトークンを窃取し、シークレットスキャンツールを展開し、別のアカウントへ広がる手口を説明しました。11月24日に報告された事案では、「Sha1-Hulud: The Second Coming」と記述された新たなShai-huludキャンペーンにより、数百のNPMリポジトリが侵害されたとされています。
本稿では、トレンドマイクロの調査でShai-hulud 2.0と名付けた新バージョンの分析内容を紹介し、初期の亜種では確認されなかった機能を明らかにします。
Shai-hulud 2.0の分析では、AWS、GCP、AzureからAPIキー、トークン、パスワードを含む認証情報を窃取し、NPMトークンやGitHub認証情報も標的にしていることが判明しています。GitHub Actionsのワークフローを作成して攻撃者側のC&Cを実現し、リポジトリのシークレットを盗むための専用ワークフローを強制的に組み込む動きも見られます。
静的な認証情報の窃取にとどまらず、マルウェアはクラウド認証情報を悪用してクラウドネイティブなシークレット管理サービスへアクセスします。AWS Secrets Manager APIを使ったシークレット取得、GCP Secret Manager APIからのシークレット抽出、Azure Key Vaultからのシークレット収集が含まれます。また、KubernetesポッドにAzureのIDを付与するために広く使われ続けているレガシー機構であるAzure Pod Identityの認証情報も標的となります。
さらに、マルウェアは被害者が管理するすべてのNPMパッケージに自動でバックドアを挿入し、インストール時に実行される悪意あるペイロード付きで再公開します。NPMエコシステム全体に指数関数的に拡散する自己増殖型の経路が形成され、信頼して利用している多くの下流ユーザが影響を受ける可能性があります。この処理は完全に自動化され、最大100件のパッケージを同時に処理する並列化によって、拡散を最大化しながら発見される機会を最小限に抑えています。
Shai-hulud 2.0の攻撃チェーン解析
Shai-hulud 2.0は、NPMインストール時に自動実行される悪意あるpreinstallスクリプトを含むNPMパッケージとして配布されます(package.jsonに「preinstall”: “node setup_bun.js」を追加した改ざん版)。
setup_bun.js(ローダー)
初期ドロッパーであるsetup_bun.jsは、NPMパッケージのインストール中に実行されるローダーとして機能します。主な目的は、被害端末にBun JavaScriptランタイムが存在するかを確認し、確認後にメインのマルウェアペイロード(bun_environment.js)を実行することにあります。
Bunランタイムの検出とインストール
setupスクリプトの初期段階では、被害端末にBun JavaScriptランタイムがすでにインストールされているかを確認します。この検出はプラットフォームごとのコマンドを使い、システムPATHにBun実行ファイルが存在するかどうかを調べる仕組みです。Windows環境ではwhereコマンド、LinuxやmacOSなどのUnix系環境ではwhichコマンドを使用します。
BunがシステムPATHで確認できない場合、スクリプトは自動的にダウンロードとインストールを開始します。この処理にはbun.shが提供する公式のBunインストールスクリプトが使われ、正規のインストール動作に似せることでセキュリティ製品に検知されにくくしています。
Windows環境では、PowerShellのInvoke-RestMethodとInvoke-Expressionを使ってインストールスクリプトを取得し実行します。Unix系環境ではcurlでインストールスクリプトを取得し、その出力をbashに直接渡して実行します。この手法はBunの公式インストール手順と同じであり、マルウェアの挙動が正当な動作に見えるよう工夫されています。
PATH環境変数の再読み込み
Bunランタイムをインストールした後、setupスクリプトは新たに追加された実行ファイルを検出するために、システムのPATH環境変数を再読み込みする必要があります。Bunのインストール処理はユーザのPATHを変更しますが、この変更はsetupスクリプトを実行しているNode.jsプロセスには即時反映されません。このため、プラットフォームごとの方法で更新後の環境設定を取得する仕組みが使われます。
Windows環境では、ユーザレベルとシステムレベルのPATH変数をPowerShellでWindowsレジストリから取得し、それらを結合して単一のPATH文字列を生成します。Bunがユーザプロファイルディレクトリにインストールされた場合も、システム全体にインストールされた場合も確実に検出できるよう、この方法が採用されています。スクリプトでは、PowerShell経由で.NETの[Environment]::GetEnvironmentVariable()メソッドを利用し、これらのレジストリ値を読み取ります。
ペイロードの実行
setupスクリプトの最終段階では、実際のマルウェアペイロードを実行する処理が行われます。
スクリプトはまず、BunがシステムPATH上で利用可能かどうかを確認します。これは、以前からBunがインストールされていた場合や、前のステップで正常にインストールされた場合に該当します。PATHに存在しない場合、スクリプトは悪意あるパッケージと共に含まれている可能性があるローカルのBun実行ファイルを検索します。この探索は、パッケージ内に含まれる可能性があるbun-distディレクトリを調べ、その中の複数の候補パスを確認します。Unix系の実行ファイル名(bun)、Windows実行ファイル名(bun.exe)の双方が探索対象となります。
Bunの実行ファイルが見つかるか、あるいはインストールが完了すると、スクリプトはメインペイロードであるbun_environment.jsの実行に進みます。スクリプトはBunプロセスを起動し、引数としてペイロードファイルを指定します。
bun_environment.js(メインペイロード)
jy1()関数
jy1()関数は、Shai-hulud 2.0のマルウェアペイロードにおける主要なエントリーポイントです。bun.exe bun_environment.jsが実行されると、この関数がスクリプトの最上位で呼び出され、攻撃シーケンス全体を制御します。
CI/CD環境の確認
マルウェアはCI/CD環境変数を確認し、処理が継続的インテグレーションパイプライン上で動作しているか、開発者のローカル環境で動作しているかを判断します。CI/CD環境が検出されると、ビルドパイプラインの実行中に認証情報へ最大限アクセスできるよう、バックグラウンド処理を行わず即座に実行します。
- BUILDKITE - Buildkite CI/CDプラットフォーム
- PROJECT_ID - Google Cloud Build
- GITHUB_ACTIONS - GitHub Actionsワークフロー
- CODEBUILD_BUILD_NUMBER - AWS CodeBuild
- CIRCLE_SHA1 - CircleCIパイプライン
これらの環境変数がprocess.env内に存在しない場合、実行環境はCI/CDパイプラインではなく通常の開発者マシンと判断され、バックグラウンドプロセスを用いたステルス実行ルートへ切り替わります。
開発者マシンでの実行
開発者マシンでは、マルウェアはステルス性を高めるため、Bun.spawn().unref()によって切り離されたバックグラウンドプロセスを生成します。この際、環境変数POSTINSTALL_BG=1が設定され、親プロセスは即座に終了するため、NPM installは通常どおり2〜3秒で完了します。この挙動によりユーザの疑念を避けます。一方で、バックグラウンドで動作する子プロセスは、認証情報を含むすべての環境変数を継承し、ユーザの目の届かない場所で資格情報の窃取を続けます。
aL0()関数
aL0()は非同期JavaScript関数で、CI/CD環境や開発者のワークステーションを標的とし、AWS、GCP、Azureクラウド基盤の認証情報に加え、NPMトークンやGitHub認証情報を窃取します。認証に失敗した場合、ユーザデータを消去する破壊的なコマンドを実行します。関数の冒頭では、GitHub Actions CI環境で動作しているかどうかを検出します。
マルウェアはLinux環境での永続化とセキュリティ制御の無効化を行うために、3つの関数を使用します。cQ0()関数は、プロセス一覧の中から「/home/agent/agent」を検索し、マルウェアエージェントがすでに実行中かどうかを確認するためのプロセス検出を行います。
pQ0()関数は権限昇格を試みます。まずパスワード不要のsudoが可能かどうかを確認し、利用できない場合はDockerの特権コンテナアクセスを悪用してホストファイルシステムをマウントし、sudoers構成ファイルを改変して無制限のroot権限を獲得します。
最後にgQ0()関数はセキュリティ制御を無効化します。systemd-resolved DNSサービスを停止して悪意ある設定ファイルに差し替え、iptablesファイアウォールのOUTPUTチェーンとDOCKER-USERチェーンのルールを順次削除し、C&C通信やデータ持ち出しを妨げるネットワークフィルタリングを完全に撤廃します。
次にマルウェアは、AWS、Google Cloud Platform、Azure、GitHubの認証情報窃取に備えるため、主要クラウド3社とGitHub向けのモジュールを初期化します。
NPMトークンの取得
マルウェアは、開発者マシンからNPM認証トークンを窃取するためのモジュールを使用します。.npmrc設定ファイルを、現在の作業ディレクトリとユーザのホームディレクトリという2つの場所で探索します。NPMがレジストリ認証情報を保存する標準的な場所です。関数はこれらのファイルを1行ずつ読み込み、コメント行や空行を除外し、__authToken= または :authToken= に続くBase64形式のトークン文字列を抽出するために正規表現パターンを使用します。
続いてマルウェアは、NPMの /-/whoami APIエンドポイントを呼び出してトークンが有効かどうかを検証し、認証済みユーザ名を取得します。whoami関数はNPM認証を確認し、被害者のNPMユーザ名を取得します。このユーザ名は後続のステージで、被害者が管理するパッケージ一覧を取得するために使われます。検証が成功すると、ユーザ名は保存され、最大100件のパッケージの列挙と、それらをバックドア化したバージョンをNPMレジストリへ公開する処理で利用されます。
コマンド・アンド・コントロール
マルウェアはGitHubリポジトリを作成し、C&C基盤を構築します。最初にGitHub認証が利用可能かどうかを確認し、窃取済みのGitHub認証情報が有効であることを確認します。その後、この被害端末専用のC&Cリポジトリ名として使う18文字のランダム識別子を生成します。これにより、感染した端末ごとに専用のC&Cリポジトリが用意されます。
GitHub APIによるリポジトリ作成
createRepo()関数は、GitHub Octokit APIを使って以下を呼び出し、ランダムな名称、説明文「Shai-Hulud: The Second Coming.」、さらに公開設定、ディスカッション有効化、その他のIssues、Projects、Wikiはすべて無効化する構成でリポジトリを作成します。C&C用途に特化した最小構成のリポジトリを構築する狙いがあります。
repos.createForAuthenticatedUser()
リポジトリ作成が成功すると、APIレスポンスからリポジトリ所有者のログイン名とリポジトリ名を抽出し、「owner/repo」の形式で完全なリポジトリパスを生成します。このパスは後続処理のためにthis.gitRepoへ保存されます。
ワークフローパーミッションの検証
マルウェアはcheckWorkflowScope()を呼び出し、窃取したGitHubトークンがworkflow OAuthスコープを持つかどうかを確認します。workflowスコープはGitHub Actionsのワークフローやランナーを管理するために必要な権限です。この関数はGitHub APIにHEADリクエストを送り、レスポンスヘッダーx-oauth-scopesを確認します。このヘッダーには、トークンが保有する権限がカンマ区切りで列挙されています。関数はこのヘッダーを解析し、一覧に「workflow」が含まれているかを確認し、その結果をthis.hasWorkflowに保存します。workflowスコープが存在する場合、マルウェアは自己ホスト型ランナーやC&Cワークフローの展開を進めます。
続いてマルウェアは、GitHub APIに以下のPOSTリクエストを送り、自己ホスト型ランナーの登録に必要な一時トークンを取得します。
/repos/{owner}/{repo}/actions/runners/registration-token
プラットフォーム別ランナー展開
検出されたOS(Linux、Windows、macOS)に応じて、マルウェアはGitHubの公式リリースから適合するGitHub Actionsランナーバイナリをダウンロードします。ダウンロードしたランナーは、Unix環境では$HOME/.dev-env、Windowsではユーザホームディレクトリ内の隠しディレクトリに展開され、取得した登録トークンを使って新規作成されたリポジトリに接続するよう構成されます。ランナー名は「SHA1HULUD」と設定されます。起動はUnixではnohup、Windowsでは非表示PowerShellウィンドウを使ってバックグラウンドで行われ、初期マルウェアプロセスが終了した後も継続して動作し、侵害された端末への持続的アクセスを維持します。
C&Cワークフローのインストール
マルウェアは、以下にGitHub Actionsワークフローファイルを作成します。
.github/workflows/discussion.yaml
このワークフローはディスカッション作成時にトリガーされ、攻撃者がリポジトリのディスカッション欄に投稿するだけで感染端末上で任意コマンドを実行できるようになり、C&C基盤が完成します。
解析妨害のフェイルセーフ
NPMトークンが無効または未取得の状態で、GitHubトークンの取得にも失敗した場合、マルウェアはユーザホームディレクトリ内のすべてのファイル削除を試みる破壊的コマンドを実行します。
システム情報の収集
マルウェアはプラットフォーム情報、ホスト名、OSユーザ情報、GitHub認証状態など、被害端末の詳細なプロファイル作成のためにシステム情報とGitHub認証データを収集します。
シークレット流出を目的とした悪意あるワークフローの作成
前述のdiscussion.yamlワークフローに加え、マルウェアはリポジトリ内のすべてのシークレットを窃取するために特化した別のGitHub Actionsワークフローを作成します。このワークフロー注入機構はGitHubのCI/CD基盤そのものを悪用し、侵害されたリポジトリでコードがプッシュされるたびに機密情報を自動的に外部へ送信します。
ワークフロー注入の仕組み
マルウェアは侵害したGitHubアカウントからアクセス可能なすべてのリポジトリを順に処理し、それぞれに悪意あるワークフローファイルを作成します。検知を避けるため、まず以下のようなタイムスタンプ付きの名前を持つ一時ブランチを作成します。
add-linter-workflow-{timestamp}
この命名規則は、開発者がリンターやフォーマッターのようなコード整形ツールを追加するために作成する一般的な機能ブランチを模倣したものです。メインブランチに直接悪意あるワークフローを追加しないことで、ブランチ保護ルールや即時レビューによって不正行為が発覚する可能性を下げています。
悪意あるワークフローの内容
このワークフローファイルは、認証情報窃取の意図を隠すために綿密に偽装されています。名前は「Code Formatter」とされ、リポジトリ内でコードがプッシュされるたびに自動実行されるよう設定されます。攻撃の核となるのはGitHub Actionsが提供するsecretsコンテキストで、ここにはリポジトリ設定で構成されたすべてのシークレットが含まれています。マルウェアはtoJSON()関数を使ってこのsecretsオブジェクト全体をJSON文字列に変換し、クラウドプロバイダキー、APIトークン、データベースパスワード、署名証明書などあらゆる機密情報を取得します。
ワークフロー実行の監視
悪意あるワークフローファイルをターゲットリポジトリに注入した後、マルウェアはワークフローが実行および完了するタイミングを検出するための監視フェーズに入ります。30秒のタイムアウトを設定したポーリングループを実装し、2秒ごとにGitHub Actions APIへ問い合わせを行い、新たに作成されたワークフロー実行が開始されたかどうかを確認します。この仕組みは、ワークフローがコードプッシュ時にのみ動作するため、既存の自動処理、または開発者のコードプッシュを待つ必要があるためです。
アーティファクトのダウンロードとシークレット抽出
ワークフローの実行が始まると、マルウェアはステータスを監視し、「completed」状態に遷移した後にアーティファクトとして保存された流出済みシークレットのダウンロードを試みます。
ワークフローが完了すると、マルウェアはGitHub Actions Artifacts APIを呼び出し、そのワークフロー実行によって生成されたすべてのアーティファクトを一覧取得します。GitHub Actionsは複数のアーティファクトをアップロードできるため、マルウェアは窃取済みシークレットを含む特定のアーティファクトを識別する必要があります。APIはアーティファクトID、名前、サイズ、ダウンロードURLなどのメタデータを保持するアーティファクトオブジェクトの配列を返します。マルウェアはこの配列を順に処理し、悪意あるworkflowの 以下のステップによってアップロードされた「formatting」アーティファクトを探します。
actions/upload-artifact@v5
GitHubはアーティファクトへ安全にアクセスさせるため、時限的に有効なストレージURLを用いた二段階ダウンロード方式を採用しています。マルウェアはまず、artifact IDを指定してダウンロードエンドポイントにリクエストを送り、redirectパラメータを「manual」に設定して自動リダイレクトを防ぎます。この最初のリクエストはLocationヘッダーを返し、そこに実際のアーティファクトストレージへの署名付き一時URLが含まれています。マルウェアはレスポンスヘッダーからこのリダイレクトURLを取り出し、そのURLへ二度目のHTTPリクエストを送って、窃取済みシークレットが格納されたZIPファイルをダウンロードします。
アーティファクトZIPがダウンロードされると、マルウェアはformat.jsonファイルを抽出します。ダウンロードしたレスポンスはArrayBufferとして受信され、処理のためNode.jsのBufferへ変換されます。ZIPアーカイブライブラリ(tG0[“default”])を使い、アーカイブを開いてgetEntry(“format.json”)を呼び出し、流出済みシークレットが保存されたファイルを見つけます。エントリを取得すると、バイナリをUTF-8文字列に変換し、悪意あるワークフローによって収集されたJSON形式のリポジトリシークレットが取得されます。
マルチクラウド認証情報の窃取
マルウェアは環境変数をまとめて取得し、APIキーやトークン、パスワードなどの認証情報を含む内容を解析します。並行して、AWS Secrets Manager APIを使ってAWSのシークレットを取得し、GCP Secret Manager APIからGoogle Cloudのシークレットを抽出し、Azure Key VaultからAzureのシークレットを収集します。
AWS認証情報収集
マルウェアはAWS SDKの認証プロバイダチェーンを利用してAWS認証情報を窃取します。この機構は環境変数を優先して探索し、標準的なAWS認証情報検索順序に基づいてクレデンシャルを見つけます。実装部分は、以下が存在するかどうかをgetterメソッドで確認し、必要に応じてセッショントークンの抽出も行います。
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
認証情報の抽出関数は非同期で動作し、マルウェア設定でログ出力を有効化できます。認証情報が見つかると、アクセスキーID、シークレットアクセスキー、セッショントークン(存在する場合)を含むクレデンシャルオブジェクトを生成します。また、マルウェアは有効期限、クレデンシャルスコープ情報、AWSアカウントIDといった拡張メタデータも取得します。
マルウェアはユーザホームディレクトリにあるAWS設定ファイルも狙います。AWS CLIの規則に従ってファイルパス解決処理を行い、まず、以下のような環境変数によるカスタムパスを確認し、指定がない場合は~/.aws/配下の標準パスを探索します。
AWS_CONFIG_FILE
AWS_SHARED_CREDENTIALS_FILE
さらにマルウェアはECS(Elastic Container Service)やEKS(Elastic Kubernetes Service)などのコンテナ実行環境を標的とした専用の窃取機能を持ちます。実装は、コンテナランタイムが公開する一時クレデンシャル取得エンドポイントを指す環境変数を確認します。これらのエンドポイントはIAMロールが付与された一時認証情報を提供するため、攻撃者がクラウド内で横方向移動を行う際に非常に価値の高い標的になります。
Google Cloud Platform(GCP)の認証情報収集
マルウェアはGoogle Cloud Platformの推奨認証方式であるApplication Default Credentials(ADC)も標的とします。実装ではまず、以下の環境変数(大文字小文字の違いも吸収する形でチェック)を確認します。
GOOGLE_APPLICATION_CREDENTIALS
この変数は通常、サービスアカウントのJSON鍵ファイルを指します。変数が存在すると、マルウェアはその鍵ファイルを読み込み、サービスアカウントの秘密鍵、クライアントメールアドレス、プロジェクト情報を抽出します。
マルウェアはプラットフォームに応じた探索ロジックを実装し、Google Cloud SDKの構成ディレクトリを特定します。このディレクトリには認証済みユーザのクレデンシャルやプロジェクト設定が保存されています。実装では、最初にユーザが構成ディレクトリを変更するための以下の環境変数を確認します。
CLOUDSDK_CONFIG
設定されていない場合、以下のようにOSに応じたデフォルトパスを決定して使用されます。
Windows環境では %APPDATA%\gcloud
Unix系環境では ~/.config/gcloud
構成ディレクトリを特定すると、マルウェアはこのディレクトリ内にある複数のクレデンシャルストアにアクセスし、gcloud CLIがキャッシュしたさまざまな認証トークンを抽出します。
マルウェアはApplication Default Credentials JSONファイルに対する特定処理も実装しています。実装にはファイル存在チェック(existsSync)が含まれ、ファイルが存在しない場合はエラーを出さずサイレントにnullを設定します。例外が発生して監視システムに感知されることを避ける狙いがあります。
Azureの認証情報収集
マルウェアはAzureの全主要認証方式を標的とした広範な認証情報窃取処理を実装しています。実装ではまず、重要なAzure関連環境変数の配列を定義し、それらがプロセス環境内に存在するかを系統的に確認します。プロバイダには、テナントIDの複数指定(セミコロン区切り)やブール値の変換など、複雑な構成を扱うための高度な解析ロジックも含まれています。
マルウェアは発見されたAzure環境変数を詳細ログに記録し、攻撃者が利用可能な認証方式を把握できるようにします。
マルウェアは複数のAzure認証方式を試行する段階的抽出システムを実装しています。最初に、もっとも一般的な自動化システム向け認証方式であるクライアントシークレット型サービスプリンシパル認証を試みます。この方式にはテナントID、クライアントID、クライアントシークレットが必要です。これら3つが揃っている場合、マルウェアはClientSecretCredentialオブジェクトを生成し、Azure Resource Managerへアクセスし、サービスプリンシパルに付与された権限の範囲でAzureリソースへ認証します。成功時、テナントIDおよびクライアントIDがログに記録されます。
クライアントシークレット認証が使えない場合、マルウェアは証明書ベース認証へ切り替えます。具体的には以下を確認します。
AZURE_CLIENT_CERTIFICATE_PATH
および必要に応じて以下を確認します。
AZURE_CLIENT_CERTIFICATE_PASSWORD
続いて、ユーザ名およびパスワードによる認証を試みます。この方式は非推奨であると示す警告ロジックが含まれています。
さらにマルウェアはWorkload Identity認証にも対応しています。これはKubernetes環境で主に使用される新しいAzure認証方式です。実装では、以下の3つの重要な環境変数を標的とします。
A_ZURE_TENANT_ID
AZURE_CLIENT_ID
AZURE_FEDERATED_TOKEN_FILE
マルウェアは、Azure Pod Identityの認証情報も標的とします。Azure Pod IdentityはKubernetesポッドへAzure IDを付与するために広く利用され続けているレガシー仕組みです。
実装では、Instance Metadata Service(IMDS)からマネージドIDトークンを取得するためのエンドポイントを指す以下の環境変数を確認します。
AZURE_POD_IDENTITY_AUTHORITY_HOST
この変数が存在する場合、マルウェアはこの値に標準的なトークン取得パスを追加し、完全なOAuthトークンエンドポイントURLを構築します。
環境変数が存在しない場合、マルウェアは標準のAzure IMDSエンドポイントを利用します。
クラウドシークレットマネージャの積極的な悪用
静的な認証情報の窃取に加え、マルウェアは窃取したクラウド認証情報を利用してクラウドネイティブなシークレット管理サービスへアクセスします。
実装にはAWS Secrets Manager、GCP Secret Manager、Azure Key Vault向けの専用処理が含まれ、それぞれが以下のメソッドを用いて、格納されたシークレットの列挙と抽出を行います。
listAndRetrieveAllSecrets()
AWS Secrets Manager
AWSシークレット収集モジュールは、多数のシークレットを取得するための複数リージョン探索戦略を採用しています。WXクラスはまず、STS GetCallerIdentity APIを使用して窃取した認証情報が有効かどうかを確認し、ユーザID、アカウントID、ARNといった識別情報を取得します。
認証情報が有効と判断されると、マルウェアは17の主要AWSリージョンを順に処理し、それぞれのリージョンにあるSecrets Managerからシークレットを探索します。各リージョンではListSecrets APIでシークレット一覧を取得し、続いてGetSecretValueで値を取得します。
GCP Secrets Manager
GCPのシークレット収集モジュールは高度な認証処理を実装しています。Google AuthライブラリのgetAccessToken()を使用して認証情報を検証した後、Resource Manager APIを呼び出してアクセス可能なGCPプロジェクトを一覧取得します。その後、各プロジェクトごとにSecret Managerクライアントを生成します。listSecrets()でシークレット一覧を取得し、以下のパスを使用して最新バージョンを抽出します。
{secretName}/versions/latest
取得処理ではシークレット本体のペイロードだけでなく、付随するメタデータも収集します。
Azure Key Vault
Azureのシークレット収集機能は、MicrosoftのKey Vaultサービスを標的とします。実装ではまず、DefaultAzureCredentialプロバイダを使用して認証を行います。このプロバイダは複数の認証方法(環境変数、マネージドID、Azure CLI認証情報など)を順に試行します。認証に成功すると、マルウェアはResource Manager APIを使用し、以下のようなリソースタイプをフィルタしてサブスクリプション内のすべてのKey Vaultを列挙します。
Microsoft.KeyVault/vaults
各Vaultが見つかると、SecretClientを生成し、すべてのシークレットを反復処理して値を取得します。
TruffleHogによるシークレットスキャン
マルウェアはTruffleHogの自動展開システムを備えており、GitHubから最新バージョンを直接ダウンロード、展開、キャッシュします。ダウンロード前にキャッシュを確認し、既存バイナリがなければ最新リリース情報をGitHubから取得し、システムに適したバイナリをダウンロードして展開し、実行可能化します。
マルウェアはGitHub APIを使用してTruffleHogの最新リリース情報を自動取得します。認証不要で、 以下にGETリクエストを送り、メタデータとプラットフォーム別ダウンロードリンクを取得します。
/repos/trufflesecurity/trufflehog/releases/latest
この方式によりバージョン番号をハードコードする必要がなくなり、更新後も継続して使用できます。
マルウェアはTruffleHogのファイルシステムスキャナを利用し、被害者のホームディレクトリ全体を対象にハードコードされたシークレットを探索します。出力を解析しやすいJSON形式とし、必要に応じてスキャン対象を限定する引数を設定します。実行は不自然に長引くことを避けるため10分間のタイムアウトつきで行われ、出力とエラーを取得します。結果は発見されたシークレット、エラー、スキャン時間、終了コードを含む構造化レポートにまとめられ、オペレーターが成功、部分成功、失敗を迅速に判断できるようにします。
情報送出
マルウェアは多段階のデータ持ち出し機構を実装しており、窃取したデータを4つのカテゴリに分けて集約し、被害者自身のGitHubアカウント内にマルウェアが自動作成する攻撃者管理リポジトリへアップロードします。持ち出し処理では、4種類のJSONファイルを作成し、それぞれに特定カテゴリの窃取データを格納します。
マルウェアは、被害者が管理するすべてのNPMパッケージへ自動的にバックドアを挿入し、インストール時に実行される悪意あるペイロードを組み込んだ状態で再公開します。これにより、NPMエコシステム全体へ指数関数的に拡散する自己増殖型の経路が形成され、影響を受けるパッケージを信頼して利用する数千人の下流ユーザが被害を受ける可能性があります。
攻撃は5つの段階で進行します。被害者が管理するすべてのパッケージを特定し、元のtarballをダウンロードし、悪意あるpreinstallフックを注入し、マルウェアインストーラをバンドルし、改ざん済みパッケージを正規アップデートとして再公開する、という流れです。
この処理全体は自動化されており、最大100件のパッケージを同時に処理する並列実行によって、検知される可能性を抑えつつ感染拡大を最大化します。
メンテナー所有パッケージの取得
マルウェアは、認証済み被害者が管理しているすべてのNPMパッケージを特定するために、NPMレジストリへクエリを送信します。実装ではmaintainer: フィルターを使ったNPM検索APIを利用し、侵害されたアカウントが所有するパッケージを列挙します。パッケージ列挙では詳細なメタデータも収集され、月間ダウンロード数などの統計により高影響のターゲットを優先できます。月間ダウンロード数の降順で並べ替えることで、最も人気の高いパッケージから侵害を進め、潜在的な被害規模を最大化します。
NPMレジストリ検索
検索処理はNPM公式の検索APIエンドポイント(/-/v1/search)を利用し、URLエンコードや認証ヘッダーを正しく設定します。デフォルトの検索制限は20パッケージですが、実際の攻撃では最大100パッケージが要求されます。
パッケージのダウンロードと展開
マルウェアは、NPMレジストリから元のパッケージtarballをダウンロードし、改変できるように準備します。この方法により、バックドア化したバージョンが正規の機能を保持しつつ、悪意ある機能を追加する構造になります。ダウンロード処理では標準的なHTTPフェッチとgzip、deflate、brotliといった圧縮方式を利用して効率的に取得します。テンポラリディレクトリ名はNPM-update-とされ、正規のNPMツール挙動を模倣することでプロセス監視による検知を避けます。
preinstallフックの注入
サプライチェーン攻撃の中心となる処理は、パッケージのpackage.jsonファイルを改変し、悪意あるpreinstallスクリプトを注入することです。このスクリプトは、誰かがNPM installを実行した時点で自動実行され、パッケージの依存関係がインストールされる前に動作します。
preinstallスクリプトはNPMインストールのライフサイクルにおいて最も早い段階で実行され、具体的には以下のタイミングに該当します。
- 依存関係の解決前
- パッケージインストール前
- 正規のパッケージコードが実行される前
- ユーザの権限を完全に利用した状態で
悪意あるペイロードのバンドル
マルウェアは、多段階インストーラsetup_bun.jsをパッケージ内へバンドルします。このスクリプトは、冒頭で説明したとおり、Bunランタイムのインストールとマルウェア本体の実行を担当します。Windows、Linux、macOSのすべての主要プラットフォームで動作するように設計されています。
パッケージの再公開
悪意あるコードとペイロードを注入した後、マルウェアは改変済みパッケージを再パッケージ化し、被害者の認証情報を使ってNPMへ公開します。公開処理には、攻撃の初期段階で取得した被害者のNPM認証トークンが利用されるため、改ざん後の更新は信頼されたメンテナーによる正規リリースのように見えます。バージョン更新ではパッチバージョンのインクリメントが行われ、一般的には軽微な修正やバグ修正として受け取られるため、利用者が疑う可能性は低くなります。
Trend Vision One™によるプロアクティブなセキュリティ対策
Trend Vision One™は、AIを活用したエンタープライズ向けサイバーセキュリティプラットフォームで、サイバーリスクの可視化とセキュリティ運用を一元化し、オンプレミス、ハイブリッド、マルチクラウド環境にわたる多層的な防御を提供します。
以下のセクションには、前回のブログ記事で紹介したTrend Vision Oneのインサイト、レポート、クエリに加え、本稿の追加情報を含む内容がまとめられています。
Trend Vision One™ スレットインテリジェンス
進化し続ける脅威に先回りするために、Trendの利用者は Trend Vision One™ Threat Insights にアクセスできます。ここでは、新たな脅威や攻撃者に関するTrend Researchの最新インサイトが提供されます。
Trend Vision One Threat Insights
Shai-Hulud 2.0 npm Supply Chain Attack
Trend Vision One Intelligence Reports(IOC Sweeping)
Shai-Hulud 2.0 npm Supply Chain Attack
ハンティングクエリ
Trend Vision One Searchアプリ
Trend Vision Oneの利用者は、Searchアプリを使うことで、本稿で取り上げた悪意あるインジケータを自分たちの環境データと照合し、脅威の特定やハンティングを行うことができます。
malName:*SHULUD* AND eventName: MALWARE_DETECTION AND LogType: detection
侵入の痕跡(Indicators of Compromise: IoC)
本稿に関連する侵入の痕跡はこちらで確認できます。
参考記事:
Shai-hulud 2.0 Campaign Targets Cloud and Developer Ecosystems
By: Jeffrey Francis Bonaobra
翻訳:与那城 務(Platform Marketing, Trend Micro™ Research)