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-адресом, а также список резервных вариантов, начинающихся с localhost.
В более поздних описаниях пакетов указано: «Полезная нагрузка CTF для тестирования цепочки поставок Verdaccio». Мы сообщаем об этом самоописании как о наблюдаемом факте. Само поведение — исходящий трафик на публичный IP-адрес, реальное чтение учетных данных IMDS, реальные вызовы Secrets Manager — остается тем, чем оно является, независимо от метки, и именно поэтому эти версии были классифицированы как вредоносные.
В этой группе всего одно имя. coral-wraithИгра не ограничилась одним релизом. Она переиздавалась в быстрой последовательности, выпуская десятки версий за считанные часы. 1.0.0 восхождение на 6.0.0 — а в более ранней версии с тем же названием использовались надувные 9999.0.x номера версий, классическая форма попытка вызвать путаницу зависимостейВ процессе этих изменений полезная нагрузка заметно повзрослела: из одноразового маяка для перечисления хостов она превратилась в полноценную систему аутентификации по учетным данным AWS, защищенную проверками среды, которые не позволяют ей оставаться незамеченной за пределами целевого объекта.
| Packages | 5 имен; coral-wraith один был переиздан в десятках версий |
| Экосистема | НПМ |
| Установить вектор | postinstall скрипт жизненного цикла |
| Основная цель | Учетные данные роли AWS IAM + значения секретов Secrets Manager, переменные среды. /app файлов |
| изгнание | webhook.site маяк + необработанный IP C2 PUT |
| Затвор триггера | 12-шестнадцатеричное имя хоста + /app/node_modules текущий рабочий каталог (cwd), а также проверка окружения, которая подавляет полезную нагрузку вне этого контекста. |
| Строгость | высокая — раскрытие учетных данных облачного сервиса и управляемого секрета от контейнеризированные среды сборки и выполнения |
Анатомия атаки
Каждый пакет в кластере собирается одинаково: практически пустой index.js (модуль.экспорт = {}), в одну строку пакет.json сценарий — “postinstall”: “node 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 -> proceed12-значное шестнадцатеричное имя хоста — это стандартная форма, которую Docker присваивает контейнеру. /app/node_modules Это обычный путь установки внутри контейнера. Третий пункт прерывается, если путь выглядит как изолированная директория для извлечения. В результате полезная нагрузка остается в спящем режиме на ноутбуке разработчика или в песочнице для анализа и активируется только внутри контейнеризированного рабочего процесса сборки или выполнения — среды, в которой, скорее всего, будут использоваться учетные данные для работы с облаком. Самый ранний пакет в кластере, коралловый призрак, не имеет такого вентиля и запускает свою (более простую) коллекцию безусловно.
Когда ворота проходят, крюк выдвигается наружу. 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-metadata-token Заголовок для получения роли IAM экземпляра и временных ключей доступа этой роли. Выбор в пользу реализации IMDSv2 вместо более простого неаутентифицированного IMDSv1. ПОЛУЧИТЬ Стоит отметить, что это означает, что полезная нагрузка работает даже на экземплярах, настроенных на использование доступа к метаданным на основе токенов, что является рекомендуемым AWS усилением безопасности. Учетные данные, возвращаемые на шаге 3, имеют кратковременный срок действия. AccessKeyId/Секретаксесскей/Токены Тройки, ограниченные ролью экземпляра; все, что может делать эта роль, может делать владелец этих ключей в течение всего срока действия учетных данных.
Шаги 4–6 расширяют охват. окр Дамп содержит все данные, унаследованные процессом сборки или выполнения — на практике здесь чаще всего хранятся токены реестра, строки подключения к базе данных и ключи API. / приложение file walk считывает до пятнадцати файлов приложения извне. node_modules, которая может отображать конфигурацию, .env файлы или источник. Шаг 6 вызывает aws secretsmanager list-secrets в трех регионах; учетные данные, полученные на шагах 1–3, в точности соответствуют аутентификации этих вызовов, поэтому чтение IMDS и цепочка перечисления Secrets Manager объединяются в единую эскалацию: роль экземпляра → инвентаризация управляемых секретов. Шаг 7 — это отсылка к стратегии «захвата флага» — когда HTB{…} Если флаг найден, он отправляется отдельно, в противном случае собранный исходный блок данных разбивается на четыре части и отправляется отдельно.
Более поздние версии в кластере развивают эту функцию дальше. Вместо того чтобы останавливаться на инвентаризации, они анализируют ответ IMDS и экспортируют временные ключи. AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN переменные среды, подтвердите личность с помощью aws sts получить идентификатор вызывающего абонентаа затем пройтись циклом по каждому секретному ключу, возвращенному функцией. список секретов требуют aws secretsmanager get-secret-value на каждом — извлекая секретное содержимое, а не только их названия. Те же версии также считывают бинарные файлы флагов, замененные в процессе./readflag и друзей) и попытаться зарядный пробег против любого проекта Rust, найденного в / приложениерасширяя возможности сбора данных за пределы облачных учетных данных и охватывая все, что предоставляет среда сборки.
Эти более поздние версии также более агрессивно ограничивают себя. В дополнение к 12-хеш-имя хоста и /app/node_modules В ходе проверок полезная нагрузка анализирует активную конфигурацию реестра пакетов и путь к рабочему каталогу и молча завершает работу, когда они указывают на контекст анализа или зеркалирования, а не на действующий целевой объект. В результате полезная нагрузка не делает ничего заметного в большинстве сред проверки и выполняет полный сбор данных только там, где, по ее мнению, она находится на подлинном контейнеризированном хосте.
эксфильтрацииСобранные данные передаются на хост по двум каналам. Во-первых, через маяк. POST к фиксированной вебхук.сайт Сборщик данных, содержащий имя хоста, числовой UID, рабочий каталог и до 120 КБ собранных данных. Во-вторых, данные объединяются в фиктивный YAML-«манифест модуля». ПОЛОЖИЛ в /api/modules/ на целевом сервере:
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 КБ собранного BLOB-объекта, поэтому даже один успешный отправитель сигнала обеспечивает получение полной информации. вебхук.сайт Это бесплатный сервис для проверки запросов; использование его в качестве сборщика означает, что оператору никогда не придется развертывать собственную приемную инфраструктуру для этого канала, а записанные запросы сохраняются в корзине сервиса.
Манифест ПОЛОЖИЛ включает в себя список запасных вариантов, начинающийся с нескольких 127.0.0.1/локальный порты, а затем происходит переключение на три публичных адреса в `154.57.164.0/24` Диапазон запросов, с остановкой на первой конечной точке, которая отвечает статусом 2xx. Порядок «сначала локальный хост» соответствует самоописанию «тестирования Verdaccio» (локальный реестр на Loopback), но резервные варианты с публичным IP-адресом означают, что данные покидают хост всякий раз, когда Loopback не прослушивается — то есть на любой машине, кроме собственной тестовой установки автора.
Лента
В кластере наблюдается постепенный рост возможностей, а не единовременное снижение. Мы ранжируем его по наблюдаемому поведению, а не по опубликованным данным:
| Этап | Пакеты / Версии | Поведение |
|---|---|---|
| Ранний забег | coral-wraith 9999.0.x | Завышенные номера версий, соответствующие попытке ввести в заблуждение пользователей относительно зависимостей; перечисление и извлечение данных во время установки. |
| Сид | coral-wraith 1.0.0 | postinstall собирает файлы id/env/flag; выполняется один PUT-запрос для... 154[.]57[.]164[.]71:30782маркер ECT-472839 |
| Быстрая итерация | coral-wraith 1.0.1 → 6.0.0 | Десятки релизов за несколько часов; полезная нагрузка получает isAppWorker() ворота, получение учетных данных IMDSv2, полный get-secret-value сводная таблица, проверка среды реестра/пути и маркеры двойного приемника |
| Параллельные имена | 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 | Та же полезная нагрузка с шлагбаумом, тот же центр управления и связи и маяк. |
Отличительной чертой кластера является ритм публикации: вместо одного пакета и одной версии, одно и то же имя переиздается снова и снова с небольшой периодичностью, каждый релиз представляет собой небольшую вариацию предыдущего, наряду с несколькими другими пакетами с другими названиями, содержащими тот же контент. Внутри кластера шептать В семействе кодов произошел разрыв на два близких по характеристикам варианта — один набор активирует два критических обнаружения, другой — три (дополнительный обработчик чтения файла), — но оба приводят к одной и той же полезной нагрузке; разница заключается в изменении кода, а не в поведенческом форке. Версии шептать За пределами анализируемого диапазона (по крайней мере, до 1.0.25 на момент написания статьи) в режиме реального времени наблюдались данные в реестре, и коралловый призрак Название продолжало подниматься по лестнице версий в том же окне.
Индикаторы компромисса
Все приведенные ниже индикаторы были извлечены из исходного кода пакета на диске. Сетевые индикаторы обезличены.
Cеть
| Индикаторные | Роли |
|---|---|
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}$/, cwd содержит /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, но они используют достаточно общую инфраструктуру, чтобы рассматривать их как один кластер: один и тот же. ecto_module схема манифеста, та же самая ЭСТ-472839 основной маркер раковины, тот же самый вебхук.сайт Идентификатор сборщика и конечные точки C2 находятся в одном и том же месте. Блок 154.57.164.0/24. Пакет семян (`coral-wraith`)(более простые и без ограничений) и, таким образом, семейство эктоплазматических организмов с ограничениями воспринимается скорее как итерации одного инструментария, чем как независимые разработки.
В более поздних версиях эти пакеты описывают себя следующим образом: «Полезная нагрузка CTF для тестирования цепочки поставок Verdaccio». Мы представляем эту метку как наблюдаемый факт и не переформулируем её как вывод о цели. Действия кода однозначны и не зависят от того, как он обозначен: он считывает учетные данные ролей IAM из службы метаданных экземпляра, перечисляет управляемые секреты в трёх регионах AWS и передаёт результаты на публичный IP-адрес и стороннему сборщику веб-хуков. В тестовой среде, использующей только локальный доступ, не потребуется список резервных публичных IP-адресов, чтение учетных данных IMDS или вызовы Secrets Manager между регионами. Поскольку исходящий трафик и доступ к учетным данным реальны, версии с ограниченным доступом были классифицированы как вредоносные.
Наиболее заметной с оперативной точки зрения особенностью является ограничение доступа только для контейнеров. Это одновременно и мера обхода (сохранение анонимности на ноутбуках и в аналитических песочницах), и мера целевого воздействия, срабатывающая только там, где наиболее вероятно наличие реальной роли IAM и действующих секретов. Аналитики, запускающие эти пакеты в обычной песочнице, ничего не заметят; такое поведение проявляется только при использовании имени хоста в стиле Docker и пути установки внутри контейнера.
Влияние, тенденции и рекомендации для защитников
В данном случае речь идёт о раскрытии облачных учётных данных и секретной информации внутри контейнеров сборки и выполнения. Учётные данные роли IAM, полученные из IMDS, содержат все разрешения, которыми обладает эта роль; secretsmanager:ListSecrets (и любые последующие) GetSecretValueЭто расширяет область действия до хранимых секретов приложений. Дампы переменных окружения часто содержат токены реестра, URL-адреса баз данных и ключи API. В контексте CI или контейнеризации — именно то, что выбирает шлюз — одной транзитивной установки одного из этих пакетов достаточно, чтобы произошла утечка этой информации.
Ectoplasm соответствует наблюдаемой нами закономерности: вредоносные программы, устанавливаемые во время работы, обращаются к облачным метаданным и управляемым секретам, а не к локальным файлам, и срабатывают только в средах с высокой ценностью. Далее следуют два замечания по поводу защиты.
- Форма различима.. Хук установки npm/PyPI, граф вызовов которого обращается как к API облачных секретов (aws secretsmanager, секреты gcloud, az keyvault) или адрес IMDS и сетевой исходящий приемник представляют собой узкий, высокосигнальный шаблон — он почти никогда не встречается в легитимном скрипте жизненного цикла. Анализ статического потока Можно пометить это независимо от конкретного домена или IP-адреса.
- Ужесточение экологических норм ослабляет его. Применение протокола IMDSv2 с ограничением количества переходов до 1 предотвращает доступ контейнерных рабочих нагрузок к метаданным экземпляра; ограничение ролей IAM минимальными привилегиями снижает вероятность утечки учетных данных; а запуск установок с использованием –Ignore-scripts В системе непрерывной интеграции полностью удаляется вектор install-hook для пакетов, которым он не нужен.
Для специалистов по кибербезопасности практические проверки сводятся к следующему: оповещение об исходящих соединениях из контейнеров сборки/CI с незарегистрированными публичными IP-адресами во время выполнения запроса. Установка npm; следите за доступом к IMDS, исходящим из скриптов жизненного цикла пакетов; и рассматривайте любой обработчик установки, который обращается к облачному CLI, как подозрительный, пока не будет доказано обратное.
Еще два замечания, касающиеся именно этого кластера. Во-первых, поскольку активация ограничена контейнеризированными средами, пакет, который кажется неактивным при проверке на рабочей станции, все еще может быть активен в производственной среде — проверка должна воспроизводить условия имени хоста и пути контейнера или считывать исходный код напрямую, а не полагаться на «я установил его, и ничего не произошло». Во-вторых, использование общедоступной службы проверки запросов в качестве сборщика маяков означает, что часть украденных данных может быть восстановлена для реагирования на инциденты: организация, обнаружившая один из таких пакетов в своем дереве зависимостей, может рассуждать о том, что содержал бы успешный маяк, исходя из логики сбора полезной нагрузки, и должна ротировать любые учетные данные ролей IAM, токены реестра и управляемые секреты, которые были доступны из затронутой среды сборки или выполнения. ротация учетных данныхПосле завершения установки оперативной мерой по устранению проблемы является не удаление пакета, а именно его замена.






