Вечером 15 сентября началась новая атака на популярнейший реестр JavaScript-компонентов, npm. Ряд пакетов, некоторые из которых имеют миллионы еженедельных загрузок, были заражены вредоносным кодом, крадущим токены и ключи аутентификации. Его самая интересная особенность – он способен распространяться автоматически, заражая другие доступные пакеты. Среди зараженных пакетов отметим популярный @ctrl/tinycolor. По данным Aikido Security были скомпрометированы почти 150 пакетов, включая пакеты Crowdstrike.
Методика распространения и алгоритм работы
Способ первого заражения и «нулевой пациент» на сегодня неизвестны. Поскольку «почерк» атаки очень похож на недавний инцидент s1ngularity, возможно, это тоже был фишинг. Но дальнейшая цепочка заражения такова:
- Вредоносный код добавляется в скомпрометированные пакеты в виде постинсталляционного скрипта, сохраненного в файле bundle.js. Когда жертва устанавливает себе зараженный пакет, скрипт начинает свою работу. В отличие от прошлого инцидента, скрипт кроссплатформенный и работает как в *nix-средах, так и под Windows.
- Скрипт скачивает подходящую для платформы версию TruffleHog, легитимного инструмента поиска секретов. TruffleHog находит в локальных файловых системах и доступных репозиториях строки с высокой энтропией. Это криптографические ключи, API-токены и другая подобная информация.
- Кроме поиска через TruffleHog, скрипт проверяет полезные токены, анализируя переменные окружения, например GITHUB_TOKEN, NPM_TOKEN, AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY. Затем он проверяет, действительны ли они, запросами к API-узлам npm whoami и GitHub user.
- Затем скрипт компрометирует пакеты npm, к которым у атакованного пользователя есть доступ на публикацию. Для этого он скачивает для заражаемого пакета его текущую версию из npm, увеличивает подверсию на 1, добавляет ссылку на постинсталляционный сценарий (postinstall hook) и записывает свою копию в файл bundle.js. Троянизированный таким образом пакет «новой версии» публикуется в npm.
- Репозитории жертвы помечаются как публичные, что иногда является отдельной, более важной утечкой.
Публикация украденных данных
Извлечение найденных у жертвы секретов ведется сразу двумя способами.
Через репозиторий GitHub. От имени жертвы и с его токеном GitHub создается публичный репозиторий Shai-Hulud. В нем публикуется JSON-файл с собранными секретами и системной информацией.
Через GitHub actions. Скрипт создает новый рабочий процесс GitHub (github/workflows/shai-hulud-workflow.yml), который кодирует собранные секреты в JSON и передает на сервер атакующих webhook[.]site.
Реагирование на инцидент
О заражении пакета tinycolor и десятков других стало известно в ночь с 15 на 16 сентября, и уже к утру администрация npm начала реагирование, откатывая зараженные пакеты к их «чистым» версиям. В истории обработанных пакетов вообще не видна вредоносная версия, но о том, что она существовала, можно узнать в бюллетенях GitHub. Судя по тому, что на момент написания материала уже 5 часов не было новых бюллетеней, масштабный инцидент можно было бы считать завершенным. Но, учитывая, что мы имеем дело с червем, все может начаться заново, если только npm не заблокирует публикацию конкретных вредоносных файлов в принципе.
Тем, кто успел загрузить зараженные пакеты, рекомендованы:
- откат к безопасным версиям пакетов и очистка кэша npm;
- аудит пайплайна CI/CD и компьютеров разработчиков на предмет несанкционированных изменений;
- анализ логов для идентификации подозрительных обращений к npm publish;
- замена всех ключей и токенов NPM, GitHub, AWS, GCP, Azure, которые были доступны в пораженной среде.
Решения "Лаборатории Касперского" детектируют эту угрозу c вердиктом Worm.Script.Shulud.*. Самый полный список зараженных пакетов ищите на GitHub.