Атака на цепочку поставок npm: новый червь распространяется через скрытый механизм сборки node-gyp

Атака на цепочку поставок npm: новый червь распространяется через скрытый механизм сборки node-gyp

Экосистема JavaScript снова столкнулась с серьёзной угрозой. Специалисты компании StepSecurity, занимающейся защитой конвейеров разработки, обнаружили активную самовоспроизводящуюся атаку на цепочку поставок, которая распространяется через реестр npm. Под ударом оказались разработчики, использующие как локальные среды, так и автоматизированные конвейеры CI/CD. Особенность этой атаки в том, что она обходит типовые механизмы контроля, встроенные в npm и средства анализа кода.

Описание

Вредоносная программа представляет собой полноценного червя, нацеленного на инфраструктуру непрерывной интеграции и развёртывания. После выполнения в среде разработчика или в конвейере CI она собирает учётные данные из множества сервисов, а затем на их основе публикует заражённые версии других пакетов, которыми владеет жертва. Таким образом вредонос распространяется дальше по экосистеме. Кроме того, червь внедряет вредоносные шаги в рабочие процессы GitHub Actions, чтобы запускаться при каждом новом задании в скомпрометированных репозиториях.

StepSecurity в своём сообщении подчёркивает, что ранее подобных атак в таком масштабе не наблюдалось. Главное отличие - способ доставки вредоносного кода. Традиционные угрозы для цепочки поставок npm используют хуки жизненного цикла в package.json, например preinstall или postinstall. Инструменты безопасности, рецензенты кода и системы аудита npm как раз ориентируются на эти точки. Однако злоумышленник пошёл другим путём.

Он добавляет в пакет небольшой файл binding.gyp. Когда npm встречает такой файл при установке, он автоматически вызывает node-gyp - утилиту для компиляции нативных модулей Node.js. Атакующий использует особенность node-gyp: возможность подстановки команд в массиве sources через конструкцию <!(...). В результате при установке пакета без каких-либо подозрительных записей в package.json выполняется произвольный код. Файл binding.gyp занимает всего около 100 байт, а вызываемый им index.js - от 4,5 до 4,9 мегабайт обфусцированного кода.

Вредоносная программа работает в три этапа. На первом этапе корневой index.js использует шифр Цезаря (ROT-N) для декодирования внутреннего скрипта, который затем расшифровывает две полезные нагрузки, зашифрованные алгоритмом AES-128-GCM (симметричное шифрование с аутентификацией). На втором этапе первая расшифрованная нагрузка беззвучно загружает из GitHub среду выполнения Bun версии 1.3.13 во временную директорию. Это даёт атакующему быструю автономную платформу, которая не оставляет явных следов в дереве процессов Node.js.

Третий этап - основная часть червя, примерно 720 килобайт. Он запускается через загруженную среду Bun и выполняет четыре функции: сбор учётных данных, внедрение в рабочие процессы GitHub Actions, отравление пакетов и эксфильтрацию. При сборе данных червь сканирует переменные окружения в поисках токенов npm, токенов GitHub и персональных ключей доступа (PAT), ключей доступа AWS, учётных данных сервисных аккаунтов GCP, секретов клиентов Azure, токенов HashiCorp Vault, токенов сервисных аккаунтов Kubernetes, ключей API RubyGems, а также паролей из менеджеров 1Password CLI, gopass и pass. Более того, он извлекает маскированные секреты из памяти процессов GitHub Actions runner.

Используя украденные токены GitHub, червь модифицирует файлы рабочих процессов CI/CD в репозиториях, куда жертва может отправлять изменения. Он добавляет шаг установки Bun и шаг выполнения полезной нагрузки, так что червь запускается при каждом новом задании в этих репозиториях. Затем с помощью украденных токенов npm или RubyGems программа запрашивает реестр, загружает все пакеты жертвы, внедряет в них вредоносный код и публикует новые отравленные версии. Именно так червь распространяется от одного скомпрометированного аккаунта на десятки пакетов.

Собранные учётные данные шифруются открытым ключом RSA, жёстко заданным в коде, и отправляются в репозитории, контролируемые злоумышленником, в виде "висячих коммитов" - таких, которые не видны при обычном просмотре веток. Это делает их обнаружение через стандартные интерфейсы GitHub крайне затруднительным.

На момент публикации StepSecurity уже выявила скомпрометированные версии нескольких пакетов в реестре npm, и этот список продолжает расти по мере распространения червя. Разработчикам рекомендуется немедленно проверить свои пакеты на наличие подозрительных файлов binding.gyp, особенно если в них нет соответствующих нативных модулей. Также стоит обратить внимание на необычно большие index.js и несанкционированные изменения в репозиториях. Хотя полное искоренение такой угрозы потребует усилий всего сообщества, знание о механизме атаки - первый шаг к защите.

Индикаторы компрометации

Комментарии: 0