Вредоносные пакеты BufferZoneCorp атакуют цепочку поставок Ruby и Go

information security

Разработчики и администраторы конвейеров непрерывной интеграции (CI) столкнулись с новой угрозой. Исследователи безопасности обнаружили кампанию, направленную на подрыв доверия к открытому коду. Злоумышленники использовали аккаунт на GitHub под именем BufferZoneCorp для публикации вредоносных гемов для Ruby и модулей для Go. Эти пакеты имитируют легитимные библиотеки, но на деле крадут учётные данные и захватывают окружения сборки.

Описание

Кампания затронула две крупные экосистемы. В Ruby-гемах код нацелен на кражу секретов - токенов, ключей доступа, содержимого файлов конфигурации. В Go-модулях применяются более разнообразные методы: подмена настроек системы управления зависимостями, добавление поддельных обёрток для исполняемых файлов и даже закрепление в системе через внедрение SSH-ключа. Вредоносные пакеты были опубликованы под похожими на оригинальные именами - это типичный пример тайпсквоттинга (использования названий, близких к известным проектам).

Анализ показал, что аккаунт BufferZoneCorp содержал семнадцать репозиториев. Семь из них были Ruby-гемами, девять - Go-модулями, ещё один репозиторий содержал код, который ещё не был опубликован в реестре, но уже содержал вредоносную логику. Ruby-гемы используют приставку "knot-" к названиям, напоминающим популярные утилиты, такие как "activesupport-logger" или "devise-jwt". Go-модули названы в духе "go-metrics-sdk", "go-retryablehttp", "config-loader" - они легко встраиваются в стандартные графы зависимостей.

Интересна тактика злоумышленников. В начале кампании они загружали "спящие" пакеты - с безобидным кодом, документацией и без явно вредоносной нагрузки. Затем, в последующих обновлениях, добавляли активные функции - кражу данных, изменение окружения, манипуляции с проверками сумм. Это позволило обойти первоначальные проверки безопасности в реестрах.

В Ruby-гемах, например, в пакете "knot-activesupport-logger", вредоносный код выполняется уже на этапе установки. Файл "extconf.rb", который RubyGems запускает автоматически при сборке нативного расширения, содержит полный набор инструкций для сбора секретов. Он перебирает переменные окружения по ключевым словам (token, secret, key, aws, github, api, auth) и считывает файлы "~/.ssh/id_rsa", "~/.aws/credentials", "~/.gem/credentials", "~/.netrc" и другие. Вся информация упаковывается в JSON и уходит на скрытый HTTPS-эндпоинт, закодированный в коде. Если разработчик задаст переменную "PKG_ANALYTICS_URL", то трафик пойдёт на указанный им адрес, что маскирует подозрительную активность под легитимную аналитику.

В отчёте исследователи отметили, что в ходе лабораторного теста перенаправление "PKG_ANALYTICS_URL" на локальный коллектор подтвердило: установка гема действительно инициирует отправку JSON-пакета с метаданными системы и тестовыми секретами. Причём аналогичный сбор происходит и при первом вызове метода логгера во время выполнения - в фоновом потоке. Ошибки при отправке подавляются, чтобы не прерывать работу пользователя.

Go-модули демонстрируют ещё более продвинутые техники. Например, "go-metrics-sdk" автоматически запускается через функцию "init()". Он проверяет, установлена ли переменная окружения "GITHUB_ENV", - значит, код исполняется внутри GitHub Actions. После этого модуль изменяет файл "go.sum", удаляя из него строки, содержащие контрольные суммы для пакета "sirupsen/logrus". Затем в переменную окружения вносятся записи: "GOPROXY" перенаправляется на подконтрольный сервер, отключаются проверки контрольных сумм через "GOSUMDB=off" и "GONOSUMDB=*", устанавливаются флаги "GOFLAGS=-mod=mod" и изменяется путь к кэшу. Цель - заставить конвейер сборки доверять вредоносному прокси, а не официальным проверкам.

Другой модуль, "go-retryablehttp", добавляет поддельную обёртку для исполняемого файла Go. Он также через "init()" обнаруживает "GITHUB_PATH" и дописывает каталог с фальшивым "go"-бинарём в начало пути. Настоящий бинар при этом не заменяется, но перехватчик может перехватывать команды или модифицировать их аргументы, передавая управление дальше.

