TL; DR
Sekumpulan lima pakej npm, diterbitkan merentasi dua pemegang akaun, menghantar postinstall cangkuk yang membaca kelayakan awan daripada hos dan menghantarnya keluar dari kotak. Pakej-pakej tersebut membawa nama-nama hantu dan lanun — coral-wraith, ecto-corsair-whisper-6f3b9, ecto-corsair-flag-x9m4, ecto-rust-read-f3a9c1, ecto-nightly-spirit — dan menyusun semula apa sahaja yang mereka kumpulkan menjadi palsu ecto_module: Manifes YAML sebelum menghantarnya. Kami menjejaki kluster sebagai Ektoplasma.
Muatan hanya berjalan apabila ia mengesan persekitaran tertentu: hos yang namanya ialah Rentetan heksagon 12 aksara dan direktori kerja di bawah /app/node_modules — bentuk binaan kontena atau pekerja CI. Apabila pintu pagar itu lalu, cangkuk akan menanyakan Perkhidmatan metadata tika AWS (IMDSv2) untuk kelayakan peranan IAM, senaraikan Pengurus Rahsia AWS merentasi tiga wilayah, membuang pembolehubah persekitaran, membaca fail di bawah /app, dan mengikis tali tangkapan bendera. Ia kemudian mengeluarkan hasilnya dengan dua cara: suar ke a webhook.site pengumpul dan manifes PUT ke titik akhir IP mentah, dengan senarai sandaran localhost-first.
Huraian pakej kemudian berbunyi "Muatan CTF untuk ujian rantaian bekalan verdaccio." Kami melaporkan perihalan kendiri itu sebagai fakta yang boleh diperhatikan. Tingkah laku itu sendiri — keluar langsung ke IP awam, bacaan kelayakan IMDS sebenar, panggilan Pengurus Rahsia sebenar — adalah seperti yang ada tanpa mengira labelnya, dan merupakan sebab versi ini dikelaskan sebagai berniat jahat.
Satu nama dalam kelompok itu, coral-wraith, tidak berhenti pada satu keluaran pun. Ia diterbitkan semula secara berturut-turut melalui berpuluh-puluh versi dalam masa beberapa jam — 1.0.0 mendaki ke 6.0.0 — dan versi terdahulu dengan nama yang sama telah menggunakan inflated 9999.0.x nombor versi, bentuk klasik a percubaan kekeliruan kebergantungan. Merentasi itu, muatan yang kelihatan matang: daripada suar penghitungan hos sekali guna kepada pangsi kelayakan AWS penuh yang dibalut dengan pemeriksaan persekitaran yang memastikan ia senyap di luar sasaran yang dimaksudkan.
| Kami | 5 nama; coral-wraith sahaja diterbitkan semula merentasi berpuluh-puluh versi |
| Ekosistem | npm |
| Pasang vektor | postinstall skrip kitaran hayat |
| Sasaran utama | Kelayakan peranan AWS IAM + Nilai rahsia Pengurus Rahsia, pembolehubah persekitaran, /app fail |
| Exfil | webhook.site suar + mentah-IP C2 PUT |
| Pintu pencetus | Nama hos 12-heks + /app/node_modules cwd, serta pemeriksaan persekitaran yang menyekat muatan di luar konteks tersebut |
| Keterukan | tinggi — kelayakan awan dan pendedahan rahsia terurus daripada persekitaran binaan dan masa jalan berkontena |
Anatomi serangan
Setiap pakej dalam kluster dibina dengan cara yang sama: hampir kosong indeks.js (modul.eksport = {}), satu baris package.json skrip — “pascapasang”: “nod pascapasang.js” — dan muatan dalam postinstall.jsMemasang pakej sudah cukup untuk menjalankan hook; tiada import atau panggilan diperlukan.
Pintu sasaran. Sebelum melakukan apa-apa, muatan ecto-family memeriksa persekitarannya:
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 Nama hos 12-heks ialah bentuk lalai yang diberikan oleh Docker kepada bekas, dan /aplikasi/modul_nod ialah laluan pemasangan dalam bekas konvensional. Klausa ketiga akan tersingkir jika laluan tersebut kelihatan seperti direktori pengekstrakan kotak pasir. Kesan bersihnya ialah muatan kekal tidak aktif pada komputer riba pembangun atau kotak pasir analisis dan hanya diaktifkan di dalam pekerja binaan atau masa jalan berkontena — jenis persekitaran yang paling berkemungkinan membawa kelayakan awan langsung. Pakej terawal dalam kluster, hantu karang, tidak mempunyai pintu sedemikian dan menjalankan koleksi (yang lebih mudah) tanpa syarat.
koleksiApabila pintu pagar itu melaluinya, cangkuk itu akan terkeluar melaluinya penyegerakanfailpelaksana(“/bin/sh”, [“-c”, …]) dan menjalankan satu arahan majmuk tunggal yang, mengikut urutan:
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) Langkah 1–3 ialah pengambilan semula IMDSv2 buku teks: minta token sesi, kemudian lampirkannya sebagai Token-metadata-X-aws-ec2 pengepala untuk menarik peranan IAM tika dan kunci akses sementara peranan tersebut. Pilihan untuk melaksanakan IMDSv2 dan bukannya IMDSv1 yang tidak disahkan yang lebih ringkas GET perlu diberi perhatian — ini bermakna muatan berfungsi walaupun pada tika yang dikonfigurasikan untuk memerlukan akses metadata berasaskan token, iaitu pengerasan yang disyorkan oleh AWS. Kelayakan yang dikembalikan oleh langkah 3 adalah jangka pendek IDKeyAkses/KunciAksesRahsia/Token tiga kali ganda yang diliputi oleh peranan tika; apa sahaja yang boleh dilakukan oleh peranan itu, pemegang kunci tersebut boleh lakukan sepanjang hayat kelayakan.
Langkah 4–6 meluaskan jangkauan. env dump menangkap apa sahaja yang diwarisi oleh proses binaan atau masa jalan — dalam praktiknya, inilah tempat token pendaftaran, rentetan sambungan pangkalan data dan kunci API paling kerap berada. /aplikasi fail walk membaca sehingga lima belas fail aplikasi di luar simpul_modul, yang boleh membentuk konfigurasi permukaan, .env fail, atau sumber. Langkah 6 panggilan senarai rahsia pengurus rahsia aws dalam tiga wilayah; kelayakan yang ditarik dalam langkah 1–3 adalah tepat apa yang mengesahkan panggilan tersebut, jadi IMDS membaca dan rantaian penghitungan Pengurus Rahsia digabungkan menjadi satu peningkatan: peranan tika → inventori rahsia-terurus. Langkah 7 ialah anggukan kepada pembingkaian tangkap-bendera — apabila HTB{…} Jika bendera ditemui, ia akan dihantar sendiri, jika tidak, gumpalan mentah yang dikumpul akan dipotong menjadi empat bahagian dan dihantar.
Versi terkemudian dalam kluster membawa peningkatan selanjutnya. Daripada berhenti pada inventori, mereka menghuraikan respons IMDS, mengeksport kunci sementara sebagai AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN pembolehubah persekitaran, sahkan identiti dengan aws sts dapatkan identiti-pemanggil, dan kemudian ulangi setiap rahsia yang dikembalikan oleh senarai-rahsia memanggil pengurus rahsia aws dapatkan nilai rahsia pada setiap satu — mendapatkan semula kandungan rahsia, bukan hanya namanya. Versi yang sama juga membaca binari bendera yang digantikan proses (/bacabendera dan rakan-rakan) dan cuba a caj dijalankan terhadap mana-mana projek Rust yang ditemui di bawah /aplikasi, meluaskan hasil tuaian melangkaui kelayakan awan ke dalam apa sahaja yang didedahkan oleh persekitaran binaan.
Versi-versi yang lebih baharu ini juga mempunyai gate sendiri yang lebih agresif. Selain nama hos 12-heks dan /aplikasi/modul_nod Apabila semakan dijalankan, muatan akan memeriksa konfigurasi pendaftaran pakej aktif dan laluan direktori kerja serta keluar secara senyap apabila ia menunjukkan analisis atau konteks cermin dan bukannya sasaran langsung. Kesan gabungan ialah muatan yang tidak melakukan apa-apa yang boleh diperhatikan dalam kebanyakan persekitaran pemeriksaan dan menjalankan koleksi penuhnya hanya apabila ia menilai dirinya berada pada hos kontena yang tulen.
exfiltrationData yang dikumpul meninggalkan hos pada dua saluran. Pertama, suar SELEPAS kepada yang tetap webhook.site pengumpul, membawa nama hos, UID berangka, direktori kerja dan sehingga 120 KB data yang dikumpul. Kedua, data dilipat ke dalam "manifes modul" YAML palsu dan PUT kepada /api/modul/ pada pelayan sasaran:
ecto_module: name: "<flag-or-chunk-0>" version: "1.0.0" power_level: "<chunk-1>" ship_deck: "<chunk-2>" cargo_hold: "<chunk-3>" Nama medan manifes (tahap_kuasa, dek_kapal, kargo_pegangan) adalah hiasan — data yang dicuri berada di dalam nilai rentetan, itulah sebabnya monitor rangkaian melihat apa yang kelihatan seperti muat naik manifes pendaftaran pakej yang tidak berbahaya dan bukannya lambakan data yang jelas. Saluran suar membawa lebih banyak: SELEPAS badan ke webhook.site merangkumi nama hos, UID berangka, direktori kerja dan sehingga 120 KB gumpalan yang dikumpul, jadi satu suar yang berjaya pun memberikan gambaran penuh. webhook.site ialah perkhidmatan pemeriksaan permintaan percuma; menggunakannya sebagai pengumpul bermakna pengendali tidak perlu lagi menanggung infrastruktur penerima mereka sendiri untuk saluran tersebut dan permintaan yang direkodkan kekal dalam tong perkhidmatan.
Manifes PUT menjalankan senarai sandaran yang bermula dengan beberapa 127.0.0.1/localhost port dan kemudian jatuh ke tiga alamat awam dalam `154.57.164.0/24` julat, berhenti pada titik akhir pertama yang menjawab dengan status 2xx. Penyusunan localhost-first adalah konsisten dengan perihalan kendiri "verdaccio testing" (daftar setempat pada loopback), tetapi fallback IP awam bermakna data meninggalkan hos apabila loopback tidak mendengar — iaitu, pada mana-mana mesin yang bukan rig ujian pengarang sendiri.
Timeline
Kluster menunjukkan pertumbuhan keupayaan tambahan dan bukannya penurunan tunggal. Kami menyusunnya mengikut tingkah laku yang diperhatikan, bukan mengikut jam dinding yang diterbitkan:
| Masa latihan | Pakej / Versi | Kelakuan |
|---|---|---|
| Larian awal | coral-wraith 9999.0.x | Nombor versi yang dibesarkan selaras dengan percubaan kekeliruan kebergantungan; penghitungan masa pemasangan dan exfil |
| Benih | coral-wraith 1.0.0 | pasca pemasangan mengumpul fail id/env/flag; PUT tunggal ke 154[.]57[.]164[.]71:30782, penanda ECT-472839 |
| Lelaran pantas | coral-wraith 1.0.1 → 6.0.0 | Berpuluh-puluh pelepasan dalam beberapa jam; muatan mendapat isAppWorker() pintu pagar, tarik kelayakan IMDSv2, penuh get-secret-value pivot, semakan persekitaran pendaftaran/laluan dan penanda sinki berganda |
| Nama-nama selari | ecto-corsair-whisper-6f3b9 1.0.14–1.0.18 | Muatan berpagar yang sama; webhook.site senarai sandaran suar dan berbilang titik akhir |
| Versi kelainan | ecto-rust-read-f3a9c1 1.0.1–1.0.2 | Menambah penanda sinki tambahan ECT-987654, ECT-654321, ECT-839201 |
| Versi kelainan | ecto-corsair-flag-x9m4 1.0.0, ecto-nightly-spirit 1.1.0 | Muatan berpagar yang sama, C2 dan suar yang sama |
Ciri yang menentukan kluster ini ialah irama penerbitannya: bukannya satu pakej dan satu versi, nama yang sama diterbitkan semula berulang kali secara berturut-turut, setiap satu mengeluarkan variasi kecil pada yang terakhir, di samping segelintir adik-beradik yang berbeza nama yang membawa muatan yang sama. Dalam bisikan keluarga kod tersebut dibahagikan kepada dua cap jari rapat — satu set yang menjerumuskan dua pengesanan kritikal, tiga lagi (singki baca fail tambahan) — tetapi kedua-duanya menyelesaikan kepada muatan yang sama; perbezaannya ialah hanyutan kod, bukan cabang tingkah laku. Versi bisikan di luar julat yang dianalisis (sehingga sekurang-kurangnya 1.0.25 pada masa penulisan) diperhatikan secara langsung pada daftar, dan hantu karang nama itu terus mendaki tangga versinya sendiri di tetingkap yang sama.
Petunjuk kompromi
Semua penunjuk di bawah telah diekstrak daripada sumber pakej pada cakera. Penunjuk rangkaian telah dinyahfang.
rangkaian
| Petunjuk | Peranan |
|---|---|
hxxp://154[.]57[.]164[.]71:30782 | Sasaran C2 PUT (coral-wraith) |
hxxp://154[.]57[.]164[.]80:30543 | C2 PUT sandaran (ecto-*) |
hxxp://154[.]57[.]164[.]82:31250 | C2 PUT sandaran (ecto-*) |
hxxp://154[.]57[.]164[.]71:31289 | C2 PUT sandaran (ecto-*) |
hxxps://webhook[.]site/602a4c72-7033-4e28-92ea-dc66e59206e5 | Pengumpul suar |
169[.]254[.]169[.]254/latest/... | Bacaan kelayakan IMDSv2 (bahagian sasaran, metadata AWS) |
Fail/tingkah laku
| Petunjuk | Peranan |
|---|---|
"postinstall": "node postinstall.js" | Pasang vektor |
ecto_module: YAML dengan power_level / ship_deck / cargo_hold kunci | Skema manifes Exfil |
Penanda sinki ECT-472839, ECT-987654, ECT-654321, ECT-839201 | Segmen laluan C2 /api/modules/<marker> |
isAppWorker() pintu gerbang: tuan rumah /^[0-9a-f]{12}$/, cwd mengandungi /app/node_modules | Keadaan pengaktifan |
aws secretsmanager list-secrets lebih us-east-1, eu-west-1, eu-central-1 | Penghitungan rahsia |
HTB{...} mengikis regex | Hasil tangkapan bendera |
Hash fail (sha256, ditangkap pada masa analisis)
| File | sha256 |
|---|---|
coral-wraith/postinstall.js | ce5ff035cfdfed1d0015446424b352c27b66bcb77e9fdb0a51e4245199146824 |
ecto-corsair-whisper-6f3b9 1.0.18/postinstall.js | b58432acba376aa6976f0490d9a1c04257ccdbc856d8390260c50322d63e31c3 |
Atribusi & tingkah laku yang diperhatikan
Lima nama pakej diterbitkan di bawah dua pemegang akaun npm, tetapi ia berkongsi infrastruktur yang mencukupi untuk melayannya sebagai satu kluster: sama modul_ecto skema manifes, sama ECT-472839 penanda sinki utama, sama webhook.site ID pengumpul, dan titik akhir C2 dalam keadaan yang sama Blok 154.57.164.0/24`. Pakej benih (`coral-wraith, lebih ringkas dan tidak berpagar) dan keluarga ekto berpagar itu dibaca sebagai lelaran pada satu toolkit dan bukannya usaha bebas.
Pakej-pakej tersebut menggambarkan diri mereka, dalam versi yang lebih baharu, sebagai "Muatan CTF untuk ujian rantaian bekalan verdaccio." Kami mengemukakan label tersebut sebagai fakta yang boleh diperhatikan dan tidak menyatakannya semula sebagai penemuan tentang tujuan. Apa yang dilakukan oleh kod tersebut adalah jelas dan bebas daripada cara ia dilabelkan: ia membaca kelayakan peranan IAM daripada perkhidmatan metadata tika, menyenaraikan rahsia terurus merentasi tiga wilayah AWS dan menghantar hasilnya kepada IP awam dan pengumpul webhook pihak ketiga. Abah-abah ujian gelung balik yang benar-benar tidak memerlukan senarai sandaran IP awam, bacaan kelayakan IMDS atau panggilan Pengurus Rahsia merentas wilayah. Oleh kerana capaian keluar dan kelayakan adalah nyata, versi berpagar dikelaskan sebagai berniat jahat.
Gerbang kontena sahaja merupakan ciri yang paling ketara dari segi operasi. Ia merupakan langkah pengelakan — kekal senyap pada komputer riba dan dalam kotak pasir analisis — dan langkah penyasaran, hanya diaktifkan di tempat peranan IAM sebenar dan rahsia langsung berkemungkinan besar hadir. Penganalisis yang menjalankan pakej ini dalam kotak pasir generik tidak akan memerhatikan apa-apa; tingkah laku hanya ditunjukkan di bawah nama hos gaya Docker dan laluan pemasangan dalam kontena.
Impak, trend & panduan untuk pembela
Pendedahan di sini adalah kelayakan awan dan pendedahan rahsia di dalam bekas binaan dan masa jalan. Kelayakan peranan IAM yang diambil daripada IMDS membawa apa sahaja kebenaran yang dipegang oleh peranan tersebut; pengurus rahsia: SenaraiRahsia (dan sebarang susulan DapatkanNilaiRahsia) meluaskannya kepada rahsia aplikasi yang disimpan. Lambakan pembolehubah persekitaran kerap membawa token pendaftaran, URL pangkalan data dan kunci API. Dalam konteks CI atau kontena — tepat seperti yang dipilih oleh get — satu pemasangan transitif bagi salah satu pakej ini sudah cukup untuk membocorkan bahan tersebut.
Ectoplasm sesuai dengan corak yang terus kita lihat: muatan masa pemasangan yang mencapai metadata awan dan rahsia terurus dan bukannya fail setempat, dan yang mengunci diri mereka untuk menembak hanya dalam persekitaran bernilai tinggi. Dua pemerhatian pertahanan menyusul.
- Bentuknya dapat dikesanCangkuk pemasangan npm/PyPI yang graf panggilannya mencapai kedua-dua API rahsia awan (pengurus rahsia aws, rahsia gcloud, az keyvault) atau alamat IMDS dan sinki keluar rangkaian ialah corak isyarat tinggi yang sempit — ia hampir tidak pernah berlaku dalam skrip kitaran hayat yang sah. Analisis aliran statik boleh menandakannya tanpa bergantung pada mana-mana domain atau IP tertentu.
- Pengerasan alam sekitar menumpulkannya. Menguatkuasakan IMDSv2 dengan had hop 1 menghalang beban kerja kontena daripada mencapai metadata tika; menskop peranan IAM kepada keistimewaan paling minimum mengehadkan jejari letupan bagi sebarang kelayakan yang bocor; dan menjalankan pemasangan dengan - Abaikan skrip dalam CI mengalih keluar vektor install-hook sepenuhnya untuk pakej yang tidak memerlukannya.
Bagi pembela, pemeriksaan praktikal adalah: amaran tentang sambungan keluar dari bekas binaan/CI ke IP awam yang tidak disenarai dibenarkan semasa npm memasang; perhatikan akses IMDS yang berasal daripada skrip kitaran hayat pakej; dan anggap sebarang hook pemasangan yang menggunakan CLI awan sebagai suspek sehingga terbukti sebaliknya.
Dua nota lanjut khusus untuk kluster ini. Pertama, kerana pengaktifan dikawal selia kepada persekitaran kontena, pakej yang kelihatan lengai apabila ditapis pada stesen kerja masih boleh disiarkan secara langsung dalam pengeluaran — penapisan perlu menghasilkan semula nama hos kontena dan keadaan laluan, atau membaca sumber secara langsung, dan bukannya bergantung pada "Saya memasangnya dan tiada apa yang berlaku." Kedua, penggunaan perkhidmatan pemeriksaan permintaan awam sebagai pengumpul suar bermakna sebahagian daripada data yang diekstrak mungkin boleh dipulihkan untuk tindak balas insiden: organisasi yang menemui salah satu pakej ini dalam pokok kebergantungannya boleh membuat pertimbangan tentang apa yang akan terkandung dalam suar yang berjaya daripada logik pengumpulan muatan dan harus memutarkan sebarang kelayakan peranan IAM, token pendaftaran dan rahsia terurus yang boleh dicapai daripada persekitaran binaan atau masa jalan yang terjejas. Penggiliran kelayakan, bukan penyingkiran pakej, ialah pemulihan operasi sebaik sahaja pemasangan dijalankan.





