Назад к блогу

Расширение Claude Code в маркетплейсе Cursor: как вредоносная версия 2.1.313 ставила SSH-бэкдор

Расширение Claude Code в маркетплейсе Cursor: как вредоносная версия 2.1.313 ставила SSH-бэкдор

Скомпрометированная версия официального расширения Claude Code for VS Code провела в маркетплейсе Cursor около одиннадцати часов, успев заразить тысячи машин вредоносным загрузчиком, который срабатывал без всякого участия пользователя. Разбор инцидента показывает, как через подмену одного файла расширения злоумышленники внедряли SSH-ключ и разворачивали обратный туннель до своего сервера — и почему часть их шагов сорвалась из-за ошибок в собственном коде.

29 октября официальное расширение Claude Code for VS Code версии 2.1.313 провело в маркетплейсе Cursor около 11 часов — с 2:27 до 13:35 по тихоокеанскому времени — и, по оценке BleepingComputer, затронуло до 5000 разработчиков. В начале файла extension.js стоял внедрённый JavaScript-загрузчик, который исполнялся при загрузке расширения, без какого-либо взаимодействия пользователя с Claude Code. Cursor удалил релиз из маркетплейса и отозвал версии 2.1.313 из реестров NPM и VSCode.

Разбор Phorion показывает, что установка состояла из нескольких этапов: правка authorized_keys, попытка включить Remote Login, reverse SSH-туннеля и механизм автозапуска. Часть шагов на macOS и Windows не сработала из-за ошибок в самом вредоносном коде, но ключи и закрепление всё равно устанавливались.

Что именно изменилось

Вредоносный код добавлен в начало extension.js как IIFE перед минифицированным бандлом расширения. Она подключает стандартные модули Node.js (child_process, fs, os, path, http, crypto) и срабатывает, как только Node загружает файл, — до вызова обычного activate — activate. Легитимный код расширения при этом не менялся.

Первое действие — обеспечить существование ~/.ssh и дописать в ~/.ssh/authorized_keys публичный ключ Ed25519 атакующего с комментарием svc-telemetry, выставив права 0700 на каталог и 0600 на файл. Наличие записи проверяется не по самому ключу, а по подстроке комментария: если строки svc-telemetry в файле ещё нет, ключ дописывается в конец файла с переводом строки и состояние помечается как added. Если комментарий уже присутствует, ключ повторно не добавляется, а состояние помечается как present. Так повторный запуск не плодит дубликаты, но и не мешает закреплению.

Предыстория

По данным Cursor, Anthropic не разрабатывала это вредоносное расширение, но как атакующие распространили скомпрометированный пакет под именем Anthropic, компания не объяснила. Исследователи Phorion и OpenSourceMalware установили, что изменён был только extension.js: загрузчик вставлен в начало файла, остальной код расширения остался прежним. Именно поэтому вредоносный код исполнялся при загрузке модуля, а не при обращении к функциям Claude Code.

Как работал бэкдор

Включение SSH на macOS

Скрипт вызывает systemsetup -getremotelogin без повышенных привилегий и проверяет вывод регулярным выражением /Off/i, а включать Remote Login пытается только при совпадении — через sudo -n systemsetup -setremotelogin on. Здесь и заложена ошибка: без прав администратора systemsetup печатает в stdout сообщение об ошибке и завершается со статусом 0, а хелпер захватывает именно stdout. В результате проверка /Off/i даёт false, блок пропускается, и команда включения не выполняется. Скрипт фактически трактует «нет прав проверить, выключен ли SSH» как «SSH уже включён». Поэтому при запуске от обычного пользователя попытка включения не видна в телеметрии процессов. На Windows и macOS эти ошибки не дали включить SSH там, где он не работал, но ключи и закрепление всё равно устанавливались.

Reverse SSH-туннель

Reverse SSH-туннель поднимается флагом -R *:0:localhost:22: ноль просит SSH-сервер атакующего динамически выделить слушающий порт и направлять весь приходящий на него трафик обратно через туннель на localhost:22 жертвы. Флаг -N означает, что команда на удалённом сервере не выполняется — соединение лишь держит проброс открытым. Когда оператору нужен доступ, он открывает отдельную SSH-сессию через выделенный порт на своём сервере и аутентифицируется против локального SSH-демона жертвы ключом, внедрённым на первом этапе, — это даёт интерактивный шелл и передачу файлов.

Соединение идёт к 134.209.82[.]225 под пользователем tunnel на порту 22, аутентификация — встроенным незашифрованным ключом OpenSSH Ed25519 с комментарием svc-telemetry-tun. Если в системе есть autossh, используется он, иначе обычный ssh. Соединение обёрнуто в отсоединённый цикл повторов с паузой 60 секунд и проверкой через pgrep, чтобы не поднимать дубликаты туннелей.

Закрепление

