TL, д-р
Кластар пяць npm-пакетаў, апублікаваны праз два нікнеймы акаўнтаў, адпраўлены postinstall перахопнік, які зчытвае воблачныя ўліковыя дадзеныя з хоста і адпраўляе іх з скрынкі. Пакеты маюць фіктыўныя імёны — coral-wraith, ecto-corsair-whisper-6f3b9, ecto-corsair-flag-x9m4, ecto-rust-read-f3a9c1, ecto-nightly-spirit — і серыялізуюць усё, што яны збіраюць, у падробку ecto_module: маніфест YAML перад яго перадачай. Мы адсочваем кластар наступным чынам Эктаплазма.
Карысная нагрузка запускаецца толькі тады, калі выяўляе пэўнае асяроддзе: хост, імя якога 12-сімвальны шаснаццатковы радок і рабочы каталог пад /app/node_modules — форма кантэйнернай зборкі або CI-воркера. Калі гэты вароты праходзяць, перахопнік запытвае Служба метададзеных экзэмпляраў AWS (IMDSv2) для ўліковых дадзеных ролі IAM пералічвае Менеджэр сакрэтаў AWS па трох рэгіёнах, стварае дампы зменных асяроддзя, чытае файлы пад /appі шукае радкі захопу сцяга. Затым ён вылучае вынік двума спосабамі: маяком да webhook.site калектар і маніфест PUT для канчатковай кропкі з неапрацаваным IP-адрасом са спісам рэзервовых варыянтаў, якія спачатку выкарыстоўваюцца ў лакальным хосты.
У пазнейшых апісаннях пакетаў гучыць «CTF payload for supply-chain testing verdaccio». Мы паведамляем пра гэтае самаапісанне як пра назіраны факт. Сама паводзіна — жывы выхад на публічны IP-адрас, рэальныя чытанні ўліковых дадзеных IMDS, рэальныя выклікі Secrets Manager — застаецца такой, якая яна ёсць, незалежна ад пазнакі, і менавіта таму гэтыя версіі былі класіфікаваны як шкоднасныя.
Адно імя ў кластары, coral-wraith, не спыніўся на адным рэлізе. Ён хутка перавыдаваўся ў дзесятках версій за лічаныя гадзіны — 1.0.0 падымаючыся да 6.0.0 — і ў больш раннім выпуску з такой жа назвай выкарыстоўваліся завышаныя 9999.0.x нумары версій, класічная форма спроба блытаніны з залежнасцяміНягледзячы на гэты хаос, карысная нагрузка прыкметна пасталела: з аднаразовага маяка пералічэння хастоў ператварылася ў паўнавартасную вяроўку ўліковых дадзеных AWS, абгорнутую праверкамі асяроддзя, якія трымаюць яе цішыню па-за межамі прызначанай мэты.
| Пакеты | 5 імёнаў; coral-wraith адзін перавыдадзены ў дзясятках версій |
| Экасістэма | НПМ |
| Усталяваць вектар | postinstall сцэнар жыццёвага цыклу |
| Асноўная мэта | Паўнамоцтвы ролі AWS IAM + сакрэтныя значэнні менеджара сакрэтаў, зменныя асяроддзя, /app файлы |
| Выгнаць | webhook.site маяк + неапрацаваны IP-адрас C2 PUT |
| Трыгерны гейт | 12-шаснаццатковае імя хаста + /app/node_modules cwd, а таксама праверка асяроддзя, якая падаўляе карысную нагрузку па-за гэтым кантэкстам |
| Строгасць | высокі — раскрыццё воблачных уліковых дадзеных і кіраванага сакрэту ад кантэйнерныя асяроддзі зборкі і выканання |
Анатомія атакі
Кожны пакет у кластары сабраны аднолькава: амаль пусты index.js (module.exports = {}), аднарадковы package.json сцэнар — «postinstall»: «вузел postinstall.js» — і карысная нагрузка ў postinstall.jsДля запуску перахопніка дастаткова ўсталяваць пакет; імпарт або выклік не патрабуецца.
Брама прыцэльвання. Перш чым што-небудзь зрабіць, карысная нагрузка эктасямейства правярае сваё асяроддзе:
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-шасціграннае імя хаста — гэта форма, якую Docker прызначае кантэйнеру па змаўчанні, і /праграма/модулі_вузлоў — гэта звычайны шлях усталёўкі ў кантэйнеры. Трэці пункт аварыйна спрацоўвае, калі шлях выглядае як каталог распакавання ў пясочніцы. У выніку карысная нагрузка застаецца неактыўным на ноўтбуку распрацоўшчыка або ў пясочніцы аналізу і актывуецца толькі ўнутры кантэйнернай зборкі або працоўнага асяроддзя выканання — асяроддзя, якое, хутчэй за ўсё, будзе ўтрымліваць жывыя воблачныя ўліковыя дадзеныя. Самы ранні пакет у кластары, каралавы прывід, не мае такога вентыля і запускае сваю (прасцейшую) калекцыю безумоўна.
калекцыяКалі брама праходзіць, крук вылятае скрозь execFileSync(“/bin/sh”, [“-c”, …]) і выконвае адну складаную каманду, якая ў наступным парадку:
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) Крокі 1–3 — гэта тыповы для атрымання IMDSv2 падручнік: запытайце токен сесіі, а затым далучыце яго ў якасці Маркер метададзеных X-aws-ec2 загаловак для атрымання ролі IAM экзэмпляра і часовых ключоў доступу гэтай ролі. Выбар рэалізацыі IMDSv2 замест больш простай неаўтэнтыфікаванай IMDSv1 GET варта адзначыць, што гэта азначае, што карысная нагрузка працуе нават на экзэмплярах, настроеных на доступ да метададзеных на аснове токенаў, што з'яўляецца рэкамендаваным AWS узмацненнем бяспекі. Уліковыя дадзеныя, вернутыя на этапе 3, маюць нядоўгі тэрмін дзеяння. Ідэнтыфікатар ключа доступу/СакрэтныКлючАдключу/Знак тройкі, абмежаваныя роляй экзэмпляра; усё, што можа рабіць гэтая роля, уладальнік гэтых ключоў можа рабіць на працягу ўсяго тэрміну дзеяння ўліковых дадзеных.
Крокі 4–6 пашыраюць ахоп. env dump фіксуе ўсё, што атрымала ў спадчыну ад працэсу зборкі або выканання — на практыцы менавіта тут часцей за ўсё захоўваюцца токены рэестра, радкі падключэння да базы дадзеных і ключы API. /прыкладанне File Walk чытае да пятнаццаці файлаў прыкладанняў па-за вузелавыя модулі, які можа мець канфігурацыю паверхні, .env файлы або крыніца. Крок 6 выклікае AWS SecretsManager спіс сакрэтаў у трох рэгіёнах; уліковыя дадзеныя, атрыманыя на этапах 1–3, менавіта аўтэнтыфікуюць гэтыя выклікі, таму зчытванне IMDS і ланцужок пералічэнняў менеджара сакрэтаў аб'ядноўваюцца ў адзіную эскалацыю: роля экзэмпляра → інвентар кіраванага сакрэту. Крок 7 — гэта намёк на фрэймаванне захопу сцяга — калі ГТБ{…} Калі знойдзены сцяг, ён адпраўляецца асобна, інакш неапрацаваны сабраны блоб падзяляецца на чатыры часткі і адпраўляецца.
Пазнейшыя версіі ў кластары працягваюць эскалацыю. Замест таго, каб спыняцца на інвентарызацыі, яны аналізуюць адказ IMDS, экспартуюць часовыя ключы як AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN зменныя асяроддзя, пацвердзіце ідэнтычнасць з AWS STS Атрымаць ідэнтыфікатар абанентаа затым перабіраць кожны сакрэт, які вяртаецца спіс-сакрэтаў пакліканне aws secretsmanager атрымаць сакрэтнае значэнне на кожным — атрыманне сакрэтнага змесціва, а не толькі іх імёнаў. Гэтыя ж версіі таксама чытаюць двайковыя файлы з заменай працэсу (/чытацьфлаг і сябры) і паспрабуйце зарадны прабег супраць любога праекта Rust, які знаходзіцца пад /прыкладанне, пашыраючы збор за межы воблачных уліковых дадзеных на ўсё, што адкрывае асяроддзе зборкі.
Гэтыя пазнейшыя версіі таксама больш агрэсіўна абараняюць сябе. У дадатак да 12-шасціграннага імя хаста і /праграма/модулі_вузлоў Пры праверках карысная нагрузка правярае актыўную канфігурацыю рэестра пакетаў і шлях да працоўнага каталога і ціха завяршае працу, калі яны паказваюць на кантэкст аналізу або люстранога люстэрка, а не на жывую мэту. У выніку карысная нагрузка не робіць нічога назіральнага ў большасці асяроддзяў праверкі і запускае поўную калекцыю толькі там, дзе яна ацэньвае сябе як сапраўднага кантэйнернага хоста.
ЭксфільтрацыяСабраныя дадзеныя пакідаюць хост па двух каналах. Па-першае, маяк POST да фіксаванага вэбхук.сайт калектар, які змяшчае імя хаста, лікавы UID, рабочы каталог і да 120 КБ сабраных дадзеных. Па-другое, дадзеныя згортваюцца ў падроблены YAML-«маніфест модуля» і PUT у /api/модулі/ на мэтавым серверы:
ecto_module: name: "<flag-or-chunk-0>" version: "1.0.0" power_level: "<chunk-1>" ship_deck: "<chunk-2>" cargo_hold: "<chunk-3>" Назвы палёў маніфеста (узровень_магутнасці, палуба_карабля, грузавы адсек) з'яўляюцца дэкарацыяй — скрадзеныя дадзеныя знаходзяцца ўнутры радковых значэнняў, таму сеткавы манітор бачыць тое, што выглядае як бяскрыўдная загрузка маніфеста рэестра пакетаў, а не відавочны дамп дадзеных. Канал маяка перадае больш: POST цела да вэбхук.сайт уключае імя хаста, лікавы UID, рабочы каталог і да 120 КБ сабранага блоба, таму нават адзін паспяховы маяк дае поўны доступ. вэбхук.сайт — гэта бясплатная служба праверкі запытаў; выкарыстанне яе ў якасці зборшчыка азначае, што аператару ніколі не трэба ствараць уласную інфраструктуру атрымання для гэтага канала, а запісаныя запыты захоўваюцца ў кошыку службы.
Маніфест PUT праходзіць рэзервовы спіс, які пачынаецца з некалькіх 127.0.0.1/лакальны парты, а затым трапляе на тры публічныя адрасы ў `154.57.164.0/24` дыяпазон, спыняючыся на першай канчатковай кропцы, якая адказвае са статусам 2xx. Парадак "localhost-first" адпавядае самаапісанню "verdaccio testing" (лакальны рэестр на зваротнай сувязі), але рэзервовыя адваротныя спасылкі на публічны IP азначаюць, што дадзеныя пакідаюць хост кожны раз, калі зваротная сувязь не праслухоўвае, гэта значыць на любой машыне, якая не з'яўляецца ўласнай тэставай устаноўкай аўтара.
Timeline
Кластар дэманструе паступовы рост магчымасцей, а не аднаразовае падзенне. Мы сартуем яго па назіранай паводзінах, а не па часе публікацыі:
| Этап | Пакеты / Версіі | Паводзіны |
|---|---|---|
| Ранні забег | coral-wraith 9999.0.x | Завышаныя нумары версій, што адпавядае спробе блытаніны з залежнасцямі; пералік падчас усталёўкі і выключэнне |
| Сямёна | coral-wraith 1.0.0 | пасля ўсталёўкі збірае файлы id/env/flag; адзін PUT для 154[.]57[.]164[.]71:30782, маркер ECT-472839 |
| Хуткая ітэрацыя | coral-wraith 1.0.1 → 6.0.0 | Дзясяткі рэлізаў за гадзіны; карысная нагрузка набірае абароты isAppWorker() шлюз, атрыманне ўліковых дадзеных IMDSv2, поўны get-secret-value pivot, праверка асяроддзя рэестра/шляху і маркеры падвойнага прыёмніка |
| Паралельныя назвы | ecto-corsair-whisper-6f3b9 1.0.14–1.0.18 | Адна і тая ж абароненая карысная нагрузка; webhook.site спіс маякоў і рэзервовых варыянтаў для некалькіх канчатковых кропак |
| Варыянты | ecto-rust-read-f3a9c1 1.0.1–1.0.2 | Дадае дадатковыя маркеры ракавіны ECT-987654, ECT-654321, ECT-839201 |
| Варыянты | ecto-corsair-flag-x9m4 1.0.0, ecto-nightly-spirit 1.1.0 | Тая ж самая карысная нагрузка, той жа C2 і маяк |
Вызначальнай рысай кластара з'яўляецца яго каардынацыя публікацый: замест аднаго пакета і адной версіі, адна і тая ж назва перавыдаецца зноў і зноў у хуткай паслядоўнасці, кожны рэліз з'яўляецца невялікай варыяцыяй папярэдняга, а таксама некалькі розных па назвах, якія нясуць адну і тую ж карысную нагрузку. шаптаць сямейства код падзяліў на два блізкія адбіткі пальцаў — адзін набор спрацоўвае на два крытычныя выяўленні, другі — на тры (дадатковы прыёмнік чытання файла), — але абодва прыводзяць да адной і той жа карыснай нагрузкі; розніца заключаецца ў дрэйфе кода, а не ў паводніцкім разгалінаванні. Версіі шаптаць за межамі аналізаванага дыяпазону (прынамсі да 1.0.25 на момант напісання) назіраліся ў рэжыме рэальнага часу ў рэестры, і каралавы прывід Назва працягвала падымацца па ўласнай лесвіцы версій праз тое ж акно.
Паказчыкі кампрамісу
Усе індыкатары ніжэй былі выняты з зыходнага кода пакета на дыску. Сеткавыя індыкатары выдалены.
сетка
| індыкатар | Роля |
|---|---|
hxxp://154[.]57[.]164[.]71:30782 | Мэта C2 PUT (coral-wraith) |
hxxp://154[.]57[.]164[.]80:30543 | C2 PUT рэзервовы варыянт (ecto-*) |
hxxp://154[.]57[.]164[.]82:31250 | C2 PUT рэзервовы варыянт (ecto-*) |
hxxp://154[.]57[.]164[.]71:31289 | C2 PUT рэзервовы варыянт (ecto-*) |
hxxps://webhook[.]site/602a4c72-7033-4e28-92ea-dc66e59206e5 | Калекцыянер маякоў |
169[.]254[.]169[.]254/latest/... | Зчытванне ўліковых дадзеных IMDSv2 (на баку мэтавай прылады, метададзеныя AWS) |
Паводніцкі/файлавы
| індыкатар | Роля |
|---|---|
"postinstall": "node postinstall.js" | Усталяваць вектар |
ecto_module: YAML з power_level / ship_deck / cargo_hold ключы | Схема маніфеста Exfil |
Маркеры ракавін ECT-472839, ECT-987654, ECT-654321, ECT-839201 | Сегмент шляху C2 /api/modules/<marker> |
isAppWorker() брама: гаспадар /^[0-9a-f]{12}$/, утрымлівае /app/node_modules | Умова актывацыі |
aws secretsmanager list-secrets за us-east-1, eu-west-1, eu-central-1 | Пералік сакрэтаў |
HTB{...} парсінг рэгулярных выразаў | Збор жніва па прынцыпе «захапі сцяга» |
Хэшы файлаў (sha256, атрыманыя падчас аналізу)
| Размовы | sha256 |
|---|---|
coral-wraith/postinstall.js | ce5ff035cfdfed1d0015446424b352c27b66bcb77e9fdb0a51e4245199146824 |
ecto-corsair-whisper-6f3b9 1.0.18/postinstall.js | b58432acba376aa6976f0490d9a1c04257ccdbc856d8390260c50322d63e31c3 |
Атрыбуцыя і назіраная паводзіны
Пяць назваў пакетаў былі апублікаваныя пад двума дэсктопамі ўліковых запісаў npm, але яны маюць дастатковую колькасць агульнай інфраструктуры, каб разглядаць іх як адзін кластар: тое ж самае экта_модуль схема маніфеста, тая ж ЭКТ-472839 маркер першаснай ракавіны, той самы вэбхук.сайт ідэнтыфікатар калектара і канчатковыя кропкі C2 у адным Блок 154.57.164.0/24`. Пакет насення (`coral-wraith, прасцейшы і неабмежаваны) і, такім чынам, закрытая эктасямейства чытаецца як ітэрацыі аднаго набору інструментаў, а не як незалежныя намаганні.
У пазнейшых версіях пакеты апісваюцца як «Карысная нагрузка CTF для тэсціравання ланцужкоў паставак Verdaccio». Мы разглядаем гэтую пазнаку як назіраны факт і не перафармулюем яе як выснову аб мэце. Тое, што робіць код, адназначна і не залежыць ад таго, як ён пазначаны: ён зчытвае ўліковыя дадзеныя ролі IAM з службы метададзеных экзэмпляра, пералічвае кіраваныя сакрэты ў трох рэгіёнах AWS і перадае вынікі на публічны IP-адрас і старонні зборшчык вэб-хукоў. Сапраўднаму тэставаму аб'екту, які працуе толькі па пятлі, не спатрэбяцца рэзервовы спіс публічных IP-адрасоў, зчытванне ўліковых дадзеных IMDS або міжрэгіянальныя выклікі Secrets Manager. Паколькі выхадны і ўліковы дадзеныя ахопліваюцца рэальна, абмежаваныя версіі былі класіфікаваны як шкоднасныя.
Кантэйнерны рэжым — найбольш прыкметная з аперацыйнага пункту гледжання рыса. Гэта як мера пазбягання (маўчанне на ноўтбуках і ў аналітычных пясочніцах), так і мера мэтанакіраванага выкарыстання, якая запускае пакеты толькі там, дзе найбольш верагодна прысутнічае рэальная роля IAM і жывыя сакрэты. Аналітыкі, якія запускаюць гэтыя пакеты ў агульнай пясочніцы, нічога не заўважаць; такая паводзіна праяўляецца толькі пад імем хаста ў стылі Docker і шляхам усталёўкі ў кантэйнеры.
Уплыў, тэндэнцыі і рэкамендацыі для абаронцаў
Тут уздзеянне заключаецца ў раскрыцці воблачных уліковых дадзеных і сакрэтаў унутры кантэйнераў зборкі і асяроддзя выканання. Уліковыя дадзеныя ролі IAM, атрыманыя з IMDS, маюць усе дазволы, якія мае гэтая роля; tajemstvamenadžer:СпісСакрэтаў (і любыя наступныя GetSecretValue) пашырае гэта на захаваныя сакрэты прыкладанняў. Дампы зменных асяроддзя часта ўтрымліваюць токены рэестра, URL-адрасы базы дадзеных і ключы API. У кантэксце неперасякальнай інфраструктуры або кантэйнера — менавіта тое, што выбірае шлюз — адной транзітыўнай усталёўкі аднаго з гэтых пакетаў дастаткова для ўцечкі гэтага матэрыялу.
Ectoplasm адпавядае заканамернасці, якую мы працягваем назіраць: карысныя нагрузкі падчас усталёўкі, якія звяртаюцца да воблачных метададзеных і кіраваных сакрэтаў, а не да лакальных файлаў, і якія самі спрацоўваюць толькі ў асяроддзях з высокай каштоўнасцю. Ніжэй прыведзены два абарончыя назіранні.
- Форма выяўляеццаУсталявальны перахопнік npm/PyPI, граф выклікаў якога дасягае як API сакрэтаў воблачных сэрвісаў (менеджар сакрэтаў AWS, сакрэты gcloud, сховішча ключоў AZ) або адрас IMDS і выхадны прыёмнік сеткі — гэта вузкі шаблон з высокім узроўнем сігналу — ён амаль ніколі не сустракаецца ў легітымным сцэнарыі жыццёвага цыклу. Статычны аналіз патоку можна пазначаць гэта незалежна ад канкрэтнага дамена або IP-адрасоў.
- Зацвярдзенне навакольнага асяроддзя прытупляе яго. Ужыванне IMDSv2 з абмежаваннем пераходу, роўным 1, не дазваляе кантэйнерным нагрузкам дасягнуць метададзеных экзэмпляра; абмежаванне роляў IAM мінімальнымі прывілеямі абмяжоўвае радыус выбуху любых уцечак уліковых дадзеных; і запуск установак з –ігнараваць-скрыпты у CI цалкам выдаляе вектар перахопнікаў усталёўкі для пакетаў, якім ён не патрэбны.
Для абаронцаў практычныя праверкі наступныя: папярэджанне аб выходных злучэннях з кантэйнераў зборкі/неперарыўнай інтэграцыі з публічнымі IP-адрасамі, якія не ўключаны ў блакітны спіс, падчас ная ўстаноўка; сачыце за доступам да IMDS, які паходзіць са сцэнарыяў жыццёвага цыклу пакета; і ўспрымайце любы перахопнік усталёўкі, які накіроўвае рэсурсы воблачнага CLI, як падазроны, пакуль не будзе даказана адваротнае.
Яшчэ дзве заўвагі, характэрныя для гэтага кластара. Па-першае, паколькі актывацыя абмежаваная кантэйнернымі асяроддзямі, пакет, які выглядае інертным пры праверцы на рабочай станцыі, усё яшчэ можа быць актыўным у прадукцыйным асяроддзі — праверка павінна ўзнавіць імя хаста кантэйнера і ўмовы шляху або прачытаць зыходны код непасрэдна, а не спадзявацца на «Я ўсталяваў яго, і нічога не адбылося». Па-другое, выкарыстанне публічнай службы праверкі запытаў у якасці зборшчыка маякоў азначае, што некаторыя з выцягнутых даных могуць быць адноўлены для рэагавання на інцыдэнт: арганізацыя, якая знаходзіць адзін з гэтых пакетаў у сваім дрэве залежнасцей, можа меркаваць аб тым, што б утрымліваў паспяховы маячок, зыходзячы з логікі збору карыснай нагрузкі, і павінна ратаваць любыя ўліковыя дадзеныя ролі IAM, токены рэестра і кіраваныя сакрэты, якія былі даступныя з пацярпелага асяроддзя зборкі або выканання. Ратацыя паўнамоцтваў, а не выдаленне пакета, з'яўляецца аператыўным выпраўленнем пасля выканання ўсталёўкі.





