Кампания CanisterWorm, представляющая собой сложную атаку на цепочку поставок программного обеспечения через реестр npm с червячным механизмом распространения, получила новое развитие. Исследователи кибербезопасности, ранее сообщавшие об этой угрозе, выявили дополнительные вредоносные версии пакетов, что расширяет масштабы потенциального заражения. Эта атака демонстрирует, как компрометация учётных данных одного разработчика может привести к автоматизированному заражению целого ряда его проектов и создать угрозу для тысяч зависимых приложений.
Описание
Изначально о кампании сообщили такие компании, как Socket и Endor Labs. Угроза, авторы которой отслеживаются под именем TeamPCP, основана на захвате легитимных пространств имён издателей в npm. Злоумышленники получали доступ к учётным записям, например, @emilgroup, и публиковали новые версии SDK-пакетов, содержащие скрытую вредоносную функциональность. Отличительной чертой CanisterWorm является её автономность: после проникновения в систему она не только крадёт конфиденциальные данные, но и самостоятельно распространяется, используя похищенные токены для заражения других пакетов того же владельца.
Механизм работы вредоносного кода продуман для обеспечения выполнения и закрепления в системе. Запуск происходит через скрипт "postinstall", определённый в файле "package.json". При стандартной установке пакета через менеджер npm этот скрипт автоматически выполняется, что приводит к развёртыванию Python-бэкдора на целевом хосте. Для обеспечения постоянного присутствия в Linux-средах червь создаёт фоновую службу "pgmon" с помощью "systemd --user". Основная опасность заключается в механизме управления: бэкдор регулярно опрашивает канал команд и управления, развёрнутый на блокчейне Internet Computer Protocol (ICP, протокол децентрализованных вычислений). Специальный "контейнер" (canister) в этой сети выступает в роли промежуточного звена, откуда загружаются вторичные полезные нагрузки.
Главной целью вредоносной программы является хищение учётных данных, необходимых для публикации пакетов в npm. Она проводит целенаправленное сканирование системы в поисках токенов аутентификации. В область поиска входят файлы конфигурации ".npmrc" в локальном проекте, домашнем каталоге пользователя и общесистемном расположении "/etc/npmrc". Кроме того, программа анализирует переменные окружения "NPM_TOKEN" и "NPM_TOKENS", а также выполняет команду "npm config get" для извлечения токена из регистра. Полученные данные используются для самораспространения: специальный скрипт "deploy.js" автоматически находит все пакеты, принадлежащие скомпрометированному пользователю, в реестре npmjs.com, инкрементирует их младшую версию и публикует обновление, уже содержащее вредоносный код. Это превращает единичный случай компрометации в лавинообразное заражение экосистемы.
Благодаря непрерывному мониторингу исследовательской группе удалось выявить полный перечень пакетов, затронутых этой атакой, включая версии, не упомянутые в более ранних публичных отчётах. Если в вашей среде используются следующие конкретные версии пакетов, необходимо считать систему скомпрометированной и немедленно принять меры: "@emilgroup/discount-sdk" (1.5.1), "@emilgroup/document-uploader" (0.0.10), "@emilgroup/docxtemplater-util" (1.1.2), "@emilgroup/numbergenerator-sdk-node" (1.3.1), "@emilgroup/partner-portal-sdk" (1.1.1), "@emilgroup/setting-sdk" (0.2.1), "@emilgroup/task-sdk" (1.0.2) и "@emilgroup/task-sdk-node" (1.0.2). Использование этих версий означает, что в процессе установки мог быть выполнен вредоносный скрипт, установлен бэкдор и похищены токены для публикации в npm.
Последствия подобной атаки выходят далеко за рамки единичной системы. Основной риск заключается в самовоспроизводящемся характере угрозы. Похитив токен, злоумышленники получают возможность от имени легитимного разработчика распространять вредоносные обновления по всем его пакетам. Это ставит под угрозу цепочки поставок всех проектов и организаций, которые используют эти зависимости, даже если их собственные системы напрямую не были атакованы. Вторичные полезные нагрузки, загружаемые с канала управления, могут быть использованы для любой последующей деятельности: от кража исходного кода и данных до криптоджекинга или движения по сети в рамках более масштабной атаки.
Для устранения последствий заражения необходим комплексный подход. Первым и критически важным шагом является сдерживание: немедленный поворот всех токенов публикации npm и секретов CI/CD, которые могли быть доступны с заражённого хоста. Это включает токены из всех возможных мест хранения. Новые учётные данные должны быть строго ограничены по уровню доступа и иметь срок действия. Далее необходимо уничтожить механизм закрепления в системе, остановив и отключив службу "pgmon", а также удалив все связанные с вредоносной программой файлы, такие как "/tmp/pglog" и "/tmp/.pg_state". На уровне проекта требуется полная очистка кэша и папки "node_modules" с последующей переустановкой зависимостей, но с жёсткой фиксацией версий пакетов на известных безопасных релизах, выпущенных до начала атаки. Если злоумышленники успели опубликовать вредоносные версии под вашим пространством имён, эти версии необходимо принудительно удалить из реестра npm, чтобы защитить других пользователей.
В долгосрочной перспективе для защиты от подобных атак цепочки поставок необходимы как технические, так и организационные меры. К ним относятся глобальное отключение автоматического выполнения скриптов в npm через настройку "ignore-scripts true", использование инструментов для выборочного утверждения жизненных циклов пакетов, внедрение системных политик безопасности для ограничения записи в критичные каталоги вроде "~/.config/systemd/user/", а также настройка автоматизированного сканирования и проверки зависимостей до их попадания в производственную среду с помощью решений класса Software Composition Analysis (SCA). Инцидент с CanisterWorm наглядно показывает, что современные угрозы цепочке поставок требуют перехода от реагирования к активному и превентивному контролю за всеми внешними зависимостями.
Индикаторы компрометации
Package
- @airtm/uuid-base32 1.0.2
- @emilgroup/accounting-sdk 1.27.3,1.27.2,1.27.1
- @emilgroup/accounting-sdk-node 1.26.2,1.26.1
- @emilgroup/account-sdk 1.41.2,1.41.1
- @emilgroup/account-sdk-node 1.40.2,1.40.1
- @emilgroup/api-documentation 1.19.2,1.19.1
- @emilgroup/auth-sdk 1.25.2,1.25.1
- @emilgroup/auth-sdk-node 1.21.2,1.21.1
- @emilgroup/billing-sdk 1.56.2,1.56.1
- @emilgroup/billing-sdk-node 1.57.2,1.57.1
- @emilgroup/changelog-sdk-node 1.0.3,1.0.2
- @emilgroup/claim-sdk 1.41.2,1.41.1
- @emilgroup/claim-sdk-node 1.39.2,1.39.1
- @emilgroup/commission-sdk 1.0.3,1.0.2,1.0.1
- @emilgroup/commission-sdk-node 1.0.3,1.0.2,1.0.1
- @emilgroup/customer-sdk 1.54.5,1.54.4,1.54.3,1.54.2,1.54.1
- @emilgroup/customer-sdk-node 1.55.2,1.55.1
- @emilgroup/discount-sdk 1.5.3,1.5.2,1.5.1
- @emilgroup/discount-sdk-node 1.5.2,1.5.1
- @emilgroup/document-sdk 1.45.2,1.45.1
- @emilgroup/document-sdk-node 1.43.6,1.43.5,1.43.4,1.43.3,1.43.2,1.43.1
- @emilgroup/document-uploader 0.0.12,0.0.11,0.0.10
- @emilgroup/docxtemplater-util 1.1.4,1.1.3,1.1.2
- @emilgroup/gdv-sdk 2.6.2,2.6.1
- @emilgroup/gdv-sdk-node 2.6.3,2.6.2,2.6.1
- @emilgroup/insurance-sdk 1.97.6,1.97.5,1.97.4,1.97.3,1.97.2,1.97.1
- @emilgroup/insurance-sdk-node 1.95.2,1.95.1
- @emilgroup/notification-sdk-node 1.4.2,1.4.1
- @emilgroup/numbergenerator-sdk-node 1.3.3,1.3.2,1.3.1
- @emilgroup/partner-portal-sdk 1.1.3,1.1.2,1.1.1
- @emilgroup/partner-portal-sdk-node 1.1.2,1.1.1
- @emilgroup/partner-sdk 1.19.3,1.19.2,1.19.1
- @emilgroup/partner-sdk-node 1.19.2,1.19.1
- @emilgroup/payment-sdk 1.15.2,1.15.1
- @emilgroup/payment-sdk-node 1.23.2,1.23.1
- @emilgroup/process-manager-sdk 1.4.2,1.4.1
- @emilgroup/process-manager-sdk-node 1.13.2,1.13.1
- @emilgroup/public-api-sdk 1.33.2,1.33.1
- @emilgroup/public-api-sdk-node 1.35.2,1.35.1
- @emilgroup/setting-sdk 0.2.3,0.2.2,0.2.1
- @emilgroup/setting-sdk-node 0.2.3,0.2.2,0.2.1
- @emilgroup/task-sdk 1.0.4,1.0.3,1.0.2
- @emilgroup/task-sdk-node 1.0.4,1.0.3,1.0.2
- @emilgroup/tenant-sdk 1.34.2,1.34.1
- @emilgroup/tenant-sdk-node 1.33.2,1.33.1
- @emilgroup/translation-sdk-node 1.1.2,1.1.1
- @leafnoise/mirage 2.0.3
- @opengov/form-builder 0.12.3
- @opengov/form-renderer 0.2.20
- @opengov/form-utils 0.7.2
- @opengov/ppf-backend-types 1.141.2
- @opengov/ppf-eslint-config 0.1.11
- @opengov/qa-record-types-api 1.0.3
- @pypestream/floating-ui-dom 2.15.1
- @teale.io/eslint-config 1.8.16,1.8.15,1.8.14,1.8.13,1.8.12,1.8.11,1.8.10,1.8.9
- @virtahealth/substrate-root 1.0.1
- babel-plugin-react-pure-component 0.1.6
- cit-playwright-tests 1.0.1
- eslint-config-ppf 0.128.2
- eslint-config-service-users 0.0.3
- jest-preset-ppf 0.0.2
- opengov-k6-core 1.0.2
- react-autolink-text 2.0.1
- react-leaflet-cluster-layer 0.0.4
- react-leaflet-heatmap-layer 2.0.1
- react-leaflet-marker-layer 0.1.5