週間1億ダウンロードを記録するJavaScript HTTPクライアント「Axios」が供給チェーン攻撃の被害に遭った。影響を受けたバージョンは[email protected](1.x系)と[email protected](0.x系)の2つ。攻撃者はメンテナのNPMアカウントを侵害し、悪意あるパッケージ[email protected]を依存関係として注入。リモートアクセストロイの木馬(RAT)が配布された。
StepSecurityとSocketの両社がそれぞれ独立に検出・分析し、「業界最高水準のサプライチェーン攻撃」と評価している。
| 時刻(UTC) | 事象 |
|---|---|
| 3月30日 23:59:12 | [email protected]がnpmに公開 |
| 3月31日 00:05:41 | Socketのスキャナーがマルウェアを検知(公開からわずか6分) |
| 3月31日 前後39分間 | 侵害済みAxios 2バージョンがnpmに公開 |
| 侵害期間中 | 両バージョンがライブ状態で配布 |
攻撃者はAxios主要メンテナのNPMアカウントを奪取し、登録メールを匿名のProtonMailアドレスに変更。長期有効なNPMアクセストークンを利用して手動公開を実行し、通常のOIDC Trusted Publisher機構をバイパスした。
正規リリースと侵害リリースのnpm registryメタデータ比較:
// axios@1.14.0 — 正規
"_npmUser": {
"name": "GitHub Actions",
"email": "[email protected]",
"trustedPublisher": {
"id": "github",
"oidcConfigId": "oidc:9061ef30-3132-49f4-b28c-9338d192a1a9"
}
}
// axios@1.14.1 — 侵害
"_npmUser": {
"name": "jasonsaayman",
"email": "[email protected]"
// trustedPublisher なし、gitHead なし、GitHub コミット/タグ なし
}
侵害版にはOIDC認証情報もGitHub上の対応コミットも存在しない。axios GitHubリポジトリに1.14.1のコミットやタグは存在せず、このバージョンはnpmにのみ存在する。
攻撃者はaxiosのpackage.jsonにplain-crypto-js: "^4.2.1"を1行だけ追加した。他の依存は一切変更しない「手術的」な修正。
正規版と侵害版のdependencies比較:
// axios@1.14.0 — 正規
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
// axios@1.14.1 — 侵害
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0",
"plain-crypto-js": "^4.2.1" // ← 追加されただけ
}
npm install [email protected]を実行すると、npmが依存ツリーを解決してplain-crypto-jsを自動インストールし、直後にpostinstallスクリプトを無条件実行する。
axios本体のソースコードにplain-crypto-jsのimport/requireは一度もない。 package.jsonに追加された唯一の目的はpostinstallフックの実行。
setup.js(4,209バイト)は2層の難読化スキームを採用。すべての機密文字列が符号化配列に格納されている。
// 難読化層1: XOR暗号
_trans_1(x, r) {
// キー処理を伴うXOR変換
return charCode XOR key[(7 × r × r) % 10] XOR 333
}
// 難読化層2: 外層
_trans_2(x, r) {
// 文字列反転 → 記号置換 → base64-decode → _trans_1に渡す
}
デコード後の配列要素(抜粋):
| 用途 | デコード値 |
|---|---|
| シェル実行 | child_process |
| プラットフォーム判定 | os |
| ファイルシステム操作 | fs |
| C2ベースURL | http://sfrclak.com:8000/ |
| Windows識別子 | win32 |
| macOS識別子 | darwin |
| 削除対象ファイル | package.json |
| clean版スタブ | package.md |
ドロッパーはos.platform()をチェックし、3つの攻撃パスに分岐する。
| OS | ペイロード配置先 | 偽装方法 | 実行方法 |
|---|---|---|---|
| macOS | /Library/Caches/com.apple.act.mond | Appleシステムデーモンに偽装 | AppleScript → osascript |
| Windows | %PROGRAMDATA%\wt.exe | PowerShellコピー+隠しVBScript | 3段階攻撃チェーン |
| Linux | /tmp/ld.py | Pythonスクリプト | curl → nohup python3 |
3プラットフォーム全てが同じC2エンドポイント(sfrclak[.]com:8000)に接続し、IE8/Windows XPを模したUser-Agentで通信する。macOS RATバイナリにはコマンド実行(peinject、runscript)、ファイルシステム列挙(rundir)、プロセス終了(kill)の機能が含まれる。
ペイロード起動後、setup.jsは3つのクリーンアップを実行:
// 1. 自分自身を削除
fs.unlink(__filename) // setup.js を削除
// 2. postinstall フックを削除
fs.unlinkSync('package.json') // 証拠となるスクリプト行を削除
// 3. clean スタブで上書き
fs.renameSync('package.md', 'package.json') // 正常版に置き換え
感染後のnode_modules/plain-crypto-js/package.jsonを検査しても、postinstallスクリプトもsetup.jsファイルも存在しない。npm auditでは侵害を検出できない。
最も確実な方法:
# 強制的に確認する方法
ls -la node_modules/ | grep plain-crypto-js
# 存在するなら侵害確定
# 理由: plain-crypto-js はどの正規 axios バージョンにも依存していない
node_modules/plain-crypto-js/ ディレクトリ自体の存在が侵害の確証。このパッケージは正規axiosのいずれのバージョンにも依存していないため、このディレクトリが見つかればドロッパーは既に実行されている。
| 特徴 | 詳細 |
|---|---|
| 綿密な準備 | 18時間かけてパッケージ事前準備、タイミング同期 |
| 3プラットフォーム対応 | macOS/Windows/Linux 個別ペイロード |
| ビルドパイプラインバイパス | OIDC Trusted Publisherを回避して手動公開 |
| 証拠自動削除 | 痕跡が消え、事後調査を無効化 |
| 検出困難性 | npm audit不可、ソースコードレビュー不可 |
この記事はAI業界の最新動向を速報でお届けする「AI Heartland ニュース」です。