盗んだGitHubトークンでPythonリポジトリ240超にforce-push――「ForceMemo」キャンペーンの手口

この記事は約8分で読めます。

盗んだGitHubトークンでPythonリポジトリ240超にforce-push――「ForceMemo」キャンペーンの手口

本稿では、サプライチェーンセキュリティ企業StepSecurityが発見し追跡している「ForceMemo」キャンペーンについて解説します。3月8日以降、GitHubアカウントの乗っ取りとforce-pushによって240超のPythonリポジトリにマルウェアが注入されており、キャンペーンは現在も継続中です。

前回の記事で取り上げたGlasswormの不可視Unicode攻撃(2026年3月3〜9日、151超リポジトリ)と同一の脅威アクターである可能性が高く、同じSolana C2インフラを共有しています。前回の攻撃とは異なり、今回はコミット履歴をリベースで書き換えるため、通常のGitHub UIではプルリクエストや新規コミットとして痕跡が見えにくいという特徴があります。

前回のGlassworm攻撃との関係

2026年3月初旬、Glasswormによる攻撃は2つの波として同時並行で進行していました。StepSecurityの分析により、両者が同一のSolanaウォレット(BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC)をC2インフラとして共有していることが確認されています。

Aikido Securityが報告した第1波(3月3〜9日)は、不可視Unicode文字をペイロードの隠蔽に使い、151超のGitHubリポジトリを侵害しました。StepSecurityが発見した第2波「ForceMemo」(3月8日以降、継続中)は、盗んだGitHubトークンによるアカウント乗っ取りとforce-pushを使い、240超のPythonリポジトリにマルウェアを注入しています。ペイロードの隠蔽に不可視Unicodeを使うか、Base64やzlib等による難読化を使うかといった手法の違いはあるものの、同一のC2インフラを使用していることから、StepSecurityはForceMemoをGlassworm攻撃者による新たな配信経路であると分析しています。

ForceMemoの攻撃手法

ForceMemoの最大の特徴は、通常のGitHub UIではプルリクエストや不自然な新規コミットとして目立ちにくい点にあります。StepSecurityは、このインジェクション手法を使ったサプライチェーン攻撃は他に文書化された例がないと指摘しています。

攻撃者はまず、Glasswormのマルウェアによって窃取されたGitHubトークンを使い、開発者のGitHubアカウントにアクセスします。Glasswormのペイロードは、git credential fillコマンドの出力やVS Codeの拡張機能ストレージ、~/.git-credentialsファイル、さらには環境変数(GITHUB_TOKEN)など、あらゆる場所から認証情報を徹底的に収集することが判明しています。

アカウントへのアクセスを得た後、攻撃者はリポジトリのデフォルトブランチ上の最新の正規コミットに悪意あるコードを含めてリベースし、force-pushを実行します。元のコミットメッセージ、作者名、作者日時はそのまま保持され、変更されるのはコミッター日時のみです。通常のGitHub UIではPRやコミット履歴に変化が見えにくくなりますが、GitHub Events APIのPushEventやコミッター日時と作者日時のずれからは追跡が可能です。StepSecurityが紹介した事例では、Redditのあるユーザーが自分のリポジトリの大半に「null」がコミットしていることに気づき、侵害されたCursor拡張機能にまで感染源を追跡しています。

標的はDjangoアプリケーション、機械学習研究コード、Streamlitダッシュボード、PyPIパッケージなどのPythonプロジェクトで、setup.py、main.py、app.pyといったファイルの末尾に難読化されたコードが追加されます。侵害されたリポジトリからpip installを実行するか、クローンしてコードを実行するとマルウェアが起動します。

ペイロードの挙動とC2インフラ

Pythonファイルの末尾に追加されるBase64エンコードされたペイロードは、まずシステムのロケールがロシア語に設定されているかを確認します。ロシア語であれば実行をスキップし、それ以外の場合はGlasswormと共通のSolanaウォレットのトランザクションメモフィールドからペイロードURLを取得します。ここから暗号化されたJavaScriptをダウンロードし、暗号資産とデータの窃取を目的としたペイロードを実行します。

StepSecurityの調査によれば、このC2アドレス上の最古のトランザクションは2025年11月27日に遡り、最初のGitHubリポジトリ注入(2026年3月8日)より3か月以上前からインフラが準備されていたことを示しています。アドレスには合計50件のトランザクションが記録されており、攻撃者はペイロードURLを1日に複数回更新することもあります。

npmパッケージおよびVS Codeマーケットプレイスへの拡大

ForceMemoキャンペーンの影響はGitHubリポジトリにとどまりません。npmユーザー「astroonauta」が管理するReact Nativeパッケージ2件(react-native-international-phone-number v0.11.8 と react-native-country-select v0.3.91)が一時的に侵害され、対応するGitHubリリースなしに悪意あるバージョンがnpmレジストリに直接公開されました。この活動もForceMemoキャンペーンの一部と評価されています。

同時期に別系統でも進化が確認されています。Socketの報告によれば、Open VSXマーケットプレイスへの最新のGlassworm攻撃では、マルウェアを拡張機能に直接埋め込むのではなく、マニフェストフィールド(extensionPackおよびextensionDependencies)を悪用して、一見無害な拡張機能が自動的に悪意ある別の拡張機能をインストールする「推移的配信」の手法に移行しています。これはForceMemoとは異なる配信手法ですが、Glasswormエコシステム全体の進化を示す動きです。

実務上の影響と対策

ForceMemoが従来のサプライチェーン攻撃と異なるのは、git履歴のリベースによって通常の監査手段では見落としやすい点です。通常のGitHub UIだけでは侵害を発見しにくいため、別途コミッター日時と作者日時のずれやGitHub Events APIのPushEventを確認する必要があります。

開発チームが点検したいポイントとして、GitHubトークンの管理があります。Glasswormのペイロードがgit credential fill、VS Codeストレージ、~/.git-credentials、GITHUB_TOKEN環境変数から認証情報を収集していることが判明しているため、これらの保管場所を見直す必要があります。VS CodeやCursorの拡張機能経由で感染する経路が確認されているため、拡張機能の定期的な棚卸しも有効です。

リポジトリの汚染チェックとしては、コミッター日時と作者日時のずれを検出する方法が挙げられます。ForceMemoではコミットメッセージと作者日時は保持されますが、コミッター日時のみ変更されるため、この差異がインジケーターになります。StepSecurityのブログではamirasaran/django-restful-adminの事例を具体例として示しています。

GitHubのブランチ保護ルールでforce-pushを禁止する設定も基本的な防御策です。一般的なサプライチェーン防御策としては、前回記事で触れた依存クールダウン(新バージョンの即時採用を避ける7〜14日の待機)も、npmパッケージへの拡大が確認された今回の事案で引き続き有効といえます。

Glasswormの攻撃者は、VS Code拡張機能(2025年10月)→不可視Unicode(2026年3月初旬)→force-push(3月8日以降)と、手法を切り替えながら同一のSolana C2インフラを使い続けています。防御側にとっては、この共通インフラの監視と、各配信経路ごとの検出策の両方が必要になります。

参考情報

コメント

タイトルとURLをコピーしました