MAATRIX / Блог / Майнер на сервере: как он попал и как его выкорчевать полностью

Майнер на сервере: как он попал и как его выкорчевать полностью

MAATRIX

Сервер вдруг начал тормозить: сайт грузится медленнее, cron-задачи опаздывают, в мониторинге CPU уже который час держится у потолка. Вы смотрите на список своих сервисов — они ничего такого не потребляют. Это один из самых частых сценариев компрометации сервера: кто-то незаметно поставил на него майнер криптовалюты и теперь тратит вашу вычислительную мощность на свою прибыль. Ниже — как это обнаружить, откуда оно берётся и, самое главное, почему простое «убить процесс» тут не работает.

Первый симптом: сервер задыхается без видимой причины

Классическая картина: нагрузка на CPU держится у 100% постоянно, а не всплесками под задачи. Если у вас обычный веб-сервер или бэкенд, для него типична пилообразная нагрузка — пики в рабочие часы, спад ночью. А тут ровная полка на максимуме сутками, независимо от времени и трафика.

Часто это подмечают не по CPU напрямую, а по косвенным признакам:

  • сайт или API стали заметно медленнее отвечать без роста реального трафика;
  • в мониторинге load average пробил число ядер и не опускается, хотя обычно у вас пилообразная нагрузка с ночными спадами;
  • вентиляторы на выделенном сервере (если он у вас физический, а не VPS) стали заметно громче — процессор реально греется;
  • в панели биллинга по CPU-часам или счётчику потребления вы видите аномалию, которой не было раньше.

Важно не путать это с обычной перегрузкой от собственных сервисов — своих легитимных процессов, которые просто плохо оптимизированы или получили всплеск трафика. Здесь же речь о ситуации, когда вы точно знаете, что ваши процессы столько не едят, а нагрузка всё равно есть.

Диагностика: находим процесс и подтверждаем, что это майнер

Первый шаг — посмотреть, кто именно ест CPU:

top

или, если стоит:

htop

Ищите процесс с аномально высоким %CPU — часто это одно ядро, загруженное на 100%, реже несколько сразу (если майнер многопоточный). Обратите внимание на имя процесса и на PID.

Дальше — то же самое, но отсортированное и без интерактивного режима, удобно для логов и скриптов:

ps aux --sort=-%cpu | head -20

Смотрите на колонку COMMAND и %CPU. Если видите процесс с именем вроде kswapd0, kthreadd, [kworker] — это может быть легитимный процесс ядра (они действительно так называются и обычно в квадратных скобках), а может быть маскировка под него. Отличить одно от другого можно так:

ps -ef | grep <PID>
cat /proc/<PID>/status

Настоящие процессы ядра всегда имеют PPID (родительский процесс) равный 2 (kthreadd), запускаются от root и у них нет исполняемого файла на диске — они не читаемы через /proc/<PID>/exe. А вот у процесса-самозванца обычно есть реальный бинарник, который можно найти:

ls -la /proc/<PID>/exe

Если команда возвращает путь вроде /proc/1234/exe -> /tmp/.X11-unix/.rsync/kworker или что-то в /var/tmp, /dev/shm, скрытую папку с точкой в начале имени — это почти наверняка не системный процесс, а нечто, что туда положили и запустили. Легитимные системные бинарники живут в /usr/bin, /usr/sbin, /bin и т.п., а не во временных директориях с правами на запись всем пользователям.

Второй важный признак — сетевые соединения. Майнер обязан куда-то отправлять результаты вычислений — на пул. Смотрим исходящие соединения по процессам:

ss -tnp

или, если утилита ещё используется в вашем дистрибутиве:

netstat -tnp

Ищите постоянное соединение, которое держится подолгу (не разовый запрос), идёт на незнакомый вам внешний IP и не привязано ни к одному вашему сервису. Майнинг-пулы обычно работают по протоколу stratum — если у вас есть возможность заглянуть глубже в трафик (например, через tcpdump на короткое окно), характерные текстовые заголовки протокола в исходящих пакетах — ещё один косвенный, но весомый признак. Не полагайтесь на конкретный номер порта как на однозначный маркер — пулы используют разные порты, и на этот признак нельзя опираться в одиночку.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Как майнер прячется от top и netstat

