TL; DR
Yksi npm-julkaisija lähetti kahdeksan pientä pakettia, joiden nimet tuntuivat lohkoketju- ja lompakkokehityksen arkipäiväisiltä rakennuspalikoilta. base58-utils, abi-encode, eth-dev, arb-kit, layer2-sdk, solana-key-utils, eth-wallet-helpersja crypto-validate-libJokainen sisältää toimivan apuohjelman. Apuohjelman jälkeen on kuitenkin liitetty itseään kutsuva koodilohko, joka suoritetaan heti, kun moduuli tuodaan.
Noin 37 sekuntia tuonnin jälkeen, joka lohko dekoodaa paketin sisällä testilaitteeksi naamioidun hyötykuorman, kirjoittaa sen käyttäjän kotihakemistoon piilotettuun tiedostoon ja rekisteröi itsensä käynnistymään uudelleen joka login Windowsissa, macOS:ssä ja Linuxissa ja käynnistää dekoodatun komentosarjan erillisenä prosessina. Tässä ei ole mitään tekemistä npm-asennuksen kanssa; se odottaa koodin tuontia ja suorittamista, mikä on asennuksen kaltaista hiljaisempaa aikaa.
Hyötykuorma ei ole läpinäkymätön. Se toimitetaan tavallisena base64-muodossa, joten "testauslaitteen" dekoodaus palauttaa toisen vaiheen kokonaisuudessaan: a kryptolompakko ja salaisuuksien varastaja joka odottaa koneen olevan käyttämättömänä, kerää yksityiset avaimet ja siemenlausekkeet, salaa jokaisen löydön kovakoodatulla RSA-4096-avaimella ja purkaa sen kiinnittämällä sen julkiseen IPFS-tallennustilaan ja lähettää takaisin 12 tunnin välein.
Seuraamme klusteria seuraavasti PhantomSyncKaikki kahdeksan pakettia olivat analyysin tekohetkellä saatavilla npm-rekisterissä yhden tilin alla.
| ekosysteemi | NPM |
| Jäsenyydet | base58-utils, abi-encode, eth-dev, arb-kit, layer2-sdk, solana-key-utils, eth-wallet-helpers, crypto-validate-lib |
| Kohdealustoja | Windows, macOS, Linux |
| Ydinkäyttäytyminen | Viivästetty, tuonnin aikana piilotettu pudotin testikiinnittimeksi; asentaa alustojen välisen pysyvyyden |
| hyötykuorma | Kryptovaluuttalompakko ja salaisuuksien varastaja, RSA-4096-salaus, vuoto julkisen IPFS-pinauksen kautta |
Hyökkäyksen anatomia
Jokainen paketti näyttää ensimmäisellä lukukerralla vaatimattomalta. base58-utilson esimerkiksi muutaman kilotavun mittainen nollariippuvainen Base58 / Bitcoin-WIF-apukoodi – juuri sitä mitä nimi lupaa. Asiaankuuluva koodi sijaitsee jälkeen moduulin moduuli.vienti, johon tiedoston alkuun silmäilevä lukija ei todennäköisesti katso: itseään kutsuva funktio, joka aikatauluttaa itsensä ajastimella.
Paketin lähdekoodista rekonstruoitu operaatioketju toimii näin:
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 process Kaksi suunnitteluvaihtoehtoa erottuu joukosta.
Hyötykuorma kulkee testilaitteena. Toista vaihetta ei kirjoiteta itsestään selvänä koodina. Se sijaitsee testi/kalusteet/avainpairs.dat, base64-tiedosto, jonka nimi sulautuu pakettiin, joka väittää käsittelevänsä avainpareja. Tarball-tiedostoa silmäilevälle ihmiselle se näyttää esimerkkidatalta; liitettävälle koodille se on dekoodattava ja suoritettava skripti. Dropper itsessään ei sisällä verkko-osoitetta – ne sijaitsevat toisessa vaiheessa – mutta siinä ei ole ylimääräistä hämärrystä: kiinnityslaite on yksi base64-kerros, joten sen dekoodaus (base64 -d) palauttaa täyden syncd.js ja sen verkkokäyttäytymistä. Seuraavassa osiossa käydään läpi, mitä kyseinen palautettu vaihe tekee.
Räjäytys on viivästynyt ja sidottu tuontiin, ei asennukseen. Koska liipaisin on vaatia () plus noin 37 sekunnin ajastin asennuskoukun sijaan, toiminta ohittaa tarkistukset, jotka tarkkailevat vain npm asentaa vaihe, ja viive kestää pidempään kuin monet lyhytikäiset hiekkalaatikko- ja CI-ajot. Siihen mennessä, kun mikään suoritetaan, paketin vetänyt asennus on jo kauan sitten päättynyt.
Kun dekoodattu skripti on levyllä osoitteessa ~/.cache-db/.node-sync/syncd.js — polku, joka on valittu luettavaksi kuten tavallinen välimuistihakemisto — dropperin avulla se selviää uudelleenkäynnistyksissä kaikilla kolmella pääalustalla:
- Linux: cron-merkintä, joka käynnistää komentosarjan uudelleen. Merkintä asennetaan suodattamalla olemassa oleva crontab läpi grep -v syncd, jolla on sivuvaikutuksena se, että uusi merkintä jää pois tavallisesta listauksesta, joka suorittaa grep-haun saman nimen osalta.
- Windows: ajoitettu tehtävä nimeltä WinNodeSync, asetettu toistumaan 12 minuutin välein.
- MacOS: käynnistetty työ, jonka nimi on com.apple.syncd, joka esiintyy useissa paketeissa – merkintä, joka jäljittelee laillista Applen järjestelmäpalvelua.
Skripti käynnistetään sitten välittömästi irrotettuna prosessina, joten se jatkaa suoritusta tuontiohjelman sulkeuduttua.
Mitä toinen vaihe tekee
Koska kiinnityslaite on yksi base64-kerros, toinen vaihe dekoodaa puhtaasti ja se voidaan lukea kokonaan. Kaikissa kahdeksassa paketissa on yksi saman skriptin kolmesta muunnelmasta, joka identifioituu otsikkokommentissa seuraavasti: phantom syncd v3 — topo durmiente (”nukkuva myyrä”). Sen tehtävänä on varastaa kryptovaluuttalompakoiden materiaalia ja kehittäjien salaisuuksia ja lähettää ne pois koneelta. Se toimii seuraavasti:
- 1. Odota, kunnes kone on käyttämätön. Ennen kuin teet mitään, syncd.js tarkistaa, kuinka kauan käyttäjä on ollut passiivinen, ja jatkaa vain tietyn kynnyksen (noin 15 minuuttia) ylittämisen jälkeen — xprintidle Linuxissa ioreg HIDIdleTime macOS:ssä ja PowerShell-kysely tyhjäkäyntiaikana Windowsissa. Tietojen kerääminen tapahtuu siis yleensä silloin, kun kukaan ei ole näppäimistöllä.
- 2. Hae etäohjattava aktivointikytkinSkripti noutaa pienen konfiguraation tyhjästä hakemistosta ennen toimintaa. Ensisijainen lähde on GitHubin gist-raaka-URL (gist.githubusercontent.com/juang55/…/cfg.txt); skripti aktivoituu vain, jos kyseinen konfiguraatio lukee aktiivinen=1Jos ydinsisältöä ei ole saatavilla, käytetään kolmea kovakoodattua IPFS-sisältötunnistetta, jotka noudetaan julkisten yhdyskäytävien kautta. gateway.pinata.cloud, ipfs.ioja cloudflare-ipfs.comTämä antaa käyttäjälle jälkikäteen tapahtuvan virittämisen/riisunnan hallinnan ja alasviennin kestävän varamekanismin. (Pienin versio, toimitetaan krypto-validate-lib, eth-lompakko-apulaisetja solana-key-utils, josta on poistettu gist-kerros ja joka perustuu pelkästään IPFS-tunnisteisiin.)
- 3. Kerää lompakkomateriaalia ja salaisuuksia. Skripti kulkee käyttäjän kotihakemistossa — ~/.config/solana, ~/.ethereum/keystore, ~/.foundry, ~/.hardhat, ~ / .sshja pöytä-/asiakirjat/Lataukset (mukaan lukien espanjankieliset kansioiden nimet) sekä ~/.env ja shell rc -tiedostot ja vastaavat AppData sijainteja Windowsissa. Se kohdistuu Ethereumin yksityisiin avaimiin, Bitcoinin WIF-avaimiin, BIP-39-siemenlausekkeisiin, Solanan avainpareihin, Ethereumin avainsäilön JSON-muotoon, SSH-avaimiin ja salaisuuksia sisältäviin ympäristömuuttujiin. Suurempi variantti (sisältää abi-koodaus, base58-utils, eth-dev) sisältää täyden 2048 sanan BIP-39-sanakirjan ja käyttää säännöllisiä lausekkeita uute yksittäisiä avaimia ja validoituja siemenlausekkeita mistä tahansa lukemastaan tekstistä; kaksi pienempää muunnosta yhdistävät tiedostot avainsanan mukaan (siemenet, muistintuki, lompakko, metamask, aave, pääkirja, laatikko, …) ja lataa kokonaisia tiedostoja.
- 4. Salaa ja pura tiedot julkisen pinauspalvelun kautta. Jokainen löydös on yhdistetty isännän sormenjälkeen (käyttäjätunnus@isäntänimi, alusta, aikaleima) ja salattu skriptiin upotetulla kovakoodatulla RSA-4096-julkisella avaimella. Salattu tietue ladataan sitten kiinnittämällä se IPFS:ään kautta api.pinata.cloud/pinning/pinJSONToIPFS, todennettu kovakoodatuilla Pinata API -tunnistetiedoilla. Ei ole olemassa räätälöityä C2-palvelinta, jota takavarikoida: varastettu data on tallennettu julkiseen hajautettuun tallennustilaan, josta operaattori voi noutaa sen tuloksena olevien sisältöhajautusten avulla. Latausten välissä on muutaman sekunnin satunnainen jitter ja paikallinen loki aikaleima | avaintyyppi | palautettu hash-arvo pidetään osoitteessa ~/.cache-db/.node-sync/.sl.
- 5. Jatka ja anna signaalin 12 tunnin syklissä. Toinen vaihe palauttaa oman pysyvyytensä — cron-merkintä Linuxissa, a com.apple.syncd launchd-työ macOS:ssä ja ajoitettu tehtävä nimeltä WindowsNodeSync Windowsissa – asetettu suoritettavaksi uudelleen 12 tunnin välein. Huomaa, että tämä on eri Windows-tehtävän nimi siitä, jonka dropper asentaa (WinNodeSync); molemmat ovat metsästyksen arvoisia.
Aikajana
Kahdeksan pakettia julkaistiin tiukassa sarjassa 13.7.2026 ja 14.7.2026. Useissa on useampi kuin yksi versio; pipetti on identtinen eri versioissa, ja vain rivien siirtymät muuttuvat sen yläpuolella olevan hyvänlaatuisen hyödyllisyyskoodin koon muuttuessa.
| Päivämäärä | Tapahtuma |
|---|---|
| 2026-07-13 | Klusterin ensimmäiset paketit näkyvät yhden julkaisijan alla (solana-key-utils, eth-wallet-helpers, crypto-validate-lib ja muiden varhaiset versiot) |
| 2026-07-13 → 07-14 | Jäljellä olevat nimet ja jatkoversiot julkaistu; samat liitetyt tiputusalukset jokaisessa |
| 2026-07-14 | Kaikki kahdeksan merkitty ja analysoitu; jokainen paketti edelleen asennettavissa rekisteristä |
Purkauksen aikana julkaisijan rekisterin maine muuttui klusterin alun suunnilleen neutraalista vahvasti negatiiviseksi havaittujen pakettien kertyessä – tämä on havaittavissa oleva sivuvaikutus pakettien merkitsemisestä, ei suunniteltu ominaisuus.
Kompromissin indikaattorit
Kaikkien alla olevien indikaattoreiden – ”toisen vaiheen” taulukoissa olevien dekoodaamalla saatujen – esiintyminen varmistui analyysihetkellä. testi/kalusteet/avainpairs.dat ja lukemalla toipunutta syncd.js.
Tiedostot ja polut
| Osoitin | Rooli |
|---|---|
~/.cache-db/.node-sync/syncd.js | Dekoodattu toinen vaihe, kirjoitettu moodilla 0o700 |
~/.cache-db/.node-sync/.sl | Paikallinen tiedonkeruuloki (aikaleima | avaintyyppi | IPFS-hajautus) |
test/fixtures/keypairs.dat | Base64-koodattu hyötykuorma, joka on asetettu tarballin sisään "testauslaitteistoksi" |
Toisen vaiheen verkkoinfrastruktuuri (palautettu syncd.js-tiedostosta)
| Osoitin | Rooli |
|---|---|
gist.githubusercontent.com/juang55/b298754cb72942b1cdcf02ccd45cde2f/raw/cfg.txt | Aktivoinnin esto; skripti suoritetaan vain, jos konfiguraatio lukee active=1 |
Qmcqz3w8j4qFQXDAXAxnrdc2oSX3nzBT4NqtpTqL8mr1ga | IPFS-konfiguraation varajärjestelmä (CID) |
QmdTXoqVmTHY1i4ZWLdLkoQ9YChp5TXPh5cWXwnAYZt5iF | IPFS-konfiguraation varajärjestelmä (CID) |
QmfJkLU5gdCpqbbqEjWYC2anXW9FmuEeSLLeLiHVJKYUjp | IPFS-konfiguraation varajärjestelmä (CID) |
gateway.pinata.cloud, ipfs.io, cloudflare-ipfs.com | IPFS-yhdyskäytävät, joita käytetään määritysten noutamiseen varajärjestelmänä |
api.pinata.cloud/pinning/pinJSONToIPFS | Pakkolunastuksen päätepiste, varastettu data kiinnitetty julkiseen IPFS:ään |
| Pinata API -avain | 13c766575b9270a9825d, kovakoodatut ulosvirtaustunnistetiedot |
Toisen vaiheen keräyskohteet (palautettu syncd.js-tiedostosta)
| Osoitin | Rooli |
|---|---|
~/.config/solana, ~/.ethereum/keystore, ~/.foundry, ~/.hardhat, ~/.ssh, ~/.env, shell rc -tiedostot | Avainten ja salaisuuksien etsintä hakemistoissa/tiedostoissa |
AppData\Roaming\Solana, AppData\Local\ethereum\keystore | Windows-vastineet haettuina |
| Kerätyt artefaktityypit | ETH-yksityiset avaimet, Bitcoin WIF, BIP-39-siemenlausekkeet, Solana-avainparit, Ethereumin avainsäilö JSON, SSH-avaimet, salaiset ympäristömuuttujat |
Pysyvyysartefaktit
| foorumi | Osoitin |
|---|---|
| Linux | cron-merkinnän käynnistys syncd.js; asennettu crontabin kautta suodatettuna grep -v syncd |
| Windows | ajoitettu tehtävä WinNodeSync (pipetti) ja WindowsNodeSync (toinen vaihe) |
| macOS | launched-tarra com.apple.syncd |
| Kaikki | Toinen vaihe toistuu 12 tunnin sykleissä |
Behavioral
- Itseään kutsuva funktio liitetään perään moduuli.vienti, ajoitus a setTimeout noin 37 000 ms tuonnin yhteydessä.
- lapsiprosessi spawn("solmu", ) irrotetun lisäasetusjoukon kanssa.
- Tyhjäkäyntiohjattu aktivointi toisessa vaiheessa (xprintidle / ioreg HIDIdleTime / PowerShell-lepoaika; ~15 minuutin kynnysarvo).
- RSA-4096-salaus per-finding, sitten HTTPS POST julkiseen IPFS-pinning-APIin.
Paketit ja versiot (npm, julkaisija solbuilder_io)
| Paketti | versiot |
|---|---|
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 |
julkaisija
- solbuilder_io - angel_lopez89[@]proton[.]me, sähköpostiosoite vahvistamaton, ei vahvistettua versionhallintatiliä, ei linkitettyä tietovarastoa.
Attribuutio ja havaittu käyttäytyminen
Kahdeksalla paketilla on yhteinen yksi julkaisijan tili ja yksi hyötykuorma. Jokainen on triviaali paketti – muutaman kilotavun kokoinen oikeaa apuohjelmakoodia, johon on liitetty sama dropper – julkaistu ilman linkitettyä repositoriota ja vahvistamattoman kertakäyttöisen sähköpostiosoitteen alla. Tuo yhdenmukaisuus, jaettu drop-polku, jaetut pysyvyystunnisteet ja jaettu... avainpairs.dat valmistelutiedostot sitovat klusterin yhteen.
Paketit ovat epätavallisen rehellisiä omasta käytöksestään. solana-key-utils sisältää rivikommentteja, jotka kuvaavat liitettävää lohkoa selkokielellä — yksi niistä nimeää sen PHANTOM: näkymätön pysyvyys, toinen (espanjaksi) kuuluu Poista yläosa taustasta, ”aja myyrä taustalla.” Nämä ovat koodin omia merkintöjä siitä, mitä se tekee; tämän viestin kampanjan nimi on johdettu ensimmäisestä tunnisteesta yhdessä väärennetyn solmun ”sync daemon” kanssa (synkronoitu) jota pysyvyyskoneisto jäljittelee.
Kuvaamme vain sitä, mitä koodi havaittavasti tekee. Pakettien nimeäminen – kaikki krypto-, lompakko- ja lohkoketjutyökalutermit – osoittaa kehittäjäyleisön, joka todennäköisimmin hakee ne nimeltä; se ei itsessään määritä kuka julkaisija on. Toinen vaihe oli täysin palautettavissa dekoodaamalla base64-kiinnitys, ja sen toiminta on kuvattu edellä: se kerää lompakkoavaimia, siemenlausekkeita ja salaisuuksia ja suodattaa ne RSA-salattuina julkiseen IPFS-tallennustilaan Pinatan kautta. Merkittävä suunnitteluvalinta on yksityisen C2-palvelimen puuttuminen – kokoonpano saapuu GitHub-gistiltä ja IPFS:ltä, ja varastetut tiedot säilytetään julkisessa hajautetussa tallennustilassa, joka on avattu sisällön hajautuksella, joita molempia on vaikeampi takavarikoida kuin yhtä hyökkääjän hallitsemaa isäntää. Kirjoitushetkellä ei löytynyt aiempaa julkista raporttia, joka vastaisi tätä klusteria.
Vaikutus, trendit ja ohjeet puolustajille
Kuka on alttiina. Jokainen, joka on lisännyt jonkin näistä paketeista Node-projektiin ja sitten suorittanut koodia, joka tuo sen. Koska detonaatio tapahtuu tuonnin eikä asennuksen aikana, pelkkä paketin läsnäolo ei riitä – vaan mikä tahansa normaali käyttö, joka lataa moduulin, saavuttaa hyötykuorman. Houkuttavat nimet kohdistuvat kehittäjiin, jotka rakentavat Ethereumin, Solanan, Arbitrumin, Layer-2:n ja yleisten lompakko-/koodaustyökalujen varaan – väestöön, jolla todennäköisimmin on juuri ne resurssit, joita toinen vaihe metsästää. Jokainen, joka on suorittanut jonkin näistä moduuleista koneella, joka sisältää lompakkoavaimia, siemenlausekkeita, avainsäilöjä, SSH-avaimia tai... .env salaisuuksien tulisi käsitellä näitä tunnistetietoja vaarantuneina ja kierrättää niitä.
Kaksi sisäistämisen arvoista kaavaa. Ensimmäinen, hyötykuorma kiinnikkeenä: toisen vaiheen toimittaminen base64-muodossa uskottavasti nimetyssä datatiedostossa (testi/kalusteet/avainpairs.dat) pitää paketin näkyvän lähteen siistinä ja siirtää haitallisen sisällön tiedostoon, jota tarkistustyökalut ja ihmisten tekemät silmäykset usein käsittelevät inerttinä datana. Toiseksi, tuontiaikana viivästynyt suoritus ja eri alustojen välinen pysyvyysLiipaisimen siirtäminen pois asennusvaiheesta, ajastimen lisääminen ja sitten sen säilyttäminen cronissa, ajoitetuissa tehtävissä ja launchd:ssä on tarkoituksellinen askel poispäin meluisammista asennusskriptitekniikoista, joita automaattinen rekisterin tarkistus seuraa eniten.
Ohjeita puolustajille ja ylläpitäjille:
- Käsittele liitetyt koodit jälkeen moduuli.vienti tarkistusprioriteettina — dropper-logiikka piiloutuu usein "todellisen" moduulipinnan alle.
- Älä oleta datatiedostojen olevan inerttejä. Base64-blob alla testi/otteluohjelma/ joka luetaan ajonaikana ja dekoodataan, on suoritettavan tiedoston vieressä; merkitsee ajonaikaisia lukuja kiinnitystiedostoista, jotka syöttävät Toiminto/eval/write-then-kutea ketju.
- Metsästä pudotusreittiä ~/.cache-db/.node-sync/ ja pysyvyysyksiköille WinNodeSync (ajoitettu tehtävä) ja com.apple.syncd (launchd) kehittäjäkoneilla, jotka hakivat nämä nimet.
- Hälytys solmuprosesseista, jotka luovat cron-merkintöjä, ajoitettuja tehtäviä tai launchd-töitä — lailliset kirjastot tekevät tätä harvoin tuonnin yhteydessä.
- Suosi lukitustiedostoja ja kiinnitettyjä versioita ja tarkista mahdollisten uusien pienten "apuohjelmariippuvuuksien" erot, erityisesti nollariippuvaisia paketteja julkaistu vahvistamattomien tilien toimesta, joihin ei ole linkitettyä arkistoa.
Rekisterinpitäjien kannalta tärkeintä on, että asennusvaiheen valvonta on välttämätöntä, mutta ei riittävää: datatiedoston sisällä oleva tuonnin aikana tapahtuva, ajastimella viivästetty dropper läpäisee vain asennuksen aikana tapahtuvan tarkistuksen, ja pysyvyysvaihe on usein voimakkain jäljellä oleva havaittava signaali.



