Два бета-релиза платформы Joyfill, предназначенной для создания цифровых форм и PDF-документов, содержали вредоносный код. Он доставлял на компьютеры пользователей троян удаленного доступа. Вслед за этим выяснилось, что инцидент является звеном более масштабной кампании, которую связывают с северокорейской группировкой PolinRider.
Описание
Кампания PolinRider известна с марта 2026 года. За несколько месяцев злоумышленники проникли в тысячи машин разработчиков. Для этого применяются поддельные собеседования, вредоносные копии открытых репозиториев, пакеты с названиями, похожими на популярные, а также специальные задания в редакторах кода. За это время группировка сменила несколько тактик, адаптируясь к мерам защиты. Цель атакующих - не только кража данных, но и получение контроля над учётными записями разработчиков. Это позволяет автоматически распространять вредоносный код через чужие репозитории и пакеты без участия человека после первичного заражения.
Как выяснили аналитики, два скомпрометированных пакета Joyfill оказались не единственными. Аналитики сопоставили индикаторы атаки с данными других исследовательских групп и обнаружили ещё 18 пакетов, включая два пакета из реестра npm и шестнадцать модулей для языка Go. Во всех случаях использовалась одинаковая инфраструктура: совпадали ключи шифрования и адреса криптовалютных кошельков в сетях Tron, Aptos и BNB Chain. Эти же признаки ранее фиксировались в мартовской кампании PolinRider. Совпадения не ограничиваются техническими деталями: злоумышленники применяли одни и те же кошельки для сбора промежуточных данных, что исключает случайное совпадение или заимствование инструментов.
Примечательно, что речь не идёт о классическом захвате аккаунтов. Злоумышленники не выбирали конкретные цели, чтобы получить доступ к популярным пакетам. Вместо этого они заражали компьютеры через социальную инженерию и вредоносные репозитории. Затем вредоносная программа сама собирала сохранённые учётные данные и использовала их для публикации новых версий от имени владельца. По оценкам, 93,5% пострадавших - индивидуальные разработчики, чьи проекты не имеют массовой популярности. Например, два npm-пакета имеют менее двух тысяч загрузок в неделю, а вредоносные бета-версии Joyfill загружали всего по два-четыре раза. Выбор падал не на значимые проекты, а на доступные машины.
Такая схема не требует участия человека после первичного заражения. Вредоносный код использует уже имеющиеся на машине ключи доступа и совершает действия, которые выглядят как обычная работа разработчика: создаёт коммиты, публикует пакеты. При этом программа может изменять метки времени в истории изменений, чтобы скрыть следы вмешательства. В результате проверка журнала изменений не выявляет ничего подозрительного. Исследователи также выяснили, что вредоносная программа способна ждать следующего действия разработчика и встраивать вредоносный код в обычную публикацию пакета.
Первый этап атаки часто выглядит безобидно. Разработчику приходит задание на собеседовании, предлагают скопировать репозиторий или установить пакет с похожим названием. После запуска кода вредоносная программа собирает данные и дальше уже действует без вмешательства человека. Это объясняет, почему пострадавшими оказываются в основном независимые разработчики: им сложнее отследить подозрительную активность в своих проектах.
В случае с Joyfill вредоносный код был встроен непосредственно в код пакета и выполнялся при его подключении, что позволяет обойти стандартные проверки безопасности. Перед активацией программа проверяла имя компьютера и оставалась скрытой в системах непрерывной интеграции. Для связи с командными серверами использовались блокчейн-сети. Загрузчик получал зашифрованные инструкции, затем запускал дополнительные модули для кражи паролей, данных браузера и криптокошельков, а также для записи нажатий клавиш.
Последствия выходят за рамки отдельного инцидента. Скомпрометированные пакеты и модули остаются доступными для скачивания даже после удаления репозиториев. В экосистеме Go работает прокси-сервер, который сохраняет копии всех версий, поэтому удаление исходного кода не убирает угрозу. Из тринадцати аккаунтов, за которыми числятся модули, восемь уже удалены или заблокированы, однако все скомпрометированные версии продолжают загружаться из кэша. Кроме того, исследователи проверили подлинность дат, указанных в версиях модулей. Сверка с архивом событий GitHub показала: из шестнадцати модулей одиннадцать имели поддельные даты. Один из них был помечен декабрём 2024 года, тогда как настоящий коммит был создан в июне 2026 года. Такая маскировка применяется, чтобы скрыть время атаки.
На данный момент конечная цель группировки остаётся неясной. Наблюдаемые действия указывают на то, что PolinRider строит сеть из скомпрометированных машин и учётных записей, которую можно использовать для последующих атак. Такая инфраструктура позволяет внедрять вредоносные изменения в широкий круг проектов, не привлекая внимания к отдельным пакетам.
Эта атака демонстрирует, как северокорейская группировка адаптирует свои методы. Ранее PolinRider была известна в основном поддельными пакетами и вредоносными репозиториями, теперь она перешла к компрометации легитимных проектов. При этом злоумышленники не тратят время на поиски ценных целей, а полагаются на автоматизацию, заражая машины разработчиков и используя их доступы. Разработчикам рекомендуется регулярно проверять свои машины на наличие вредоносного ПО, не переходить по подозрительным ссылкам и не открывать файлы из ненадёжных источников. Кроме того, стоит использовать двухфакторную аутентификацию и следить за активностью своих учётных записей.
Индикаторы компрометации
IPv4
- 23.27.13.43
IPv4 Port Combination
- 166.88.134.62:443
- 166.88.134.62:80
- 198.105.127.210:443
- 198.105.127.210:80
- 23.27.202.27:27017
- 23.27.202.27:443
Domain
- api.trongrid.io
- bsc-dataseed.binance.org
- bsc-rpc.publicnode.com
- fullnode.mainnet.aptoslabs.com
Aptos addresses
- 0xbe037400670fbf1c32364f762975908dc43eeb38759263e7dfcdabc76380811e
- 0x3f0e5781d0855fb460661ac63257376db1941b2bb522499e4757ecb3ebd5dce3
- 0x533b2dbcaeff19cd1f799234a27b578d713d8fcaa341b7501e4526106483e0b1
SHA256
- 13e9a3c41e038bf9d8fcb0831305819819e4f7f4452bc20a04b9bf2756ee22e8
- 53abf37710d6f2e35694fbe7cfaf1108127cbc001ce3e6bf994d0486cae5a0e8