На macOS создаётся пользовательский LaunchAgent ~/Library/LaunchAgents/com.apple.sysmond.plist, замаскированный под системный компонент Apple. Он запускает /bin/sh ~/.config/.smt — скрипт со встроенным приватным ключом туннеля и циклом переподключения. Агент настроен на запуск сразу при загрузке и на перезапуск при завершении, что и удерживает туннель живым. На Linux закрепление сделано через cron-запись @reboot для ~/.config/.smt.

Сбор данных о хосте

Перед установкой скрипт собирает имя хоста, имя пользователя, платформу и архитектуру ОС, домашний и текущий рабочий каталог, глобальный Git email, публичный IP и флаги статуса каждого этапа. Отдельно берутся до 40 имён переменных окружения, отобранных по регулярному выражению /KEY|TOKEN|SECRET|PASS|AWS|GCP/i. Передаются только имена, без значений: секреты не выгружаются, но оператор получает перечень того, какие облачные учётные данные и API-токены есть на машине, — чтобы понять, какие хосты приоритезировать.

Отчёт уходит HTTP POST-запросом на путь /beacon по адресам 134.209.82[.]225:8099 и 127.0.0.1:8099 с таймаутом 3000 мс. Это beacon: отправка выполняется один раз, через 1.5 секунды после начальной настройки, а ответ отбрасывается. Реальный доступ идёт через SSH-туннель. Приватный ключ туннеля при этом лежит во временном каталоге под именем .stk_ с суффиксом из первых 10 hex-символов MD5 от имени хоста и домашнего каталога; оттуда его берут ssh/autossh как identity-файл.

Почему это стало возможно

Расширения исполняются с правами IDE и пользователя, поэтому скомпрометированный бандл получает доступ к локальным файлам, исходному коду и инструментам сразу при загрузке модуля — до того, как пользователь что-то сделает в самом расширении. Инцидент иллюстрирует слабое место в цепочке поставки: пакет под именем Anthropic распространялся через маркетплейс Cursor, хотя, по словам Cursor, Anthropic его не разрабатывала, а механизм публикации под чужим именем остался необъяснённым.

Что это меняет на практике

Удаления расширения недостаточно — оно не убирает бэкдор. Для затронутой машины нужна очистка всех этапов:

  • завершить цикл повторов /bin/sh и процессы ssh/autossh, подключающиеся к 134.209.82[.]225;
  • удалить механизмы автозапуска: на macOS — выгрузить и удалить пользовательский LaunchAgent ~/Library/LaunchAgents/com.apple.sysmond.plist, который запускает /bin/sh ~/.config/.smt; на Linux — cron-запись @reboot для того же скрипта; на Windows — удалить файлы автозапуска из папки Startup. Также удалить ~/.config/.smt и ~/.config/.smtk;
  • удалить публичный ключ svc-telemetry из ~/.ssh/authorized_keys, удалить /tmp/.stk_* и проверить, что Remote Login не был включён неожиданно;
  • ротировать доступные этой учётной записи креды и токены, особенно совпадающие с фильтром KEY|TOKEN|SECRET|PASS|AWS|GCP, если SSH был включён или есть признаки входящего входа.

Для детектирования важен способ записи ключа: он дописывается напрямую, поэтому процессные правила на echo/tee, трогающие authorized_keys, не сработают — нужна телеметрия изменения файлов. На macOS признак — plist с меткой com.apple.*, записанный не-Apple процессом и запускающий /bin/sh против скрытого скрипта в домашнем каталоге. На сетевом уровне ищут ssh/autossh с пробросом -R *:0:localhost:22 и identity-файлами из /tmp/.stk_* или ~/.config/.smtk, исходящие SSH-соединения к 134.209.82[.]225 на порту 22 и HTTP POST на 134.209.82[.]225:8099.

Артефакты по платформам: каталог установленного расширения ~/.<ide>/extensions/anthropic.claude-code-2.1.313-darwin-arm64 (macOS на Apple Silicon, <ide> зависит от редактора); ~/.ssh/authorized_keys с комментарием svc-telemetry и <TMP>/.stk_<10 hex chars> — на всех платформах; ~/.config/.smt и ~/.config/.smtk — на macOS и Linux; на Windows — ~/.config/smt.cmd, ~/.config/smtk и %APPDATA%/Microsoft/Windows/Start Menu/Programs/Startup/sysmon.cmd.

Ограничения и открытые вопросы

Издание обратилось к Anthropic и Cursor с вопросами об атаке и обещало обновить материал при ответе — на момент публикации реакции не было. Неясно, зачем копия beacon отправляется на 127.0.0.1:8099: скрипт не поднимает локальный слушатель на этом порту. Остаётся и вопрос к логике macOS-этапа: проверка systemsetup -getremotelogin без повышения прав и сверка с /Off/i приводят к тому, что включение Remote Login пропускается, — то есть часть замысла на системах без работающего SSH не сработала.

Источники

Похожее