TL; DR
Areto de kvin npm-pakaĵoj, publikigita tra du kontoteniloj, sendis postinstall hoko kiu legas nubajn akreditaĵojn de la gastiganto kaj sendas ilin ekster la skatolo. La pakaĵoj portas nomojn de fantomoj kaj piratoj — coral-wraith, ecto-corsair-whisper-6f3b9, ecto-corsair-flag-x9m4, ecto-rust-read-f3a9c1, ecto-nightly-spirit — kaj seriigas ĉion, kion ili kolektas, en falsaĵon ecto_module: YAML-manifesto antaŭ ol sendi ĝin. Ni spuras la areton kiel Ektoplasmo.
La utila ŝarĝo nur funkcias kiam ĝi detektas specifan medion: gastiganton kies nomo estas 12-karaktera deksesuma ĉeno kaj labora dosierujo sub /app/node_modules — la formo de kontenerigita konstruo aŭ CI-laboristo. Kiam tiu pordego pasas, la hoko pridemandas la AWS-instanca metadatena servo (IMDSv2) por IAM-rolaj akreditaĵoj, listigas AWS Secrets Manager tra tri regionoj, forigas ĉirkaŭajn variablojn, legas dosierojn sub /app, kaj skrapas por kapto-la-flago-ĉenoj. Ĝi tiam elfiltras la rezulton du manierojn: signostango al webhook.site kolektanto kaj manifesto PUT al kruda-IP-finpunkto, kun listo de localhost-first rezervaj aliroj.
La pli postaj pakaĵpriskriboj legas "CTF-utila ŝarĝo por verdaccio-provizoĉena testado." Ni raportas tiun mempriskribon kiel observeblan fakton. La konduto mem — viva eliro al publika IP-adreso, realaj IMDS-akreditaĵlegadoj, realaj Secrets Manager-vokoj — estas kia ĝi estas sendepende de la etikedo, kaj estas la kialo, kial ĉi tiuj versioj estis klasifikitaj malicaj.
Unu nomo en la aro, coral-wraith, ne haltis ĉe ununura eldono. Ĝi reeldonis rapide tra dekoj da versioj en nur kelkaj horoj — 1.0.0 grimpante al 6.0.0 — kaj pli frua kuro de la sama nomo uzis ŝveligitajn 9999.0.x versinumeroj, la klasika formo de dependec-konfuza provoTrans tiu ŝanĝiĝemo la utila ŝarĝo videble maturiĝis: de unufoja gastiganto-listiga signostango al plena AWS-akreditaĵa pivoto envolvita en mediaj kontroloj kiuj tenas ĝin kvieta ekster sia celita celo.
| pakaĵoj | 5 nomoj; coral-wraith sole reeldonita trans dekduoj da versioj |
| Ekosistemo | npm |
| Instali vektoron | postinstall vivcikla skripto |
| Primara celo | AWS IAM rolaj akreditaĵoj + sekretaj valoroj de Secrets Manager, mediaj variabloj, /app dosierojn |
| Eksfil | webhook.site signostango + kruda-IP C2 PUT |
| Ellasilpordego | 12-heksamena gastiga nomo + /app/node_modules cwd, plus media kontrolo kiu subpremas la utilan ŝarĝon ekster tiu kunteksto |
| Severity | alta — nuba akreditaĵo kaj malkaŝo de administrita sekreta de kontenerigitaj konstruaj kaj rultempaj medioj |
Atako-anatomio
Ĉiu pakaĵo en la areto estas konstruita sammaniere: preskaŭ malplena indekso.js (modulo.eksportoj = {}), unulinia pako.json manuskripto — “postinstalo”: “nodo postinstalo.js” — kaj la utila ŝarĝo en postinstall.jsInstali la pakaĵon sufiĉas por ruli la hokon; neniu importado aŭ alvoko estas necesaj.
La cela pordego. Antaŭ ol fari ion ajn, la ekto-familia utila ŝarĝo kontrolas sian ĉirkaŭaĵon:
function isAppWorker(): host = os.hostname() if host does NOT match /^[0-9a-f]{12}$/ -> exit if cwd does NOT contain "/app/node_modules" -> exit if cwd contains "/tmp/npm-safe" -> exit otherwise -> proceed 12-heksamena gastiga nomo estas la defaŭlta formo, kiun Docker asignas al ujo, kaj /aplikaĵo/nodo_moduloj estas konvencia en-kontenera instala vojo. La tria paragrafo foriras se la vojo aspektas kiel sablokestigita eltira dosierujo. La neta efiko estas, ke la utila ŝarĝo restas dormanta sur programista tekokomputilo aŭ analiza sablokestejo kaj nur aktiviĝas ene de kontenerigita konstrua aŭ rultempa laboristo — la speco de medio plej verŝajne portas vivajn nubajn akreditaĵojn. La plej frua pakaĵo en la areto, korala-fantomo, ne havas tian pordegon kaj funkciigas sian (pli simplan) kolekton senkondiĉe.
kolektoKiam la pordego pasas, la hoko elŝeliĝas tra execFileSync("/bin/sh", ["-c", ...]) kaj ruligas unuopan kunmetitan komandon kiu, laŭorde:
1. PUT /latest/api/token to 169.254.169.254 (IMDSv2 token request) 2. GET .../iam/security-credentials/ (IAM role name) 3. GET .../iam/security-credentials/<role> (temporary credentials) 4. dump env | sort (environment variables) 5. list /app (excl. node_modules) + cat first 15 (application files) 6. aws secretsmanager list-secrets (us-east-1, eu-west-1, eu-central-1) 7. scrape readable files for HTB{...} (capture-the-flag strings) Paŝoj 1–3 estas lernolibra IMDSv2-rehavigo: petu seancan ĵetonon, poste alkroĉu ĝin kiel la X-aws-ec2-metadatumoj-ĵetono kaplinio por tiri la IAM-rolon de la instanco kaj la provizorajn alirŝlosilojn de tiu rolo. La elekto efektivigi IMDSv2 anstataŭ la pli simpla neaŭtentigita IMDSv1 GET indas rimarki — ĝi signifas, ke la utila ŝarĝo funkcias eĉ ĉe instancoj agorditaj por postuli ĵeton-bazitan metadaten-aliron, kio estas la AWS-rekomendita plifortigo. La akreditaĵoj redonitaj de paŝo 3 estas mallongdaŭraj AlirŝlosilaIdentigilo/SekretaAlirŝlosilo/ĵetono triopoj limigitaj al la rolo de la instanco; kion ajn tiu rolo povas fari, la posedanto de tiuj ŝlosiloj povas fari dum la vivdaŭro de la akreditaĵo.
Paŝoj 4–6 plilarĝigas la prenadon. La env dump kaptas ĉion, kion la konstrua aŭ rultempa procezo heredis — praktike ĉi tie plej ofte troviĝas registro-ĵetonoj, datumbazaj konekto-ĉenoj kaj API-ŝlosiloj. La /aplikaĵo dosierpromenado legas ĝis dek kvin aplikaĵajn dosierojn ekstere nodo_moduloj, kiu povas surfacigi konfiguracion, .env dosieroj, aŭ fonto. Paŝo 6 alvokoj aws secretsmanager listo-sekretoj en tri regionoj; la akreditaĵoj prenitaj en paŝoj 1–3 estas ĝuste tio, kio aŭtentigas tiujn vokojn, do la IMDS-legado kaj la listigo de Secrets Manager estas kunigitaj en unu solan eskaladon: instanca rolo → administrita-sekreta inventaro. Paŝo 7 estas kapjeso al la kapto-de-la-flago-kadrigo — kiam HTB{…} flago estas trovita, ĝi estas sendita memstare, alie la kruda kolektita blob estas dividita en kvar pecojn kaj sendita.
Pli postaj versioj en la areto portas la eskaladon pluen. Anstataŭ halti ĉe inventaro, ili analizas la IMDS-respondon, eksportas la provizorajn ŝlosilojn kiel AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN mediaj variabloj, konfirmu la identecon per aws sts akiri-alvokanto-identecon, kaj poste ripetas ĉiun sekreton resenditan de listo-sekretoj vokante aws secretsmanager akiri-sekret-valoron sur ĉiu — prenante la sekretan enhavon, ne nur iliajn nomojn. La samaj versioj ankaŭ legas procez-anstataŭigitajn flagajn duumaĵojn (/leguflagon kaj amikoj) kaj provi kargoveturo kontraŭ iu ajn Rust-projekto trovita sub /aplikaĵo, plilarĝigante la rikolton preter nubaj akreditaĵoj en kion ajn la konstrua medio eksponas.
Ĉi tiuj pli postaj versioj ankaŭ pli agreseme enigas sin. Aldone al la 12-heksamena-gastigantonomo kaj /aplikaĵo/nodo_moduloj ĉekojn, la utila ŝarĝo inspektas la aktivan pakaĵ-registro-agordon kaj la labor-dosierujan vojon kaj eliras silente kiam ili indikas analizan aŭ spegulan kuntekston anstataŭ vivan celon. La kombinita efiko estas utila ŝarĝo kiu faras nenion observeblan en plej multaj inspektaj medioj kaj funkciigas sian plenan kolekton nur kie ĝi juĝas sin esti sur aŭtentika kontenerigita gastiganto.
EksfiltradoLa kolektitaj datumoj forlasas la gastiganton per du kanaloj. Unue, lumturo POST al fiksa rethoko.ejo kolektanto, portante la gastigantnomon, numeran UID-on, laboran dosierujon, kaj ĝis 120 KB da kolektitaj datumoj. Due, la datumoj estas falditaj en falsan YAML-"modulan manifeston" kaj metu al /api/moduloj/ sur cela servilo:
ecto_module: name: "<flag-or-chunk-0>" version: "1.0.0" power_level: "<chunk-1>" ship_deck: "<chunk-2>" cargo_hold: "<chunk-3>" La nomoj de la manifestkampoj (potenco_nivelo, ŝipferdeko, kargo-haltejo) estas ornamaĵoj — la ŝtelitaj datumoj rajdas ene de la ĉenvaloroj, tial retmonitoro vidas tion, kio aspektas kiel bonkora alŝuto de la manifesto de pakaĵregistro anstataŭ evidenta datenrubo. La signala kanalo portas pli: la POST korpo al rethoko.ejo inkluzivas la gastigantnomon, numeran UID-on, laboradresujon, kaj ĝis 120 KB de la kolektita blob, do eĉ ununura sukcesa lumturo liveras la plenan informon. rethoko.ejo estas senpaga servo por inspektado de petoj; uzi ĝin kiel kolektilon signifas, ke la funkciigisto neniam devas starigi propran ricevan infrastrukturon por tiu kanalo, kaj la registritaj petoj restas en la ujo de la servo.
La manifesto metu iras laŭ rezerva listo kiu komenciĝas per pluraj 127.0.0.1/localhost pordoj kaj poste falas tra tri publikaj adresoj en la `154.57.164.0/24` intervalo, haltante ĉe la unua finpunkto kiu respondas kun 2xx stato. La ordigo "localhost-first" kongruas kun la mem-priskribo "verdaccio testing" (loka registro sur buklo), sed la rezervaj publik-IP signifas, ke la datumoj forlasas la gastiganton kiam ajn buklo ne aŭskultas — tio estas, sur iu ajn maŝino kiu ne estas la propra testplatformo de la aŭtoro.
templinio
La areto montras pliigan kreskon de kapabloj anstataŭ unuopan falon. Ni ordigas ĝin laŭ observita konduto, ne laŭ publikiga horloĝo:
| scenejo | Pakaĵoj / Versioj | Kutimaro |
|---|---|---|
| Frua kuro | coral-wraith 9999.0.x | Ŝvelintaj versinumeroj kongruaj kun provo de dependeckonfuzo; listigo dum instalo kaj forigo |
| Semo | coral-wraith 1.0.0 | postinstalo kolektas id/env/flag-dosierojn; unuopa PUT al 154[.]57[.]164[.]71:30782, markilo ECT-472839 |
| Rapida ripetado | coral-wraith 1.0.1 → 6.0.0 | Dekoj da eldonoj en horoj; utila ŝarĝo akiras la isAppWorker() pordego, IMDSv2-akreditaĵa tiro, la plena get-secret-value pivoto, la registro/pada mediokontrolo, kaj duoblaj lavujmarkiloj |
| Paralelaj nomoj | ecto-corsair-whisper-6f3b9 1.0.14–1.0.18 | Sama enirkontrolita utila ŝarĝo; webhook.site lumturo kaj plurfinpunkta rezerva listo |
| variantoj | ecto-rust-read-f3a9c1 1.0.1–1.0.2 | Aldonas ekstrajn lavujajn markilojn ECT-987654, ECT-654321, ECT-839201 |
| variantoj | ecto-corsair-flag-x9m4 1.0.0, ecto-nightly-spirit 1.1.0 | Sama enirkontrolita utila ŝarĝo, sama C2 kaj signostango |
La difina trajto de la areto estas ĝia publikiga ritmo: anstataŭ unu pakaĵo kaj unu versio, la sama nomo estas reeldonita denove kaj denove en rapida sinsekvo, ĉiu eldono estas malgranda variaĵo de la antaŭa, kune kun manpleno da malsame nomitaj gefratoj portantaj la saman utilan ŝarĝon. Ene de la flustras familio la kodo dividiĝas en du proksimajn fingrospurojn — unu aro ekfunkciigas du kritikajn detektojn, alia tri (plia dosierlega lavujo) — sed ambaŭ solviĝas al la sama utila ŝarĝo; la diferenco estas koddrivo, ne konduta forko. Versioj de flustras preter la analizita intervalo (ĝis almenaŭ 1.0.25 dum la verkado) estis observitaj rekte en la registro, kaj la korala-fantomo nomo daŭre grimpis sian propran version-ŝtuparon super la sama fenestro.
Indikiloj de kompromiso
Ĉiuj indikiloj sube estis ĉerpitaj el la pakaĵa fontkodo sur disko. Retaj indikiloj estas malŝaltitaj.
reto
| indikilo | rolon |
|---|---|
hxxp://154[.]57[.]164[.]71:30782 | C2 PUT-celo (coral-wraith) |
hxxp://154[.]57[.]164[.]80:30543 | C2 PUT rezerva (ecto-*) |
hxxp://154[.]57[.]164[.]82:31250 | C2 PUT rezerva (ecto-*) |
hxxp://154[.]57[.]164[.]71:31289 | C2 PUT rezerva (ecto-*) |
hxxps://webhook[.]site/602a4c72-7033-4e28-92ea-dc66e59206e5 | Signostangkolektanto |
169[.]254[.]169[.]254/latest/... | IMDSv2-akreditaĵo legita (cela flanko, AWS-metadatenoj) |
Kondutisma/dosiero
| indikilo | rolon |
|---|---|
"postinstall": "node postinstall.js" | Instali vektoron |
ecto_module: YAML kun power_level / ship_deck / cargo_hold klavoj | Exfil-manifesta skemo |
Lavujmarkiloj ECT-472839, ECT-987654, ECT-654321, ECT-839201 | C2-vojsegmento /api/modules/<marker> |
isAppWorker() pordego: gastiganto /^[0-9a-f]{12}$/, cwd enhavas /app/node_modules | Aktiviga kondiĉo |
aws secretsmanager list-secrets super us-east-1, eu-west-1, eu-central-1 | Sekreta listigo |
HTB{...} skrapado de regula esprimo | Kaptu-la-flagan rikolton |
Dosieraj haŝoj (sha256, kaptitaj dum analizo)
| dosiero | sha256 |
|---|---|
coral-wraith/postinstall.js | ce5ff035cfdfed1d0015446424b352c27b66bcb77e9fdb0a51e4245199146824 |
ecto-corsair-whisper-6f3b9 1.0.18/postinstall.js | b58432acba376aa6976f0490d9a1c04257ccdbc856d8390260c50322d63e31c3 |
Atribuo kaj observita konduto
La kvin pakaĵnomoj estis publikigitaj sub du npm-kontaj teniloj, sed ili dividas sufiĉan infrastrukturon por trakti ilin kiel unu areton: la sama ekto_modulo manifesta skemo, la sama ECT-472839 ĉefa lavujmarkilo, la sama rethoko.ejo kolektanta ID, kaj C2-finpunktoj en la sama 154.57.164.0/24` bloko. La sempakaĵo (`koralo-fantomo`, pli simpla kaj senporda) kaj la senporda ekto-familio tiel legiĝas kiel ripetoj sur unu ilaro prefere ol sendependaj klopodoj.
La pakaĵoj priskribas sin, en pli postaj versioj, kiel "CTF-utila ŝarĝo por testado de la provizoĉeno de verdaccio." Ni prezentas tiun etikedon kiel observeblan fakton kaj ne ripetas ĝin kiel trovon pri celo. Kion la kodo faras estas neambigua kaj sendependa de kiel ĝi estas etikedita: ĝi legas IAM-rolajn akreditaĵojn de la instanca metadatena servo, listigas administritajn sekretojn tra tri AWS-regionoj, kaj transsendas la rezultojn al publika IP-adreso kaj triaparta rethoko-kolektilo. Vere nur-buklo-testa ilaro ne bezonus la rezervan liston de publikaj IP-adresoj, la IMDS-akreditaĵojn, aŭ la transregionajn vokojn de Secrets Manager. Ĉar la eliro kaj akreditaĵa atingo estas realaj, la baritaj versioj estis klasifikitaj kiel malicaj.
La pordego nur-en-kontenero estas la plej funkcie rimarkinda trajto. Ĝi estas kaj evitrimedo — resti silenta sur tekokomputiloj kaj en analizaj sablokestoj — kaj cela rimedo, pafante nur kie vera IAM-rolo kaj vivaj sekretoj plej verŝajne ĉeestas. Analizistoj funkciigantaj ĉi tiujn pakaĵojn en ĝenerala sablokesto observus nenion; la konduto nur manifestiĝas sub Docker-stila gastnomo kaj en-kontenera instala vojo.
Efiko, tendencoj kaj gvidlinioj por defendantoj
La malkaŝo ĉi tie estas nuba-akreditaĵo kaj sekreta malkaŝo ene de konstruaj kaj rultempaj ujoj. IAM-rolakreditaĵo prenita de IMDS portas kiajn ajn permesojn, kiujn tiu rolo havas; sekretestroj:ListoSekretoj (kaj ajna sekvaĵo AkiriSekretan Valoron) plilarĝigas tion al konservitaj aplikaĵaj sekretoj. Mediaj variablo-dumpiloj ofte portas registro-ĵetonojn, datumbazajn URL-ojn kaj API-ŝlosilojn. En CI- aŭ kontenera kunteksto — ĝuste tio, kion la pordego elektas — ununura transitiva instalado de unu el ĉi tiuj pakaĵoj sufiĉas por liki tiun materialon.
Ektoplasmo konformas al ŝablono, kiun ni daŭre vidas: instaltempaj ŝarĝoj, kiuj atingas nubajn metadatenojn kaj administritajn sekretojn anstataŭ lokajn dosierojn, kaj kiuj sin mem funkciigas nur en altvaloraj medioj. Sekvas du defensivaj observoj.
- La formo estas detektebla. Instala hoko por npm/PyPI, kies alvoka grafeo atingas ambaŭ Cloud Secrets API-on (aws sekreta manaĝero, gcloud-sekretoj, az ŝlosiltrezorejo) aŭ la IMDS-adreso kaj ret-elira sinko estas mallarĝa, alt-signala padrono — ĝi preskaŭ neniam okazas en legitima vivcikla skripto. Statika fluoanalizo povas marki ĝin sen dependi de iu ajn specifa domajno aŭ IP-adreso.
- Medio malmoliĝante malakrigas ĝin. Devigi IMDSv2 kun saltlimo de 1 malhelpas kontenerajn laborŝarĝojn atingi instancajn metadatenojn; difini IAM-rolojn al malplej privilegio limigas la eksplodradiuson de iu ajn akreditaĵo, kiu likas; kaj funkciigi instaladojn kun –ignori-skriptojn en CI tute forigas la vektoron install-hook por pakaĵoj, kiuj ne bezonas ĝin.
Por defendantoj, la praktikaj kontroloj estas: alarmo pri elirantaj konektoj de konstruaj/CI-ujoj al ne-permesitaj publikaj IP-adresoj dum npaga instali; atentu pri IMDS-aliro originanta de pakaĵaj vivciklaj skriptoj; kaj traktu ajnan instalan hokon, kiu sendas sin al nuba CLI, kiel suspektindan ĝis pruvite alie.
Du pliaj notoj specifaj por ĉi tiu areto. Unue, ĉar aktivigo estas limigita al kontenerigitaj medioj, pakaĵo kiu aspektas inerta kiam kontrolita sur laborstacio povas ankoraŭ esti aktiva en produktado — kontrolita sistemo bezonas reprodukti la gastigantnomon kaj padkondiĉojn de la kontenero, aŭ legi la fontkodon rekte, anstataŭ fidi je "Mi instalis ĝin kaj nenio okazis." Due, la uzo de publika peto-inspekta servo kiel signostango-kolektilo signifas, ke iuj el la elfiltritaj datumoj povas esti reakireblaj por respondo al okazaĵoj: organizo kiu trovas unu el ĉi tiuj pakaĵoj en sia dependecarbo povas rezoni pri kion sukcesa signostango enhavus el la kolekta logiko de la utila ŝarĝo, kaj devus rotacii iujn ajn IAM-rolakreditaĵojn, registrajn ĵetonojn kaj administritajn sekretojn, kiuj estis atingeblaj el la trafita konstrua aŭ rultempa medio. Akreditaĵa rotacio, ne pakaĵforigo, estas la funkcianta riparo post kiam instalado funkciis.





