- PVSM.RU - https://www.pvsm.ru -
16 июня 2026 года исследователи Checkmarx изучили [1] кампанию ChainVeil, использовавшую npm-пакеты для распространения многоступенчатых JavaScript-загрузчиков. И как раз недавно одному из моих знакомых (не)посчастливилось получить один из ранее неизвестных экземпляров.
Репозиторий с AI-агентом ему посоветовал... AI-агент. Да, отправной точкой заражения стала рекомендация от AI-помощника, а после клонирования репозитория и локального запуска антивирус прервал выполнение и классифицировал обнаруженный объект как:
Trojan.Script.Agent.mlgj
На первый взгляд ситуация выглядела довольно банально: ложное срабатывание, случайно попавший в репозиторий артефакт или очередной обфусцированный JavaScript-файл. Но я решил, что было бы интересно изучить вредоносный код, учитывая то, что Kaspersky не присвоил ему конкретное семейство.
Первым делом я решил заглянуть в сам репозиторий: узнать кто автор, когда и кем был внедрен код. Но оказалось, что автор не новичок на платформе: 320 репозиториев, 50 подписчиков и много данных в поле О себе. Но об истории Git'а и самом репозитории чуть позднее. Перейдем непосредственно к коду!
В самом начале я упомянул кампанию Chainveil не просто так. Если присмотреться к коду, можно заметить первые совпадения артефактов кампании.
Во-первых, идентификатор: у кампании в начале обфусцированного вредоносного блока кода присутствовало объявление глобального значения:
global['!']='9-0554-3'
В ходе анализа, эта строка приняла следующий вид:
A9-0554-3
Если вы прочитаете статью Checkmarx указанную выше, то в самом конце сможете найти обнаруженные ими идентификаторы кампании, но все они имеют первый блок A6, в то время как я наткнулся на A9. Также стоит обратить внимание: источник не является npm-пакетом, это самостоятельный ИИ-инструмент на Python использующий JS для Web части приложения.
Продолжив анализ я еще больше убедился в сходстве с ChainVeil, образец использовал абсолютно те же самые техники, что указаны в статье от Checkmarx.
Многоступенчатая обфускация JS-кода.
Использование данных TRON, Aptos и BSC транзакций в качестве источника полезной нагрузки.
Адреса C2-инфраструктуры полностью совпали с теми, что опубликовали Checkmarx.
Код является нестандартным по архитектуре работы loader'ом. Он использует несколько blockchain сервисов для получения полезной нагрузки.
Через TRON получает последнюю исходящую транзакцию аккаунта злоумышленника.
Использует Aptos, если через TRON получить данные не удалось
Извлеченное значение после UTF-8 декодирования и разворота строки используется как идентификатор транзакции BSC, откуда, из поля input, извлекается закодированная строка.
Извлеченная из данных BSC транзакции строка проходит через несколько операций:
Извлечение необходимых частей по разделителю ?.?
XOR декодирование с ключом, находящимся в коде
Для деобфускации строк код использует функцию перестановки _$af163278 с фиксированным значением seed, так что мне удалось полностью восстановить используемые строки:
[0]: "r"
[1]: "_V"
[2]: "A"
[3]: "!"
[4]: "end"
[5]: "error"
[6]: "on"
[7]: ""
[8]: "data"
[9]: "parse"
[10]: "JSON"
[11]: "get"
[12]: "https"
[13]: "Promise"
[14]: "2.0"
[15]: "stringify"
[16]: "POST"
[17]: "request"
[18]: "write"
[19]: "join"
[20]: "reverse"
[21]: "split"
[22]: "utf8"
[23]: "toString"
[24]: "raw_data"
[25]: "/transactions?only_confirmed=true&only_from=true&limit=1"
[26]: "hex"
[27]: "from"
[28]: "Buffer"
[29]: "arguments"
[30]: "payload"
[31]: "/transactions?limit=1"
[32]: "?.?"
[33]: "substring"
[34]: "input"
[35]: "result"
[36]: "eth_getTransactionByHash"
[37]: "bsc-dataseed[.]binance[.]org"
[38]: "bsc-rpc[.]publicnode[.]com"
[39]: "length"
[40]: "charCodeAt"
[41]: "fromCharCode"
[42]: "String"
[43]: "getTime"
[44]: "Date"
[45]: "_p_t"
[46]: "2[...C"
[47]: "TMfK...7mAP"
[48]: "0xbe03...11e"
[49]: "m...]"
[50]: "TXf...zcG"
[51]: "0x3f0...ce3"
[52]: "node"
[53]: "-e"
[54]: "';"
[55]: "ignore"
[56]: "spawn"
[57]: "child_process"
В конечном итоге вся цепочка сводится к коду с RAT-функционалом, а поскольку структура загрузчика, механизм получения полезной нагрузки и конечный RAT-компонент соответствуют описанию Checkmarx, я не стал повторно подробно разбирать уже опубликованную ими финальную стадию. Поэтому сразу перейдем к главному вопросу статьи.
Чтобы понять, как вредоносный файл попал к конечному пользователю, пришлось исследовать историю Git-коммитов зараженного репозитория inbox-ai.
На первый взгляд, владелец аккаунта выглядит как обычный разработчик: более 300 репозиториев и активный профиль. Однако история изменений ключевого файла navigation.js раскрывает то, как именно вредоносный код попал в кодовую базу.
Первое появление файла зафиксировано в коммите a3940ca (ноябрь 2025 года):
commit a3940ca
Author: Lite Object <...@gmail.com>
Date: Sat Nov 8 09:26:42 2025 -0600
feat: Implement user preferences management with CRUD operations
and integrate into settings page
В этот момент navigation.js был добавлен как чистый, легитимный скрипт. Вредоносный код появился значительно позже - 29 марта 2026 года в процессе слияния веток в коммите a40301a:
Commit: a40301a8a5b3a53d13c6c784b72ef5e1a192669e
Parents: 080ef0f, 5499bda
Message: Merge pull request #20 from .../ui-ux-improvements
В хвост файла был добавлен обфусцированный JS-однострочник, причем при осмотре кода, я заметил, что изначально его не видно из-за большого количества пробелов.
Но если мы повнимательнее присмотримся к ползунку то заметим, что длина строк основного кода не занимает столько места, и найдем вредоносный блок:
Самое интересное, что код как был добавлен автором в марте, так до сих пор там и лежит. А из истории коммитов мы можем выстроить цепочку изменений файла.
Таким же образом вредоносный код был внедрен в файл calendar-rail.js 30 марта 2026 года 03:44:18 UTC.
Можно предположить несколько сценариев: компрометацию учетной записи разработчика, компрометацию рабочего окружения или использование техники, напоминающей EvilMerge. Однако остается открытым вопрос: почему вредоносный код оставался в репозитории более пяти месяцев и не был удален?
При самостоятельном анализе связанного BSC-адреса мне удалось обнаружить транзакцию от 7 февраля 2025 года, содержащую данные, которые по структуре соответствуют наблюдаемой цепочке доставки. Если данная транзакция действительно относится к той же инфраструктуре, это сдвигает предполагаемую дату начала ее активности еще дальше - за пределы периода, описанного в публичном исследовании Checkmarx.
Анализ временных интервалов между транзакциями показал, что полезная нагрузка обновлялась регулярно - примерно каждые 2-3 дня. При этом в отдельные периоды наблюдались серии быстрых обновлений, когда несколько новых версий публиковались в течение нескольких минут. Подобное поведение может свидетельствовать об использовании автоматизированного механизма публикации полезной нагрузки.
Весной 2026 года активность инфраструктуры резко возрастает. Появляются новые кошельки, увеличивается частота ротации полезной нагрузки, а вскоре после этого начинается распространение вредоносных npm-пакетов.
Наиболее интересным выглядит временное совпадение между расширением инфраструктуры кампании и заражением исследуемого репозитория.
Если проследить TRON и BSC транзакции, можно заметить следующее:
|
Событие |
Время |
|---|---|
|
Merge-коммит |
29.03.2026 |
|
Коммит |
30.03.26 |
|
TRON-транзакция |
31.03.2026 14:20:57 UTC |
|
BSC-транзакция |
31.03.2026 14:20:42 UTC |
|
Появление первых npm-пакетов |
18.05.26 |
Важной особенностью является то, что BSC-транзакция произошла на 15 секунд раньше TRON-транзакции. Это объясняется архитектурой загрузчика. Из данных TRON-транзакции извлекается идентификатор транзакции BSC, содержащей следующую стадию полезной нагрузки.
Фактически злоумышленники использовали TRON в качестве промежуточного уровня, а BSC - в качестве хранилища следующего этапа загрузчика.
Вредоносный код был внедрен в репозиторий 29 марта 2026 года, тогда как первые npm-пакеты, описанные Checkmarx, появились только 18 мая 2026 года. Это может свидетельствовать о том, что npm никогда не был единственным каналом распространения ChainVeil.
Таким образом, исследуемый образец демонстрирует практически полное совпадение с ранее описанной архитектурой ChainVeil: от многоступенчатой обфускации и блокчейн-механизма доставки полезной нагрузки до используемой C2-инфраструктуры и конечного RAT-компонента. Checkmarx также описывает именно трехблокчейнную схему TRON/Aptos - BSC и связывает ее с кампанией SuccessKey.
При этом исследованный экземпляр отличается от известных npm-образцов как минимум каналом доставки и идентификатором кампании: вместо A6-* используется A9-0554-3. В публичном исследовании Checkmarx именно A6-* используется как общий маркер семейства известных npm-пакетов.
История Git позволяет установить точку появления вредоносного кода в исследуемом проекте и проследить его дальнейшее распространение в другие JavaScript-файлы. Однако она не позволяет установить, кто именно контролировал учетную запись разработчика в момент внесения изменений.
Автор: ChikoiSan
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/investigation/456658
Ссылки в тексте:
[1] изучили: https://checkmarx.com/zero-post/chainveil-a-malicious-npm-supply-chain-attack-by-successkey/
[2] Источник: https://habr.com/ru/articles/1070914/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1070914
Нажмите здесь для печати.