Простые версии просто называют себя как-нибудь незаметно — apache2, systemd-worker, .cache. Более настойчивые идут дальше:

  • периодически переименовывают себя — если вы запускаете top раз, видите один процесс, а через минуту имя уже другое;
  • используют руткит-модули, которые подменяют вывод ps, top и ls, скрывая свой процесс и файлы из обычного листинга — в этом случае стандартные команды вообще ничего не покажут, и нужен просмотр /proc напрямую (ls /proc | grep -E '^[0-9]+$' и сверка каждого PID вручную) или загрузка с live-образа для анализа диска в оффлайне;
  • распределяют нагрузку, специально ограничивая себя не на 100%, а на 60-80% CPU, чтобы не привлекать внимание слишком очевидной аномалией — эти экземпляры обнаружить сложнее, помогает только регулярный мониторинг baseline-нагрузки вашего сервера, чтобы видеть отклонение от привычной картины.

Если стандартные ps/top показывают чистую картину, а суммарная загрузка CPU (например, по /proc/stat или через mpstat) не сходится с тем, что показывают процессы — это сигнал, что часть процессов от вас скрыта, и нужен более глубокий анализ, вплоть до загрузки с внешнего носителя.

Откуда он взялся: три типичных сценария заражения

Майнер сам себя не устанавливает — кто-то получил доступ к серверу. Три сценария встречаются чаще всего:

1. Подобранный или слабый пароль SSH. Боты сканируют весь диапазон IPv4 постоянно и перебирают пароли для root и типовых логинов. Если у вас разрешён вход по паролю и пароль не абсолютно случайный — рано или поздно его подберут. Это самый массовый вектор для VPS без всякой конкретной цели — атакующему всё равно, чей это сервер, лишь бы зашёл.

2. Уязвимость в веб-приложении или панели управления. Устаревшая CMS, незапатченный плагин, открытая наружу админ-панель без ограничения по IP, уязвимость в самописном API — через любую дыру, дающую выполнение кода, можно закинуть загрузчик майнера. Это касается и популярных CMS вроде WordPress, и самописных панелей — принцип один и тот же: неисправленная уязвимость даёт возможность выполнить произвольный код.

3. Скомпрометированный или вредоносный Docker-образ. Если вы (или скрипт деплоя) тянете образ из непроверенного источника — из чужого репозитория на Docker Hub без верификации, из форка с изменёнными слоями — в нём может быть встроен майнер, который запускается автоматически при старте контейнера. Он использует ресурсы хоста через тот же механизм, что и любой контейнер, и снаружи выглядит как «ваш собственный» процесс, пока вы не проверите, что именно внутри образа. Общие принципы безопасной работы с контейнерами разобраны в статье про безопасность Docker.

Во всех трёх случаях итог один: у атакующего было (или всё ещё есть) выполнение произвольных команд на вашем сервере — а майнер это просто то, что он решил на этом заработать, потому что это не требует дальнейшего внимания с его стороны и монетизируется само.

Почему просто убить процесс не работает

Первая реакция — сделать kill -9 <PID> и забыть. Это не решение, а в лучшем случае временная передышка на несколько минут. Причины:

  • Автозапуск через cron. Проверьте crontab -l для всех пользователей (for u in $(cut -f1 -d: /etc/passwd); do echo "== $u =="; crontab -u $u -l 2>/dev/null; done) и системные /etc/cron.d/, /etc/cron.daily/ — майнеры часто добавляют себе задачу перезапуска каждые несколько минут.
  • Автозапуск через systemd. Проверьте systemctl list-units --type=service и systemctl list-unit-files на подозрительные unit-файлы с обобщёнными именами — вредоносный сервис пропишет себя в автозагрузку и будет подниматься при каждой перезагрузке.
  • Самовосстановление. Более продвинутые версии держат сторожевой процесс, который следит за основным и перезапускает его, если тот убит или пропал файл. Убили один PID — через секунду появляется новый.
  • Скрытые копии на диске. Файл могли положить в несколько мест сразу, с разными именами, плюс прописать в ~/.bashrc или /etc/profile.d/ команду на запуск при входе в шелл.
  • Изменённые SSH-ключи или новые пользователи. Если доступ был получен через SSH, атакующий почти наверняка добавил свой публичный ключ в ~/.ssh/authorized_keys или создал дополнительного пользователя с sudo — это его запасной вход, даже если вы поменяете пароль основного аккаунта.

