TL, DR
Jeden vydavatel NPM vydal osm malých balíčků, jejichž názvy znějí jako každodenní stavební kameny pro vývoj blockchainu a peněženek. base58-utils, abi-encode, eth-dev, arb-kit, layer2-sdk, solana-key-utils, eth-wallet-helpers, a crypto-validate-libKaždý z nich obsahuje funkční utilitu. Za touto utilitou je však připojen samovolný blok kódu, který se spustí v okamžiku importu modulu.
Zhruba 37 sekund po importu, tento blok dekóduje datovou část, která se dodává uvnitř balíčku maskovaná jako testovací zařízení, zapíše ji do skrytého souboru v domovském adresáři uživatele a zaregistruje se k restartu při každém login ve Windows, macOS a Linuxu a spouští dekódovaný skript jako oddělený proces. Během instalace npm se nic nespustí; čeká se na import a spuštění kódu, což je klidnější okamžik než samotná instalace.
Užitečná zátěž není neprůhledná. Dodává se jako prostý base64, takže dekódování „testovacího zařízení“ obnoví druhou fázi v plném rozsahu: a krypto peněženka a zloděj tajemství který čeká, až bude stroj nečinný, shromažďuje soukromé klíče a seed fráze, šifruje každý nalezený klíč pevně zakódovaným klíčem RSA-4096 a exfiltruje jej jeho připnutím k veřejnému úložišti IPFS, přičemž se každých 12 hodin odesílá zpět.
Sledujeme shluk jako PhantomSyncVšech osm balíčků bylo v době analýzy aktivních v registru npm a publikovaných pod jedním účtem.
| Ekosystém | Npm |
| Balíčky | base58-utils, abi-encode, eth-dev, arb-kit, layer2-sdk, solana-key-utils, eth-wallet-helpers, crypto-validate-lib |
| Cílové platformy | Windows, MacOS, Linux |
| Základní chování | Zpožděný dropper v době importu skrytý jako testovací přípravek; instaluje perzistenci napříč platformami |
| Užitné zatížení | Krypto peněženka a zrádce tajných dat, šifrování RSA-4096, exfiltrace přes veřejné pinování IPFS |
Anatomie útoku
Každý balíček na první pohled vypadá nenápadně. base58-utilityje například několik kilobajtů pomocného kódu Base58 / Bitcoin-WIF s nulovou závislostí – přesně to, co název slibuje. Příslušný kód se nachází po modulu modul.exports, kam se čtenář prohlížející začátek souboru pravděpodobně nepodívá: samovolající funkce, která se sama plánuje pomocí časovače.
Řetězec operací, rekonstruovaný ze zdrojového kódu balíčku, probíhá takto:
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 processVynikají dvě designové možnosti.
Užitečné zatížení se pohybuje jako testovací přípravek. Druhá fáze není napsána jako zřejmý kód. Je v ní obsažena test/fixtures/keypairs.dat, soubor base64, jehož název se splývá s balíčkem, který tvrdí, že zvládá páry klíčů. Pro člověka prohlížejícího tarball to vypadá jako vzorová data; pro připojený kód je to skript k dekódování a spuštění. Samotný dropper neobsahuje žádnou síťovou adresu – ty se nacházejí ve druhé fázi – ale neexistuje žádné další zmatkování: fixture je jedna vrstva base64, takže jeho dekódování (base64 -d) obnoví celou syncd.js a jeho chování v síti. Následující část se zabývá tím, co tato obnovená fáze dělá.
Detonace je zpožděná a vázána na dovoz, nikoli na instalaci. Protože spouštěčem je vyžadovat() plus ~37sekundový časovač namísto instalačního hooku, toto chování obchází kontroly, které sledují pouze npm install krok a zpoždění trvá déle než mnoho krátkodobých běhů v sandboxu a CI. Než se cokoli spustí, instalace, která balíček stáhla, je už dávno dokončena.
Jakmile je dekódovaný skript na disku v ~/.cache-db/.node-sync/syncd.js — cesta zvolená tak, aby se četla jako běžný adresář mezipaměti — dropper umožňuje přežít restartování na všech třech hlavních platformách:
- Linux: položka cron, která restartuje skript. Položka se nainstaluje filtrováním existujícího crontabu přes grep -v syncd, což má vedlejší účinek, že se nová položka vynechá z prostého výpisu, který grepuje pro stejný název.
- Windows: naplánovaný úkol s názvem WinNodeSync, nastavené na reprízu v 12minutovém intervalu.
- MacOS: úloha launchd s označením com.apple.syncd, přítomný v několika balíčcích – označení, které napodobuje legitimní systémovou službu Apple.
Skript se poté okamžitě spustí jako oddělený proces, takže po ukončení importujícího programu pokračuje v běhu.
Co dělá druhá fáze
Protože zařízení má jednu vrstvu base64, druhý stupeň dekóduje čistě a lze jej přečíst v plném rozsahu. Všech osm balíčků obsahuje jednu ze tří variant stejného skriptu, který se v komentáři záhlaví identifikuje jako phantom syncd v3 — topo durmiente („spící krtek“). Jeho úkolem je krást materiály kryptoměnové peněženky a vývojářská tajemství a odesílat je ze stroje. Probíhá v těchto krocích:
- 1. Počkejte, dokud se stroj nepřepne do klidového stavu. Než cokoli uděláte, syncd.js kontroluje, jak dlouho je uživatel neaktivní, a pokračuje až po určité prahové hodnotě (kolem 15 minut) – xprintidle na Linuxu, ioreg HIDIdleTime v systému macOS a dotaz PowerShellu v době nečinnosti ve Windows. Sběr dat proto obvykle probíhá, když nikdo není u klávesnice.
- 2. Přineste dálkově ovládaný aktivační spínačSkript si před provedením akce stáhne malou konfiguraci z deaddropu. Primárním zdrojem je nezpracovaná URL adresa souboru Gist z GitHubu (gist.githubusercontent.com/juang55/…/cfg.txt); skript se aktivuje pouze tehdy, pokud tato konfigurace přečte aktivní=1Pokud není obsah dostupný, vrátí se zpět ke třem pevně zakódovaným identifikátorům obsahu IPFS, které jsou načteny prostřednictvím veřejných bran. gateway.pinata.cloud, ipfs.io, a cloudflare-ipfs.comTo dává operátorovi možnost dodatečného ovládání/odepnutí a záložní možnost odolnou proti zneškodnění. (Nejmenší varianta, dodávaná v crypto-validate-lib, pomocníci s eth-peněženkami, a solana-key-utils, má odstraněnou vrstvu GIST a spoléhá se pouze na identifikátory IPFS.)
- 3. Sbírejte materiál a tajemství peněženky. Skript prochází domovský adresář uživatele — ~/.config/solana, ~/.ethereum/úložiště klíčů, ~/.foundry, ~/.ochranná přilba, ~ / .ssh, a Desktop/Dokumenty/Počet stažení (včetně názvů složek ve španělštině) a navíc ~/.env a soubory rc prostředí Shell a ekvivalentní AppData umístění ve Windows. Zaměřuje se na soukromé klíče Etherea, klíče Bitcoinu WIF, seed fráze BIP-39, páry klíčů Solana, JSON úložiště klíčů Etherea, klíče SSH a proměnné prostředí s tajnými kódy. Větší varianta (v abi-kódování, base58-utility, eth-dev) obsahuje kompletní slovník BIP-39 s 2048 slovy a používá regulární výrazy k extrakt jednotlivé klíče a ověřené základní fráze z jakéhokoli textu, který přečte; dvě menší varianty místo toho porovnávají soubory podle klíčového slova (semínko, mnemotechnická pomůcka, peněženka, metamask, přízrak, účetní kniha, trezor, …) a nahrávat celé soubory.
- 4. Zašifrujte a exfiltrujte pomocí veřejné služby pro připínání. Každý nález je spojen s otiskem hostitele (uživatelské_uživatel@název_hostitele, platforma, časové razítko) a zašifrovaný pomocí pevně zakódovaného veřejného klíče RSA-4096 vloženého do skriptu. Zašifrovaný záznam je poté nahrán jeho připnutím k IPFS prostřednictvím api.pinata.cloud/pinning/pinJSONToIPFS, ověřeno pomocí pevně zakódovaných přihlašovacích údajů Pinata API. Neexistuje žádný speciální server C2, který by bylo možné zabavit: ukradená data jsou uložena ve veřejném decentralizovaném úložišti, odkud je operátor může získat pomocí výsledných hashů obsahu. Nahrávání je rozloženo s několika sekundami náhodného chvění a lokální protokol časové razítko | typ klíče | vrácený hash je uchováván v ~/.cache-db/.node-sync/.sl.
- 5. Vytrvejte a vysílájte signály v 12hodinovém cyklu. Druhá fáze obnovuje vlastní perzistenci – položku cron v Linuxu, com.apple.syncd úloha launchd v systému macOS a naplánovaná úloha s názvem WindowsNodeSync ve Windows – nastaveno na opětovné spuštění každých 12 hodin. Upozorňujeme, že se jedná o odlišný Název úlohy systému Windows z té, kterou instaluje dropper (WinNodeSync); obojí stojí za to hledat.
Timeline
Osm balíčků bylo publikováno v krátkém čase 13. a 14. 7. 2026. Některé z nich obsahují více než jednu verzi; dropper je ve všech verzích identický, pouze offsety řádků se mění s tím, jak se mění velikost neškodného utility kódu nad ním.
| Datum | událost |
|---|---|
| 2026-07-13 | První balíčky v clusteru se objeví pod jedním vydavatelem (solana-key-utils, eth-wallet-helpers, crypto-validate-lib a rané verze zbytku) |
| 2026-07-13 → 07-14 | Zbývající názvy a následné verze zveřejněny; stejné připojené dropper lodě v každém |
| 2026-07-14 | Všech osm označeno a analyzováno; každý balíček je stále nainstalovatelný z registru |
Během celého období se reputace vydavatele v registru změnila z přibližně neutrální na začátku clusteru na silně negativní s postupným narůstáním detekcí – což byl pozorovatelný vedlejší účinek označování balíčků, nikoli záměrná funkce.
Ukazatele kompromisu
Všechny níže uvedené indikátory byly v době analýzy potvrzeny jako přítomné – ty v tabulkách „Druhé fáze“ – dekódováním test/fixtures/keypairs.dat a čtení získaných dat syncd.js.
Soubory a cesty
| Indikátor | Role |
|---|---|
~/.cache-db/.node-sync/syncd.js | Dekódovaný druhý stupeň, zapsaný v módu 0o700 |
~/.cache-db/.node-sync/.sl | Lokální protokol exfiltrace (časové razítko | typ klíče | hash IPFS) |
test/fixtures/keypairs.dat | Datové zatížení kódované v Base64 je uloženo uvnitř tarballu jako „testovací zařízení“ |
Síťová infrastruktura druhé fáze (obnovená ze syncd.js)
| Indikátor | Role |
|---|---|
gist.githubusercontent.com/juang55/b298754cb72942b1cdcf02ccd45cde2f/raw/cfg.txt | Aktivační deaddrop; skript se spustí pouze v případě, že konfigurace přečte active=1 |
Qmcqz3w8j4qFQXDAXAxnrdc2oSX3nzBT4NqtpTqL8mr1ga | Záložní konfigurace IPFS (CID) |
QmdTXoqVmTHY1i4ZWLdLkoQ9YChp5TXPh5cWXwnAYZt5iF | Záložní konfigurace IPFS (CID) |
QmfJkLU5gdCpqbbqEjWYC2anXW9FmuEeSLLeLiHVJKYUjp | Záložní konfigurace IPFS (CID) |
gateway.pinata.cloud, ipfs.io, cloudflare-ipfs.com | Brány IPFS používané k načtení záložní konfigurace |
api.pinata.cloud/pinning/pinJSONToIPFS | Koncový bod exfiltrace, ukradená data připnutá na veřejný IPFS |
| Klíč API Pinata | 13c766575b9270a9825d, pevně zakódované pověření pro exfiltraci |
Cíle kolekce druhé fáze (obnovené ze syncd.js)
| Indikátor | Role |
|---|---|
~/.config/solana, ~/.ethereum/keystore, ~/.foundry, ~/.hardhat, ~/.ssh, ~/.env, soubory rc shellu | Adresáře/soubory prohledávané kvůli klíčům a tajným klíčům |
AppData\Roaming\Solana, AppData\Local\ethereum\keystore | Vyhledané ekvivalenty ve Windows |
| Typy získaných artefaktů | Soukromé klíče ETH, Bitcoin WIF, seed fráze BIP-39, páry klíčů Solana, JSON úložiště klíčů Ethereum, SSH klíče, tajné proměnné prostředí |
Artefakty perzistence
| Plošina | Indikátor |
|---|---|
| Linux | spuštění cronu syncd.js; nainstalováno přes crontab, filtrováno skrz grep -v syncd |
| Windows | naplánovaný úkol WinNodeSync (kapatka) a WindowsNodeSync (druhá fáze) |
| macOS | launchd štítek com.apple.syncd |
| Vše | Druhá fáze se opakuje v 12hodinovém cyklu. |
Behaviorální
- Samovolná funkce připojená za modul.exports, plánování setTimeout ~37 000 ms při importu.
- podřízený_proces spawn(„uzel“, ) s oddělenou sadou možností.
- Aktivace s volnoběhem ve druhé fázi (xprintidle / ioreg Doba nečinnosti HIDIdleTime / PowerShellu; prahová hodnota ~15 minut).
- Šifrování RSA-4096 na základě nalezení a poté HTTPS POST k veřejnému API pro připínání IPFS.
Balíčky a verze (npm, vydavatel solbuilder_io)
| Balíček | verze |
|---|---|
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 |
Vydavatel
- solbuilder_io - angel_lopez89[@]proton[.]já, neověřený e-mail, žádný ověřený účet pro správu zdrojového kódu, žádné propojené repozitář.
Atribuce a pozorované chování
Osm balíčků sdílí jeden účet vydavatele a jeden datový obsah. Každý z nich je triviální balíček – několik kilobajtů skutečného užitného kódu se stejným připojeným dropperem – publikovaný bez propojeného repozitáře a pod neověřeným e-mailem v jednorázovém stylu. Tato jednotnost, sdílená cesta pro dropování, sdílené popisky perzistence a sdílené… keypairs.dat stagingové soubory spojují cluster dohromady.
Balíčky jsou ohledně svého vlastního chování neobvykle upřímné. solana-key-utils obsahuje vložené komentáře, které popisují připojený blok jednoduchým způsobem – označí se FANTOM: neviditelná vytrvalost, další (ve španělštině) zní Vyjmout topografii na pozadí, „spustit krtka na pozadí.“ Toto jsou vlastní anotace kódu k tomu, co dělá; název kampaně v tomto příspěvku je převzat z prvního popisku spolu s falešným uzlem „sync daemon“ (synchronizováno), kterou napodobuje perzistenční mechanismus.
Popisujeme pouze to, co kód dělá pozorovatelně. Pojmenování balíčků – všechny se týkají kryptoměn, peněženek a blockchainových nástrojů – naznačuje, kdo si je s největší pravděpodobností stáhne; samo o sobě to neurčuje, kdo je vydavatelem. Druhá fáze byla plně obnovitelná dekódováním fixture base64 a její chování je popsáno výše: shromažďuje klíče od peněženky, seed fráze a tajné kódy a přesune je, šifrované pomocí RSA, do veřejného úložiště IPFS prostřednictvím služby Pinata. Pozoruhodnou konstrukční volbou je absence soukromého serveru C2 – konfigurace přichází z GitHub Gist a IPFS a ukradená data jsou parkována ve veřejném decentralizovaném úložišti s klíčem hash obsahu, přičemž obojí je obtížnější získat než jeden hostitel ovládaný útočníkem. V době psaní tohoto článku nebyly nalezeny žádné předchozí veřejné zprávy odpovídající tomuto klastru.
Dopad, trendy a pokyny pro obránce
Kdo je odhalen. Každý, kdo přidal jeden z těchto balíčků do projektu Node a poté spustil kód, který jej importuje. Protože detonace probíhá spíše v době importu než instalace, pouhá přítomnost balíčku nestačí – ale jakékoli běžné použití, které načte modul, dosáhne jeho užitečného zatížení. Názvy lákadel cílí na vývojáře, kteří staví na Ethereu, Solaně, Arbitru, Layer-2 a obecných nástrojích pro peněženky/kódování – populaci, která s největší pravděpodobností vlastní přesně ta aktiva, která druhá fáze hledá. Každý, kdo spustil jeden z těchto modulů na počítači s klíči k peněžence, seed frázemi, úložišti klíčů, SSH klíči nebo… .env Tajné údaje by měly s těmito přihlašovacími údaji zacházet jako s kompromitovanými a střídat je.
Dva vzorce, které stojí za to internalizovat. Za prvé, užitečné zatížení jako upínací prvek: odeslání druhé fáze jako base64 uvnitř datového souboru s věrohodným názvem (test/fixtures/keypairs.dat) udržuje viditelný zdroj balíčku v čistotě a škodlivý obsah ukládá do souboru, který kontrolní nástroje a lidské prohledávače často považují za inertní data. Za druhé, zpožděné spuštění importu s perzistencí napříč platformamiPřesunutí spouštěče z instalačního hooku, přidání časovače a jeho následné zachování v cronu, naplánovaných úlohách a launchd je záměrný krok od hlučnějších technik instalačních skriptů, které automatizované skenování registru sleduje nejpečlivěji.
Pokyny pro obránce a správce:
- Ošetřit připojený kód po modul.exports jako priorita při revizi – logika dropperu se často skrývá pod „skutečným“ povrchem modulu.
- Nepředpokládejte, že datové soubory jsou inertní. Objekt base64 blob pod test/přípravky/ který je čten za běhu a dekódován, je přilehlý ke spustitelnému souboru; označit běhové čtení souborů fixtures, které poskytují funkce/eval/napiš-pak-potěr řetěz.
- Hledejte cestu k pádu ~/.cache-db/.node-sync/ a pro jednotky perzistence WinNodeSync (naplánovaný úkol) a com.apple.syncd (launchd) na vývojářských počítačích, které tyto názvy stáhly.
- Upozornění na procesy Node, které vytvářejí položky cron, naplánované úlohy nebo úlohy launchd – legitimní knihovny to při importu dělají jen zřídka.
- Upřednostňujte lockfiles a pinned verze a zkontrolujte rozdíly u všech nových malých „utilit“ závislostí, zejména publikované balíčky s nulovou závislostí neověřenými účty bez propojeného repozitáře.
Pro obránce registru je důležité si uvědomit, že monitorování instalačních hook je nezbytné, ale ne postačující: dropper s časovačem zpožděným v době importu, umístěný uvnitř datového souboru, projde kontrolou pouze v době instalace a krok perzistence je často nejhlasitějším pozorovatelným signálem, který je třeba zachytit.







