TL; DR
Een eenzegen npm-Verlag huet aacht kleng Paketen verschéckt, deenen hir Nimm sech wéi alldeeglech Bausteng fir Blockchain- an Portemonnaienentwécklung lauschteren, base58-utils, abi-encode, eth-dev, arb-kit, layer2-sdk, solana-key-utils, eth-wallet-helpers, an crypto-validate-libJidderee vun hinnen enthält e funktionéierend Utility. No dësem Utility gëtt awer e selbstopruffende Codeblock bäigefüügt, deen ausféiert soubal de Modul importéiert gëtt.
Ongeféier 37 Sekonnen nom Import, dee Block decodéiert eng Notzlaascht, déi als Testfixture verstoppt am Pak geliwwert gëtt, schreift se an eng verstoppt Datei ënner dem Home-Verzeichnis vum Benotzer, registréiert sech selwer fir bei all Neistart login iwwer Windows, macOS a Linux, a start de decodéierte Skript als en ofgetrennte Prozess. Näischt drun gëtt während der npm-Installatioun ausgeléist; et waart bis de Code importéiert a gelaf ass, wat e méi rouege Moment ass wéi d'Installatioun.
D'Notzlaascht ass net opak. Si gëtt als plain base64 geliwwert, sou datt d'Dekodéierung vun der "Testfixture" déi zweet Stuf komplett erëmkritt: a Krypto-Portemonnaie a Geheimnisdéif déi waart bis d'Maschinn am Leerlaf ass, privat Schlësselen a Seed-Phrasen sammelt, all Fonnt mat engem hardcodéierten RSA-4096 Schlëssel verschlësselt an en exfiltréiert andeems en op en ëffentlechen IPFS-Späicher gepinnt gëtt, an all 12 Stonnen e Beacon zréckschéckt.
Mir verfollegen de Cluster als PhantomSyncAll aacht Pakete waren zum Zäitpunkt vun der Analyse am npm-Registrierung aktiv a goufen ënner engem eenzege Kont publizéiert.
| Ecosystem | npm |
| Formulen | base58-utils, abi-encode, eth-dev, arb-kit, layer2-sdk, solana-key-utils, eth-wallet-helpers, crypto-validate-lib |
| Zilplattformen | Windows, macOS, Linux |
| Kärverhalen | Verzögerten Importzäit-Dropper verstoppt als Testfixture; installéiert plattformiwwergräifend Persistenz |
| Notzlaascht | Krypto-Portemonnaie a Geheimnisdéif, RSA-4096 Verschlësselung, Exfiltratioun iwwer ëffentlech IPFS Pinning |
Attack Anatomie
All Packung gesäit beim éischte Lies onopfälleg aus. base58-utils, zum Beispill, ass e puer Kilobyte vun Null-ofhängegem Base58 / Bitcoin-WIF Hëllefscode - genau dat, wat den Numm versprécht. De relevante Code läit no de Modul säin module.exports, wou e Lieser, deen uewen an der Datei iwwerbléckt, wahrscheinlech net nokucke wäert: eng selbstopruffend Funktioun, déi sech selwer mat engem Timer plangt.
D'Kette vun den Operatiounen, déi aus der Quellcode vum Pak rekonstruéiert gouf, leeft sou:
1. Package is required() by the host project
2. A self-invoking function schedules a callback ~37,000 ms later (setTimeout)
3. On fire, the callback reads test/fixtures/keypairs.dat (a base64 blob)
4. It base64-decodes that blob into a Node.js script
5. It writes the script to ~/.cache-db/.node-sync/syncd.js (mode 0o700)
6. It installs login-persistence for that script (see below)
7. It spawns "node syncd.js" as a detached processZwee Designwahlen hiewe sech eraus.
D'Notzlaascht reest als Teststatioun. Déi zweet Etapp ass net als offensichtleche Code geschriwwen. Si lieft an test/fixtures/keypairs.dat, eng base64-Datei, där hiren Numm an e Pakett integréiert gëtt, dat behaapt, Schlësselpairen ze handhaben. Fir e Mënsch, deen den Tarball iwwerkuckt, gesäit et aus wéi Beispilldaten; fir den ugehängte Code ass et e Skript fir ze decodéieren an auszeféieren. Den Dropper selwer enthält keng Netzwierkadress - déi liewen an der zweeter Stuf - awer et gëtt keng zousätzlech Verschleierung: de Fixture ass eng eenzeg Schicht vu base64, sou datt d'Decodéierung en (base64 -d) kritt dat Ganzt erëm syncd.js a säi Netzwierkverhalen. Déi nächst Sektioun erkläert, wat déi restauréiert Phas mécht.
D'Detonatioun ass verspéit a gebonnen un den Import, net un d'Installatioun. Well den Ausléiser ass erfuerderen () plus en Timer vun ~37 Sekonnen amplaz vun engem Installatiounshook, ëmgeet d'Verhalen Kontrollen, déi nëmmen déi kucken npm installéiert Schrëtt, an d'Verspéidung dauert méi laang wéi vill kuerzlieweg Sandbox- a CI-Läufe. Bis iergendeng Saach ausgefouert gëtt, ass d'Installatioun, déi de Pak erausgeholl huet, laang fäerdeg.
Soubal den decodéierte Skript op der Festplack ass, ~/.cache-db/.node-sync/syncd.js — e Wee, deen ausgewielt gouf, fir wéi e Routine-Cache-Verzeichnis ze liesen — den Dropper suergt dofir, datt en Neistarten op allen dräi grousse Plattforme iwwerlieft:
- Linux: en Cron-Eintrag, deen de Skript nei start. Den Eintrag gëtt installéiert andeems de bestehenden Crontab duerch gefiltert gëtt. grep -v synchroniséiert, wat den Niewewierkung huet, datt den neien Entrée aus enger einfacher Lëscht erausgeet, déi fir deeselwechten Numm greps benotzt.
- Windows: eng geplangten Aufgab mam Numm WinNodeSync, agestallt fir an engem Intervall vun 12 Minutten nei ze lafen.
- macOS: e Launchd-Job mam Numm com.apple.syncd, déi a verschiddene vun de Paketen präsent ass - eng Etikett déi engem legitimen Apple System Service imitéiert.
De Skript gëtt dann direkt als en ofgetrennte Prozess gestart, sou datt en weider leeft nodeems den importéierende Programm ofgeschloss ass.
Wat déi zweet Etapp mécht
Well d'Fixture aus enger eenzeger base64-Schicht besteet, decodéiert déi zweet Stuf propper a kann komplett gelies ginn. All aacht Paketen enthalen eng vun dräi Varianten vum selwechte Skript, deen sech an engem Headerkommentar als identifizéiert. phantom syncd v3 - topo durmiente („Schlofmaul“). Seng Aufgab ass et, Material aus Krypto-Portemonnaien a Geheimnisser vun den Entwéckler ze klauen an se vum Computer ze verschécken. Et leeft an dëse Schrëtt:
- 1. Waart bis d'Maschinn am Leerlaf ass. Ier Dir eppes maacht, syncd.js kontrolléiert wéi laang de Benotzer inaktiv war a geet nëmmen iwwer eng gewëssen Schwell (ongeféier 15 Minutten) eraus — xprintidle op Linux, Ioreg HIDIdleTime op macOS, an eng PowerShell Idle-Time-Ufro op Windows. D'Harvesting geschitt dofir normalerweis wann keen un der Tastatur ass.
- 2. Bréngt Iech e ferngesteierten AktivéierungsschalterDe Skript zitt eng kleng Konfiguratioun aus engem Dead-Drop ier en handelt. Déi primär Quell ass eng GitHub Gist Raw URL (gist.githubusercontent.com/juang55/…/cfg.txt); de Skript aktivéiert sech nëmmen, wann déi Konfiguratioun liest aktiv=1Wann de Gist net verfügbar ass, gëtt op dräi fest kodéiert IPFS-Inhaltsidentifikatoren zréckgegraff, déi iwwer déi ëffentlech Gateways ofgeruff ginn. gateway.pinata.cloud, ipfs.io, an cloudflare-ipfs.comDëst gëtt dem Bedreiwer eng Kontroll fir no der Tatsaach ze bewaffnen/entwaffnen an e Réckfallschutz. (Déi klengst Variant, geliwwert an Krypto-validéieren-Lib, Eth-Portemonnaie-Hëllefer, an Solana-Schlëssel-Utils, huet d'Gist-Schicht ewechgeholl a baséiert eleng op den IPFS-Identifikatoren.)
- 3. Sammelt Portemonnaiematerial a Geheimnisser. De Skript féiert duerch den Heemverzeichnis vum Benotzer — ~/.config/solana, ~/.ethereum/Schlësselgeschäft, ~/.Gießerei, ~/.Schutzhelm, ~/.ssh, an Desktop/Dokumenter/erofgelueden (inklusiv spueneschsproocheg Dossiernimm), plus ~/.env an Shell rc Dateien, an dat Äquivalent AppData Standuerter op Windows. Et zielt op Ethereum privat Schlësselen, Bitcoin WIF Schlësselen, BIP-39 Seed Phrasen, Solana Schlësselpairen, Ethereum Keystore JSON, SSH Schlësselen a geheimhalteg Ëmweltvariablen. Déi méi grouss Variant (an abi-encode, base58-utils, eth-entwéckler) enthält dat komplett BIP-39 Wierderbuch mat 2048 Wierder a benotzt regulär Ausdréck fir Extrait individuell Schlësselen a validéiert Seed-Phrasen aus all Text, deen et liest; déi zwou méi kleng Varianten fannen amplaz Dateien no Schlësselwuert (Som, mnemonesch, Portemonnaie späicheren, metamask, Geescht, Ledger, Trezor, …) a ganz Dateien eroplueden.
- 4. Verschlësselen an exfiltréieren iwwer e ëffentleche Pinning-Service. All Befund ass mat engem Fangerofdrock vum Host gebündelt (Benotzernumm@Hostnumm, Plattform, Zäitstempel) a verschlësselt mat engem fest kodéierten RSA-4096 ëffentleche Schlëssel, deen am Skript integréiert ass. Den verschlësselten Enregistrement gëtt dann eropgelueden andeems en op IPFS gepinnt gëtt iwwer api.pinata.cloud/pinning/pinJSONToIPFS, authentifizéiert mat hardcoded Pinata API Umeldungsinformatiounen. Et gëtt kee speziellen C2 Server fir ze beschlagnahmen: déi geklaut Donnéeën sinn an engem ëffentlechen dezentraliséierte Späicher geparkt, deen vum Bedreiwer mat den resultéierenden Inhaltshashes ofgeruf ka ginn. Uploads ginn mat e puer Sekonne zoufällegen Jitter ofgestëmmt, an e lokale Log vun Zäitstempel | Schlësseltyp | zréckginn Hash gëtt bei ~/.cache-db/.node-sync/.sl.
- 5. Bleift a beaconéiert op engem 12-Stonne-Zyklus. Déi zweet Etapp restauréiert seng eege Persistenz - e Cron-Eintrag op Linux, e com.apple.syncd launchd Job op macOS, an eng geplangten Aufgab mam Numm WindowsNodeSync op Windows — agestallt fir all 12 Stonnen nei auszeféieren. Notéiert datt dëst eng ënnerschiddlech ass Windows-Aufgabennumm vun deem, deen den Dropper installéiert (WinNodeSync); béid sinn derwäert ze sichen.
Timeline
Déi aacht Päck goufen den 13. Juli 2026 an den 14. Juli 2026 an engem knappen Ausbroch publizéiert. Verschidde vun hinnen hunn méi wéi eng Versioun; den Dropper ass a verschiddene Versiounen identesch, nëmmen d'Linnoffsets verännere sech wann d'Gréisst vum guttméigleche Versuergungscode driwwer ännert.
| Datum | Héichwaasser |
|---|---|
| 2026-07-13 | Déi éischt Paketen am Cluster erschéngen ënner engem Editeur (solana-key-utils, eth-wallet-helpers, crypto-validate-lib an fréi Versioune vum Rescht) |
| 2026-07-13 → 07-14 | Rescht Nimm a weider Versioune publizéiert; déiselwecht ugehaangte Dropper gëtt an all Versioun geliwwert. |
| 2026-07-14 | All aacht markéiert an analyséiert; all Pakete kënnen nach ëmmer aus der Registrierung installéiert ginn |
Iwwer de ganze Burst huet sech d'Registrierungsruff vum Editeur vun ongeféier neutral um Ufank vum Cluster op staark negativ geännert, wéi sech d'Detektiounen ugesammelt hunn - eng observéierbar Niewewierkung vun de markéierte Paketen, keng entworf Funktioun.
Indicateuren vun Kompromëss
All Indikatoren hei ënnendrënner goufen zum Zäitpunkt vun der Analyse als präsent bestätegt - déi an den Tabellen vun der "Zweeter Phas" duerch Decodéierung test/fixtures/keypairs.dat an d'Liesung vun der erhollter syncd.js.
Dateien a Weeër
| Luucht | Roll |
|---|---|
~/.cache-db/.node-sync/syncd.js | Decodéiert zweet Stuf, geschriwwen mam Modus 0o700 |
~/.cache-db/.node-sync/.sl | Lokalen Exfiltratiounsprotokoll (Zäitstempel | Schlësseltyp | IPFS-Hash) |
test/fixtures/keypairs.dat | Base64-kodéiert Notzlaascht am Tarball als "Testgerät" ageriicht |
Netzwierkinfrastruktur vun der zweeter Stuf (gewonnen aus syncd.js)
| Luucht | Roll |
|---|---|
gist.githubusercontent.com/juang55/b298754cb72942b1cdcf02ccd45cde2f/raw/cfg.txt | Aktivéierung ouni Ausnam; de Skript leeft nëmme wann d'Konfiguratioun gelies gëtt active=1 |
Qmcqz3w8j4qFQXDAXAxnrdc2oSX3nzBT4NqtpTqL8mr1ga | IPFS-Konfiguratiounsfallback (CID) |
QmdTXoqVmTHY1i4ZWLdLkoQ9YChp5TXPh5cWXwnAYZt5iF | IPFS-Konfiguratiounsfallback (CID) |
QmfJkLU5gdCpqbbqEjWYC2anXW9FmuEeSLLeLiHVJKYUjp | IPFS-Konfiguratiounsfallback (CID) |
gateway.pinata.cloud, ipfs.io, cloudflare-ipfs.com | IPFS-Gateways, déi benotzt gi fir de Konfiguratiounsfallback ofzelueden |
api.pinata.cloud/pinning/pinJSONToIPFS | Exfiltratiouns-Endpunkt, geklaut Daten op ëffentlechen IPFS gespäichert |
| Pinata API Schlëssel | 13c766575b9270a9825d, hardcodéiert Exfiltratiounsautorisatioun |
Sammelziler vun der zweeter Phas (gewonne vu syncd.js)
| Luucht | Roll |
|---|---|
~/.config/solana, ~/.ethereum/keystore, ~/.foundry, ~/.hardhat, ~/.ssh, ~/.env, Shell rc Dateien | Verzeichnisser/Dateien no Schlësselen a Geheimnisser gesicht |
AppData\Roaming\Solana, AppData\Local\ethereum\keystore | Windows-Äquivalente gesicht |
| Artefakttypen, déi geerntet goufen | ETH privat Schlësselen, Bitcoin WIF, BIP-39 Seed Phrasen, Solana Schlësselpairen, Ethereum Keystore JSON, SSH Schlësselen, geheim Ëmfeldvariablen |
Persistenzartefakte
| Plattform | Luucht |
|---|---|
| Linux | Cron-Entrée starten syncd.js; installéiert iwwer Crontab gefiltert duerch grep -v syncd |
| Windows | geplangten Aufgab WinNodeSync (Drëpser) an WindowsNodeSync (zweet Etapp) |
| macOS | Launchd-Label com.apple.syncd |
| all | Déi zweet Phas widderhëlt sech an engem 12-Stonne-Zyklus |
Verhalen
- Selbstopruffend Funktioun bäigefüügt nodeems module.exports, Zäitplang a setTimeout vun ~37,000 ms beim Import.
- Kand_prozess spawn("Knuet", ) mat der ofgetrennter Optiounsset.
- Idle-gated Aktivéierung an der zweeter Phas (xprintidle / Ioreg HIDIdleTime / PowerShell Idlezäit; ~15-Minutte Schwellwäert).
- RSA-4096 Verschlësselung pro Finding, dann HTTPS POST op eng ëffentlech IPFS Pinning API.
Paketen a Versiounen (npm, Publisher solbuilder_io)
| Pak | Versiounen |
|---|---|
base58-utils | 1.0.0, 1.0.1, 1.0.3 |
abi-encode | 1.0.0, 1.0.1, 1.0.2 |
eth-dev | 1.0.0, 1.0.1, 1.0.2 |
arb-kit | 1.0.0, 1.0.1 |
layer2-sdk | 1.0.0, 1.0.1 |
solana-key-utils | 1.0.0 |
eth-wallet-helpers | 1.0.0 |
crypto-validate-lib | 1.0.0 |
Publisher
- solbuilder_io - angel_lopez89[@]proton[.]me, E-Mail net verifizéiert, kee verifizéierte Quellkontrollkonto, kee verlinkte Repository.
Attributioun & observéiert Verhalen
Déi aacht Pakete deelen sech ee Publisher-Kont an eng Payload. Jiddweree vun hinnen ass e trivialt Pak - e puer Kilobyte richtege Utility-Code mam selwechten Dropper derbäi - publizéiert ouni e verlinkte Repository an ënner enger net verifizéierter E-Mail-Adress am Stil vun engem Wegwerf-E-Mail-Adress. Déi Uniformitéit, de gemeinsame Drop-Pfad, déi gemeinsam Persistenz-Labels an déi gemeinsam ... Schlësselpairen.dat Staging-Dateie sinn dat, wat de Cluster zesummebréngt.
D'Päckelcher sinn ongewéinlech oppe wat hiert eegent Verhalen ugeet. Solana-Schlëssel-Utils enthält Inline-Kommentaren, déi den ugehängte Block einfach beschreiwen - een nennt en PHANTOM: onsichtbar Persistenz, en aneren (op Spuenesch) liest Topo am Hannergrond auswerfen, „de Maulwurf am Hannergrond ausféieren.“ Dëst sinn d'Annotatioune vum Code selwer iwwer dat, wat e mécht; den Numm vun der Kampagne an dësem Post ass vun deem éischten Label zesumme mam gefälschten Node „Sync Daemon“ (synchroniséiert) déi d'Persistenzmaschinn imitéiert.
Mir beschreiwen nëmmen, wat de Code observéierbar mécht. D'Benennung vun de Paketen - all Krypto-, Portemonnaie- a Blockchain-Tooling-Begrëffer - weist op d'Entwécklerpublikum hin, dat se am wahrscheinlechsten mam Numm zitt; et eleng bestëmmt net, wien den Editeur ass. Déi zweet Phas war komplett rekonstruéierbar andeems de base64 Fixture decodéiert gouf, an hiert Verhalen ass uewe beschriwwen: et sammelt Portemonnaie-Schlësselen, Seed-Phrasen a Geheimnisser a verschéckt se, RSA-verschlësselt, an en ëffentlechen IPFS-Späicher iwwer Pinata. Eng bemierkenswäert Designwahl ass d'Feele vun engem privaten C2-Server - d'Konfiguratioun kënnt vun engem GitHub Gist an IPFS, an geklaut Daten ginn an engem ëffentlechen dezentraliséierte Späicher geparkt, deen duerch Inhalts-Hash geschalt ass, déi allebéid méi schwéier ze beschlagnahme sinn wéi en eenzegen Ugräifer-kontrolléierten Host. Zum Zäitpunkt vum Schreiwen gouf keng fréier ëffentlech Berichterstattung fonnt, déi dësem Cluster entsprécht.
Impakt, Trends & Richtlinne fir Verdeedeger
Wien ass ausgesat. Jiddereen, deen ee vun dëse Paketen zu engem Node-Projet bäigefüügt huet an dann Code ausgeféiert huet, deen en importéiert. Well d'Detonatioun zur Importzäit anstatt zur Installatiounszäit ass, ass et net genuch, datt de Pak einfach präsent ass - mee all normal Notzung, déi de Modul lued, erreecht d'Payload. D'Lockernimm zielen op Entwéckler, déi op Ethereum, Solana, Arbitrum, Layer-2 an allgemenge Portemonnaie-/Codéierungstools opbauen - déi Populatioun, déi am wahrscheinlechsten genau déi Verméigen huet, déi déi zweet Stuf sicht. Jiddereen, deen ee vun dëse Moduler op enger Maschinn ausgeführt huet, déi Portemonnaie-Schlësselen, Seed-Phrasen, Schlësselspeicher, SSH-Schlësselen oder ... enthält. .NS Geheimnisser sollten dës Umeldungsinformatioune als kompromittéiert behandelen a se rotéieren.
Zwee Musteren, déi et wäert sinn, sech ze vereenen. Éischten, Notzlaascht als Armatur: déi zweet Stuf als base64 an enger Datendatei mat engem plausibelen Numm liwweren (test/fixtures/keypairs.dat) hält déi siichtbar Quell vum Pak propper a dréckt den béiswëllegen Inhalt an eng Datei, déi vun Iwwerpréiwungsinstrumenter a mënschleche Skims dacks als inert Daten behandelt gëtt. Zweetens, Importzäitverzögert Ausféierung mat plattformiwwergräifender Persistenz: den Trigger vum Install Hook ze läschen, en Timer derbäizesetzen an dann iwwer Cron, geplangten Aufgaben a Launchd weiderzemaachen ass e bewossten Schrëtt ewech vun den méi haartnäckegen Install-Skript-Techniken, déi automatiséiert Registry-Scanning am genausten iwwerwaacht.
Richtlinne fir Verdeedeger a Betreiber:
- Behandelt den ugehängte Code duerno module.exports als Prioritéit fir d'Iwwerpréiwung - verstoppt sech d'Dropper-Logik dacks ënner der "richteger" Moduluewerfläch.
- Gitt net dovun aus, datt Datendateien inert sinn. E base64 Blob ënner Test/Spillplang/ dat zur Lafzäit gelies an decodéiert gëtt, ass ausführbar-ugrenzend; markéiert Lafzäitliesunge vu Fixture-Dateien, déi e fidderen Funktioun/eval/schreiwen-dann-spawnen Kette.
- Juegd op de Wee fir den Drop ~/.cache-db/.node-sync/ an fir d'Persistenzunitéiten WinNodeSync (geplangte Aufgab) an com.apple.syncd (launchd) op Entwécklermaschinnen, déi dës Nimm erausgeholl hunn.
- Alarm bei Node-Prozesser, déi Cron-Entréen, geplangten Aufgaben oder Launchd-Jobs erstellen - legitim Bibliothéike maachen dat selten beim Import.
- Léiwer Lockfiles a gepinnte Versiounen, a préift den Ënnerscheed vun all neier klenger "Utility"-Ofhängegkeet, besonnesch Null-Ofhängegkeetspakete publizéiert vun net verifizéierte Konten ouni verlinkte Repository.
Fir Registry-Defensiver ass d'Konklusioun, datt d'Iwwerwaachung vum Install-Hook néideg ass, awer net ausräichend: en Import-Zäit-, Timer-verzögert Dropper, deen an enger Datendatei stagnéiert ass, hält eng Kontroll nëmmen zur Installatiounszäit stand, an de Persistenzschritt ass dacks dat lautst observéierbaart Signal, dat iergendwou ze fange bleift.