Проблема в том, что вы не можете быть уверены, что нашли *всё*. Руткит мог подменить системные утилиты, бэкдор может ждать неделями без активности, а способ проникновения (та самая уязвимость или пароль) остаётся открытым, если вы его не закрыли. Чистка вручную — это гонка с неизвестным количеством закладок, и вы никогда не знаете, выиграли вы её или нет.

Единственное надёжное решение: переустановка с нуля

Если сервер скомпрометирован, правильный подход — не лечение, а замена. Это не паранойя, а экономия времени: попытки «долечить» систему с сомнительной целостностью занимают часто больше времени, чем чистая переустановка, и не дают гарантии результата.

Порядок действий:

  1. Заберите с сервера только то, что проверено. Базы данных, файлы приложения, конфиги — но не бинарники и не системные файлы целиком. Перед восстановлением бэкапа проверьте даты его создания — если компрометация произошла давно, в бэкапе тоже может быть закладка. Если у вас есть автоматический бэкап через borgbackup, restic или аналоги — сверьте, что последняя чистая копия действительно предшествует моменту заражения.
  2. Переустановите ОС полностью — через панель управления хостинга (переустановка обычно доступна за пару кликов) или полную реинсталляцию, если сервер выделенный. Не накатывайте образ системы поверх старого диска — используйте чистую установку дистрибутива.
  3. Смените все пароли и ключи без исключений: root, все дополнительные учётные записи, пароли баз данных, API-ключи приложений, которые теоретически могли быть прочитаны с диска. Считайте скомпрометированным всё, что физически лежало на сервере в открытом виде.
  4. Настройте доступ заново с нуля, а не восстановлением старого authorized_keys — сгенерируйте новую пару SSH-ключей и добавьте только её.
  5. Разверните сервисы из проверенных источников — если использовали Docker-образы, пересоберите их из официальных или проверенных репозиториев, не копируйте старые локальные образы без проверки.

Общий пошаговый план действий при компрометации сервера, не только для случая с майнером, разобран в статье взломали сервер — пошаговый план.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли обойтись без переустановки, если я нашёл и удалил файл майнера вручную?

Технически можно, но это риск: вы не можете быть уверены, что нашли все точки закрепления и что вектор входа закрыт. Если сервер важен для бизнеса, переустановка — единственный способ гарантированно исключить остаточный доступ у атакующего.

Как понять, что переустановка вообще нужна, а не просто высокая нагрузка от легитимного процесса?

Проверьте /proc/<PID>/exe на путь исполняемого файла и сравните с ожидаемым расположением ваших сервисов. Если процесс запущен из /tmp, /dev/shm, скрытой директории или у него подозрительное сетевое соединение, которое не относится ни к одному вашему сервису — это компрометация, а не легитимная нагрузка.

Майнер вообще опасен, кроме того что жрёт CPU?

Да. Сам факт, что кто-то смог запустить произвольный код на вашем сервере, означает, что он мог украсть данные, пароли из конфигов, ключи доступа к другим сервисам — майнер просто самая заметная часть возможного ущерба, а не единственная.

Что делать в первую очередь, если сервер продакшн и его нельзя просто выключить?

Сначала снимите резервную копию критичных данных (баз, файлов приложения) на внешнее хранилище, изолируйте сервер от сети настолько, насколько возможно (закройте лишние порты в файрволе), и начинайте разворачивать замену параллельно, переключаясь на неё сразу по готовности — а не чинить заражённый сервер в проде.

Как убедиться, что после переустановки заражение не вернётся тем же путём?

Закройте именно тот вектор, через который зашли в первый раз — смените пароли на строгие ключи, отключите вход по паролю в SSH, обновите или замените уязвимое приложение, проверяйте источники Docker-образов. Если не знаете, каким путём зашли — закрывайте все три сразу.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →