Три двери, одна открыта
Загрузка открытой модели может привести к выполнению кода через три разные двери. Первая — парсер, читающий бинарный формат, например GGUF. Именно эта поверхность атаки стоит за CVE-2024-34359, когда шаблон чата, хранившийся в файле GGUF, выполнял код через llama-cpp-python.
Вторая — формат сериализации: веса в форматах pickle, Keras и SavedModel могут содержать исполняемую логику. Это самый известный риск в безопасности машинного обучения, и для него существует больше всего инструментов. Третья — путь импорта Python, trust_remote_code=True, и именно через эту дверь действует данная кампания.
Фреймворки для развёртывания моделей уже спотыкались об эту же дверь. CVE-2026-22807 показала, что vLLM (с 0.10.1 до 0.14.0) загружал модули auto_map, не проверяя настройку trust_remote_code. Вредоносный репозиторий модели мог выполнить код при запуске сервера. Проблема исправлена в версии 0.14.0.
Цепочка выполнения
Разработчик вызывает from_pretrained() с trust_remote_code=True для того, что выглядит как небольшая модель Qwen2. В файле config.json репозитория через auto_map указаны модуль и класс, например modeling_evil2.EvilModel. Transformers скачивает указанный файл в свой кеш модулей и импортирует его.
В get_class_in_module() функция exec_module() выполняет код верхнего уровня файла до того, как getattr() вернёт запрошенный класс. Любой вызов, размещённый рядом с определением класса, срабатывает первым. В типичной сборке MENXIANGYU/qwen2-tiny импорт модуля доходит до функции _boot() раньше определения класса.
Лежащий рядом model.safetensors весит всего 42 байта и не содержит тензоров. Атака не использует ни отравленных весов, ни эксплойта pickle.
Почему сканеры молчат
Hugging Face действительно сканирует файлы репозиториев. Согласно документации, каждый файл размером меньше 2 ГБ проверяется антивирусным сканером ClamAV при каждом коммите. ClamAV сверяет файлы с сигнатурами известных вредоносных программ. Форматы весов проверяют сканеры партнёров. В документации по pickle сказано, что сканирование «не даёт стопроцентной гарантии» и что проверка безопасности — ответственность пользователя.
Обычный файл Python, указанный в auto_map, не является ни известной сигнатурой, ни сериализованной моделью. В результате никто не анализирует, что он делает. В проверках Pluto Security файл modeling_evil2.py из qwen2-tiny был признан безопасным всеми запущенными сканерами. Антивирус ничего не нашёл, а JFrog сообщил, что это не модель машинного обучения.
То же самое касалось и файлов первой волны. Формат safetensors, созданный для устранения риска выполнения кода, фигурирует в этой кампании лишь как 42-байтовая заглушка.
Первый этап: сначала — плацдарм
Полезная нагрузка записывает /tmp/.cch/svc.py — сторожевой процесс (watchdog), работающий отдельно. Его перезапускают хуки, дописанные в /root/.bashrc, /root/.profile и ~/.bashrc. Используя интерпретатор самого загрузчика модели, он каждые 120 секунд перезапускает майнер, если тот отсутствует.
Три сборки — qwen2-tiny-5, -6 и -9 — добавляют нулевой шаг. Отдельный процесс подключает оболочку к 212.32.253.3 на порт 443 или 9443 и повторяет попытку после каждого разрыва. Успешное подключение даёт злоумышленнику интерактивную оболочку с доступом к файлам и учётным данным скомпрометированного процесса.
Второй этап: майнер под видом рабочего потока ядра
Затем наступает очередь бинарного файла майнера syscore.bin. Полезная нагрузка проверяет скачанный снимок модели, затем /tmp/.cch/sync, оставшийся от предыдущего заражения. В противном случае она загружает бинарник из репозитория Hugging Face или с зеркала.
Если требуется загрузка, клиент отключает настроенные на хосте прокси. Если сеть допускает прямой исходящий трафик, загрузка минует инспекцию и журналы этого прокси. Обойти сеть, где использование прокси обязательно, она не может.
При первом запуске полезная нагрузка копирует бинарник в файловый дескриптор в памяти с помощью memfd_create. Затем запускает его через fexecve под именем [kworker/u20:1]. При этом первом запуске на диске не остаётся исполняемого файла, который мог бы проверить файловый антивирус или EDR. В списке процессов он выглядит как рабочий поток ядра.
Но маскировка себя выдаёт: в отличие от настоящего потока ядра, у процесса есть аргументы пользовательского пространства, включая логин для майнинга. Резервная копия остаётся в /tmp/.cch/sync для перезапусков сторожевым процессом.
Бинарник размером 40,6 МБ упакован UPX. Два маркера UPX! в метаданных упаковки, по смещениям 0x000000ec и 0x026be650, заменены на PEK!, поэтому upx -d отвергает файл как не упакованный UPX. Встроенный загрузчик всё равно распаковывает и запускает майнер.
Pluto Security восстановила оба маркера и распаковала файл, обнаружив peakminer. Это тот же клиент, о котором сообщали активные воркеры на кошельке первой волны. Загрузчик при запуске передаёт адреса пулов и логин krxXJ2PKQW.worker. Учётная запись оператора в самом майнере не зашита.
Третий этап: отчёты и зачистка конкурентов
Отчёты о ходе работы помещаются в локальный реестр моделей Xinference под видом названий моделей: qwen2-tiny-, за которым следует статус в кодировке base32. Оператор, имеющий доступ к открытому API, может их расшифровать.
Отметки варьируются от B (запуск выполнен) и P (бинарник на месте) до OK и OK2 (работа через путь в памяти или резервный путь на диске), DLN и NM (сбой получения или запуска), OK3 (сторожевой процесс восстановил майнинг) и H — сигнала активности с данными о загрузке GPU каждый пятый цикл сторожевого процесса.
Запустив собственный майнер, полезная нагрузка удаляет регистрации конкурирующих моделей. Она вычищает их команды запуска и завершает соответствующие процессы. Более ранние сборки искали в /proc/*/cmdline 13 известных названий конкурирующих майнеров.
Что это значит для инженеров
Кража вычислительных ресурсов для майнинга — видимая часть ущерба. Долгосрочный ущерб — это доступ. SSH-ключи, хуки в профилях оболочки, сторожевой процесс и обратные оболочки переживают майнер. Pluto Security отмечает, что завершение майнера или удаление модели не устраняет закрепление в системе.
Компания рекомендует проверять файлы .py, на которые указывает auto_map, прежде чем устанавливать флаг, и фиксировать проверенную ревизию. Она также советует запускать недоверенный код с ограниченными привилегиями, ограниченным доступом к сети и без производственных секретов, а также требовать аутентификацию для API Xinference. Чистый результат сканирования сам по себе — не повод доверять репозиторию.
Опубликовано 29 октября 2026 - 05:00 Наверх