Самый опасный модуль - "go-stdlib-ext". Он не только собирает креды и переменные окружения, но и дописывает жёстко заданный открытый SSH-ключ в файл "~/.ssh/authorized_keys" с меткой "deploy@buildserver". Это даёт злоумышленнику постоянный доступ к хосту. Кроме того, модуль оставляет в логах диагностической информации и может опрашивать метаданные Docker и AWS, что расширяет поверхность атаки.

Исследователи сообщили о находках в реестры RubyGems и Go. Команда безопасности Go оперативно заблокировала все выявленные модули. Однако на момент написания Ruby-гемы и сам аккаунт BufferZoneCorp на GitHub оставались активны. Это означает, что пользователи всё ещё могут скачать заражённые пакеты, если не используют блокирующие списки.

Разработчикам и администраторам CI-сред следует немедленно проверить, не устанавливались ли гемы с префиксом "knot-" или модули из пространства "github.com/BufferZoneCorp". Если такие пакеты были найдены, необходимо ротировать все скомпрометированные учётные данные, проверить логи сети на исходящие HTTPS-запросы к обнаруженному эндпоинту, а также изучить SSH-ключи на наличие посторонних записей. В GitHub Actions нужно пересмотреть изменения в переменных "GOPROXY", "GOSUMDB", "GONOSUMDB", "GOFLAGS", "GOMODCACHE", а также искать подозрительные обёртки для "go" и следы записи в "~/.ssh/authorized_keys".

Кампания BufferZoneCorp - это яркий пример того, как атакующие используют доверие к open-source экосистемам. Спящие пакеты обходят автоматические сканеры, а последующие обновления доставляют полноценную нагрузку. Скорее всего, даже после удаления конкретных модулей появятся новые с аналогичной тактикой. Единственный способ снизить риск - ограничить область действия секретов в CI и внедрить контрольные процедуры для новых зависимостей, особенно тех, которые выглядят как точная копия известных библиотек.

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

Threat actor aliases

  • BufferZoneCorp — GitHub username
  • knot-theory — RubyGems username

SSH public key

  • ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBp9VZGMxqFpTwKbKJi7dS2mNrX3LqEoHcYsWfAkZvUt deploy@buildserver

GitHub repositories

  • github.com/BufferZoneCorp/activesupport-logger
  • github.com/BufferZoneCorp/devise-jwt-helper
  • github.com/BufferZoneCorp/rack-session-store
  • github.com/BufferZoneCorp/rails-assets-pipeline
  • github.com/BufferZoneCorp/rspec-formatter-json
  • github.com/BufferZoneCorp/date-utils-rb
  • github.com/BufferZoneCorp/simple-formatter
  • github.com/BufferZoneCorp/go-metrics-sdk
  • github.com/BufferZoneCorp/go-weather-sdk
  • github.com/BufferZoneCorp/go-retryablehttp
  • github.com/BufferZoneCorp/go-stdlib-ext
  • github.com/BufferZoneCorp/grpc-client
  • github.com/BufferZoneCorp/net-helper
  • github.com/BufferZoneCorp/config-loader
  • github.com/BufferZoneCorp/log-core
  • github.com/BufferZoneCorp/go-envconfig
  • github.com/BufferZoneCorp/go-stdlog

Ruby gems

  • knot-activesupport-logger
  • knot-devise-jwt-helper
  • knot-rack-session-store
  • knot-rails-assets-pipeline
  • knot-rspec-formatter-json
  • knot-date-utils-rb
  • knot-simple-formatter

Go modules

  • github.com/BufferZoneCorp/go-metrics-sdk
  • github.com/BufferZoneCorp/go-weather-sdk
  • github.com/BufferZoneCorp/go-retryablehttp
  • github.com/BufferZoneCorp/go-stdlib-ext
  • github.com/BufferZoneCorp/grpc-client
  • github.com/BufferZoneCorp/net-helper
  • github.com/BufferZoneCorp/config-loader
  • github.com/BufferZoneCorp/log-core
  • github.com/BufferZoneCorp/go-envconfig

Exfiltration endpoint

  • https://webhook.site/49c21843-c27c-4a1b-b1f6-037c3998055f
Комментарии: 0