Девять пакетов npm скрывали самодельный червь для Linux, распространявшийся по SSH-ключам и токенам публикации

Атака на цепочку поставок NPM

29 сентября 2026 года в реестре npm появились девять пакетов от одного аккаунта. Восемь копировали библиотеку Express версии 5.2.1, девятый - библиотеку React версии 19.3.0. Все публикации уложились в 33 минуты, с 06:05 до 06:38 по всемирному координированному времени. Установка любого из них на Linux запускала самодельный червь. Червь - программа, которая сама копирует себя на новые машины без участия человека.

Описание

Первыми под удар попали разработчики и сборочные серверы. Пакеты выглядели как обычные вспомогательные библиотеки, и подмена имён не бросалась в глаза. Автор использовал учётную запись dirtyblanket и почтовый ящик на стороннем домене. Похожие названия - приём, известный как тайпосквоттинг (подмена имени, рассчитанная на невнимательность), только вместо доменов здесь подделывались имена библиотек.

Запуск цепочки обеспечивал предустановочный сценарий, который менеджер пакетов выполняет до установки самой библиотеки. По данным проведённого анализа, этот сценарий скачивал вспомогательный файл не напрямую с площадки злоумышленника, а через интернет-архив Wayback Machine. Приём маскирует источник: в сетевых журналах виден запрос к архиву, а не к серверу с вредоносным кодом. Многие системы фильтрации трактуют обращения к архиву как безопасные, поэтому проверка пропускала загрузку.

Копия в архиве пережила удаление исходного репозитория на площадке Codeberg. Первый снимок вредоносного файла датирован тем же днём, 05:24 по всемирному времени. Это примерно за 40 минут до публикации первого пакета. Совпадение по времени указывает на подготовку: код заранее положили в архив, а затем выпустили пакеты.

Первая стадия работала только на Linux. На macOS и Windows сценарий ничего не делал. Ветви для Windows остались закомментированными, хотя заготовки в коде есть. Значит, поддержку Windows автор планировал добавить позже. Ошибки и вывод сценарий игнорировал, поэтому установка завершалась молча.

Вторая стадия - скрипт командной оболочки длиной 227 строк, который выполняется с правами установившего его пользователя. С правами администратора он дополнительно ставит системные пакеты. Червь уходил в фон, а его вывод направлялся в никуда. Менеджер пакетов сообщал об успешной установке, и разработчик не замечал ничего необычного.

Следующий шаг - закрепление в системе. Червь копировал исполняемый файл в системный каталог рядом с настоящими службами и оформлял его как службу отрисовки шрифтов. Имя файла, описание службы и её расположение имитировали штатные компоненты операционной системы. Весь трафик поддельной службы направлялся через сеть анонимизации Tor (система, скрывающая адрес отправителя). Файлы службы помечались как неизменяемые, и снять эту защиту мог только тот, кто знает соответствующую команду.

С правами администратора червь ставил сам Tor и инструменты разработчика, а также включал шифрование трафика принудительно. Без таких прав он скачивал переносимую сборку Tor в домашний каталог и заводил две пользовательские службы с правдоподобными названиями. Обе стартовали при входе пользователя в систему.

Основная опасность - быстрое заражение соседних машин. Червь собирал файлы, в которых хранятся отпечатки ранее посещённых серверов, и перебирал все найденные закрытые ключи доступа. Подходящим ключом он пытался войти на каждый известный хост и пароль при этом не запрашивал. Если вход удавался и удалённая система работала на Linux, туда скачивался тот же сценарий и запускался заново. Каждая новая машина давала очередной набор ключей и адресов, и круг расширялся.

Логика перебора имела слабое место. Когда имена серверов хранились в виде необратимых значений, восстановить адрес не получалось, и такой хост червь пропускал. В организациях, где подобная настройка включена по умолчанию, распространение шло медленнее.

Отдельная ветка заражения касалась пользовательского репозитория Arch Linux (AUR - хранилище сборочных описаний, которые ведут сами участники сообщества). Ключом с правом публикации червь заходил в репозиторий, находил пакеты владельца ключа и вносил в них правку. Он увеличивал номер выпуска, добавлял шаг установки и переписывал историю изменений так, чтобы авторство выглядело как у настоящего сопровождающего. Любой, кто обновил такой пакет, запускал червя у себя.

Третье направление - возврат в npm. Червь искал на диске описания проектов, добавлял в них тот же предустановочный сценарий, поднимал версию и публиковал заражённую сборку. Публикация шла от имени владельца каждого найденного файла с токеном доступа. Такие файлы встречаются в домашних каталогах пользователей, у администратора и даже в разделах Windows, открытых из Linux. Локальная копия описания проекта возвращалась в исходный вид, поэтому разработчик не видел изменений.

Список доступного червю широк. Это закрытые ключи без пароля, которые может прочитать пользователь; все серверы, принимающие эти ключи; все пакеты Arch, куда ключ позволяет писать; все проекты npm, открытые найденным токенам. На сборочном сервере или в конвейере непрерывной интеграции (CI - автоматическая сборка и проверка кода) ставки выше: там собраны ключи сразу ко многим системам.

Машину, где установили хотя бы один из девяти пакетов, нужно считать скомпрометированной целиком, вместе со всеми ключами и токенами на ней. Смена паролей не поможет: ключи и токены придётся отозвать и выпустить заново. Полезно сверить журналы публикаций в npm и историю изменений в пользовательском репозитории Arch. На будущее разумно запретить автоматический запуск сценариев установки, требовать двухфакторную аутентификацию для публикаций и держать ключи под паролем.

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

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