Специалисты по информационной безопасности из компании Socket обнаружили давно действующую атаку на цепочку поставок в экосистеме языка Go. Речь идёт о модуле-двойнике (typosquat) популярной библиотеки для точных вычислений с плавающей запятой. Поддельный модуль github[.]com/shopsprint/decimal копировал функциональность легитимной библиотеки github.com/shopspring/decimal, но в старой версии содержал скрытый бэкдор, работающий через DNS-запросы. Злоумышленники опубликовали вредоносную версию ещё в августе 2023 года, и всё это время она оставалась доступной для скачивания через официальные инструменты разработки.
Описание
Отличие между настоящим и поддельным модулем - всего одна буква в имени владельца репозитория: shopspring (правильное) против shopsprint (вредоносное). Библиотека shopspring/decimal широко используется в финансовых, бухгалтерских, криптовалютных и аналитических проектах, поскольку встроенный тип float64 языка Go не позволяет точно представлять денежные значения. Число известных импортёров легитимного модуля превышает 38 тысяч. Это делает его привлекательной целью для атаки через опечатку.
Отчёт исследователей Socket показывает, что вредоносный модуль был создан ещё 8 ноября 2017 года. За шесть лет вышло восемь версий с тегами. Первые семь из них не содержали опасного кода и просто копировали исходники оригинальной библиотеки. Восьмая версия v1.3.3, опубликованная 19 августа 2023 года, получила дополнительную функцию init(), которая запускает цикл управления и связи (C2) с использованием DNS-записей типа TXT. Вредоносная версия вышла всего через семь минут после v1.3.2, которая содержала лишь два безобидных исправления, скопированных из основного репозитория. Такой паттерн называют "доверие, затем отравление" - злоумышленник сначала показывает легитимную активность, а следом выпускает заражённую версию.
Исходный код вредоносного модуля полностью повторяет все публичные функции оригинальной библиотеки. Поэтому любой проект, который случайно использует путь github.com/shopsprint/decimal (например, из-за опечатки в go.mod или автодополнения), продолжает компилироваться, проходить тесты и корректно выполнять арифметические операции. Вредоносное поведение запускается в отдельной легковесной нити (goroutine) и никак не проявляет себя при обычной работе - ни сообщений об ошибках, ни сетевых шумов, заметных разработчику.
Как именно работает бэкдор? В файл decimal.go добавлены три импорта: net, os/exec и time. Ни один из них не нужен для математических вычислений. Функция init(), которая выполняется при загрузке любого модуля Go, запускает бесконечный цикл. Каждые пять минут код отправляет DNS-запрос на получение TXT-записи поддомена dnslog-cdn-images[.]freemyip[.]com. Если запись возвращается, её содержимое передаётся напрямую в команду exec.Command(txt). Таким образом, злоумышленник может выполнить произвольную команду на скомпрометированной машине, просто изменив TXT-запись у своего провайдера динамического DNS. Команды не проходят через оболочку, но это не ограничивает атакующего: он может использовать уже установленные на системе программы, включая утилиты для повышения привилегий или установки пакетов.
Инфраструктура управления использует бесплатный сервис динамических DNS freemyip[.]com. Сам по себе сервис легитимен, но, по данным VirusTotal, на его поддоменах фиксировались фишинговые страницы, вредоносные узлы и командные центры. Вредоносный поддомен впервые попал в базы антивирусных компаний 7 августа 2024 года, при этом его A-запись указывает на 8.8.8.8 - адрес Google Public DNS, что является маскировкой. Реальная полезная нагрузка передаётся только через TXT-записи.
Важная особенность атаки - сохранение вредоносного модуля в кэше официального прокси-сервера Go (proxy.golang.org). Даже после того как репозиторий GitHub и учётная запись shopsprint были удалены (вероятно, самой платформой), прокси продолжает выдавать версию v1.3.3 любому разработчику, который запросит этот модуль. Это стандартное поведение для обеспечения воспроизводимости сборок в Go, но оно же позволяет бэкдору оставаться доступным для новых жертв ещё долгое время.
Любое устройство, которое импортирует данный модуль и запускает полученный бинарный файл, оказывается под контролем злоумышленника. Это могут быть рабочие станции разработчиков, сборочные фермы CI/CD и даже серверы, работающие с контейнерами. Вредоносная функция действует всё время жизни процесса, не требуя дополнительных механизмов закрепления в системе. Достаточно одного импорта - и атакующий получает возможность выполнять команды с правами этого процесса.
Период между выходом вредоносной версии (август 2023) и обнаружением (май 2025) составляет почти три года. За это время любая компания или разработчик, случайно использовавшие поддельный модуль, могли быть скомпрометированы. Исследователи рекомендуют немедленно проверить файлы go.mod и go.sum всех проектов на наличие пути github.com/shopsprint/decimal. Если он найден, зависимость нужно заменить на оригинальную github.com/shopspring/decimal, выполнить go mod tidy и пересобрать проект. Все хосты, на которых запускался такой код, следует считать скомпрометированными и провести полную ротацию учётных данных.
Специалистам по безопасности стоит добавить индикатор dnslog-cdn-images[.]freemyip[.]com в системы блокировки DNS и корреляции событий. Любой запрос TXT к этому поддомену из внутренней сети - надёжный признак заражения. Также рекомендуется проверять зависимости на наличие нехарактерных импортов вроде net, os/exec и time у библиотек, которые не должны выполнять сетевые вызовы или запускать процессы. Техника typosquat остаётся одной из самых эффективных в атаках на цепочки поставок, и данный инцидент служит очередным напоминанием о необходимости тщательно проверять каждую зависимость перед её добавлением в проект.
Индикаторы компрометации
Domains
- dnslog-cdn-images.freemyip.com
- freemyip.com
URLs
- github.com/shopsprint/decimal
MD5
- e3c6ce0440d9acd0f1cef1f0da3cdb5d
SHA1
- 2f0ee073c6f29d66188a845592029c9b52528f04
- fd26f4ca4746ee390e22043a5e19ebf2b7fcd1f9
SHA256
- 387d7ea5ca733b1e7219c943f4b461877a8df0148adfef42b1538b6c398fbb41
- dd9c0268c8944e6ddf90d4d0c81aa843785b7a9ee965faa635841ed9fc0ba086