Майнер на сайте: как проверить без остановки
АйТи Фреш
Информационная безопасность

Как искать скрытый майнер на работающем сайте

Автор: , директор ООО «АйТи-Фреш» · · ~11 мин чтения
Скрытая утечка нагрузки на работающем сайте обнаруживается при проверке
Нагрузка — сигнал для проверки

Высокая нагрузка на сайт сама по себе не доказывает, что там майнер. Я проверяю, какой процесс расходует CPU, с чем он соединяется и какие файлы менялись, затем сохраняю журналы и копию перед очисткой. Так можно начать разбор без немедленной остановки сайта и не спутать атаку с обычной нагрузкой.

1. Что в нагрузке действительно подозрительно

Начинаю с top или htop: смотрю на процессы, пользователя, длительность работы и изменение нагрузки во времени. Ищу связь с веб-запросами: если пик появляется вместе с посещаемостью, причина может быть в обычной работе CMS, импорте, генерации страниц или неудачном запросе к базе. Если нагрузка держится и при затишье, это повод расследовать, но не доказательство майнера. У PHP-процесса не всегда видно имя конкретного файла, а имя php-fpm само по себе ничего не говорит о его добросовестности.

В условном разборе «Лагуна-М» я сперва сохраняю время наблюдения, PID, пользователя и снимок нагрузки, а затем сопоставляю их с журналом веб-сервера и планировщика. Это простое действие помогает отличить подозрительный скрипт от штатной фоновой задачи. Если вы передали сайт на аудит безопасности, попросите зафиксировать исходные признаки до изменений. Иначе расследование быстро превращается в «вчера что-то было, сегодня уже не найти».

Для просмотра командной строки процесса годится ps -p PID -o pid,user,etime,args. В PID подставляют номер процесса, а не буквальный текст PID. Вывод полезен, но не гарантирует путь к PHP-скрипту: у долгоживущего PHP-FPM обработчика командная строка может показать только управляющий процесс. Путь уточняют по журналам веб-сервера, окружению процесса и файловым событиям, если такие данные собираются.

Не отправляю kill -9 наугад. Сигнал немедленно завершает процесс и может оборвать запрос, потерять полезные данные для анализа или затронуть легитимную задачу. Сначала фиксирую доступные сведения и выясняю владельца процесса; при подтверждённой угрозе выбираю согласованное с владельцем сайта сдерживание. Если сайт обслуживает критичную операцию, заранее оцениваю влияние любого действия на пользователей. Быстрый удар по PID эффектен, но расследование от этого не становится точнее.

Сначала фиксирую признаки, потом меняю состояние системы.
Порядок действий: Что в нагрузке действительно подозрительно — схема
Порядок действий: Что в нагрузке действительно подозрительно. Открыть схему в полном размере

2. Как проверить исходящие соединения

На Linux список сокетов можно посмотреть командой ss -tunap. Параметр -p показывает связанные с сокетом процессы, если у пользователя есть необходимые права. Вывод сохраняю вместе со временем проверки. Смотрю на повторяющиеся исходящие соединения и сопоставляю их с PID, DNS-именами, конфигурацией приложения, журналами и известными интеграциями. Соединение на 80 или 443 порт не делает адрес подозрительным автоматически: там работают API, CDN, обновления и внешние сервисы.

У майнера может быть сетевое взаимодействие с пулом, но конкретный порт не является надёжным маркером. Протоколы и адреса меняются, а легитимный сайт общается с множеством внешних узлов. Поэтому в черновой статье я убрал непроверенный диапазон IP: без журналов и подтверждённой репутации адреса это не факт о заражении, а случайное обвинение. Белый список полезен лишь тогда, когда его поддерживают и понимают, какие зависимости сайта он описывает.

Если в ss виден PID, свяжите его с процессом и проверьте открытые файлы. Например, lsof -nP -p PID -i показывает сетевые файлы процесса; PID снова заменяется числом. Команды могут требовать прав администратора, а отсутствие результата не доказывает отсутствие активности: соединение могло завершиться до проверки. Для краткоживущих задач нужны журналы или инструмент наблюдения, который собирает данные постоянно.

Не блокирую адрес по принципу «не узнаю — значит вредоносный». Сначала выясняю, кому он принадлежит и какой компонент его вызвал; затем при подтверждённом риске согласую правило с владельцем сайта и проверяю, что не ломаются внешние функции. Так меньше шансов выключить собственную оплату или загрузку изображений, объявив это победой над атакой.

Неизвестный адрес — повод проверить, а не приговор.
Как искать скрытый майнер на работающем сайте — схема
Схема к статье. Открыть схему в полном размере

3. Какие файлы и признаки искать

Дальше сравниваю дерево файлов с чистой резервной копией или официальным дистрибутивом CMS и плагинов. Время изменения помогает сузить поиск, но не датирует заражение: вредоносный файл могли положить давно, а время на сервере — изменить. Пример команды для недавних PHP-файлов: find /var/www -type f -name '*.php' -mtime -7 -size +20k -print. Перед запуском замените /var/www на реальный корень сайта. Здесь -mtime -7 отбирает файлы, изменённые менее семи суток назад, а порог размера — только удобный фильтр, не признак вредоносности.

В условном примере «Лагуна-М» сравнение файлов с чистой копией и журналом изменений даёт больше пользы, чем догадка по имени .cache. Папка /tmp не является автоматически частью сайта, а /var/www/html/.cache — лишь пример возможного пути, не универсальное место заражения. Я проверяю права записи веб-пользователя, каталог загрузок, задания cron и новые учётные записи CMS. Для восстановления полезно проверить целостность резервной копии: слепое возвращение заражённой копии возвращает и проблему.

Поиск строк eval, base64_decode или shell_exec можно использовать как грубый фильтр, но эти функции встречаются и в легитимном коде, а обфускация обходится без них. Для рекурсивного поиска в PHP-файлах команда выглядит так: find /var/www -type f -name '*.php' -exec grep -nHE 'eval|base64_decode|shell_exec' {} +. Команда читает содержимое файлов и печатает совпадения; она не устанавливает вредоносность и не заменяет сравнение с доверенной версией.

Любую находку проверяю по контексту, контрольной сумме или известной чистой копии. Если файл отличается, сохраняю копию для анализа и записываю путь, владельца и время. Не удаляю подозрительное до фиксации: вместе с ним можно уничтожить подсказку о способе проникновения. И наоборот, красивое имя плагина не даёт файлу индульгенцию. Проверять нужно код, источник изменения и то, может ли атакующий записать его снова.

Совпадение с `eval` — зацепка для анализа, не вердикт.
Порядок действий: Какие файлы и признаки искать — схема
Порядок действий: Какие файлы и признаки искать. Открыть схему в полном размере

4. Что дают сканеры и чего от них не ждать

Внешний сканер видит то, что доступно снаружи: страницы, ответы сервера и известные сигнатуры. Сканер на самом сайте может видеть больше файлов, но зависит от прав, полноты правил и актуальности базы. Нулевой результат ни у одного способа не доказывает чистоту. Руководство WordPress рекомендует сочетать внешнюю и прикладную проверку; тот же практический принцип годится для других CMS, хотя конкретные плагины WordPress к ним не относятся.

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

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

База знаний подтверждает полезный порядок: искать вредоносный код не одним способом, просматривать изменения файлов, проверять чистую копию и обновлять компоненты после устранения причины. Это конкретнее, чем запускать сканер по расписанию и считать задачу закрытой. У сканера нет доступа к вашему контексту — он не знает, зачем именно сайт запускает конкретный код.

Сканер сообщает о признаках, решение требует проверки.

5. Очистка, восстановление и защита от повтора

Перед изменениями сохраняю резервную копию файлов и базы, журналы и список подозрительных объектов. Затем выясняю, как появился посторонний код: уязвимый компонент, утёкшая учётная запись, небезопасные права или другой путь. Удалить файл и оставить доступ атакующему — косметический ремонт. Рекомендации CISA по реагированию отдельно подчёркивают сохранение данных расследования и проверку резервных копий; при серьёзном инциденте не стоит начинать с перезапуска, который сотрёт часть летучих данных.

Если очистка требует замены файлов приложения или рестарта, планирую короткое окно и проверяю точные имена служб на конкретном сервере. systemctl restart nginx работает только если сервис действительно называется nginx; на другой установке может быть Apache, контейнер или иной способ запуска. Команда перезапуска не удаляет заражение и не закрывает уязвимость. Если сайт можно восстановить из проверенной чистой копии, сравниваю даты, содержимое и базу, затем обновляю компоненты до поддерживаемых версий.

После очистки обновляю CMS, темы, расширения и системные компоненты из доверенного источника, удаляю неиспользуемые модули, меняю скомпрометированные пароли и ключи, проверяю административные учётные записи. Отдельно ограничиваю запись в каталоги приложения и проверяю планировщик заданий. База знаний рекомендует обновление и повторную проверку после удаления кода; без устранения первопричины тот же сценарий может повториться. Бэкап рядом с заражённым сайтом — полезная копия до первого сбоя, но не проверенный план восстановления.

Иногда обсуждают PHP disable_functions. Это настройка php.ini, список имён разделяется запятыми, но документация PHP прямо предупреждает: директива не является достаточной мерой безопасности. Отключение exec, shell_exec, system или proc_open способно сломать приложение, а сама настройка не устраняет дыру в CMS. Я включаю её только после проверки совместимости и рассматриваю как дополнительное ограничение, а не как лечение заражения.

После восстановления проверяю страницы, формы, авторизацию и интеграции, затем наблюдаю за процессами, соединениями и изменениями файлов. Фиксирую время контрольной проверки и критерии, по которым можно снова поднять инцидент. В условной истории «Лагуна-М» финал — не строка «вирусов не найдено», а подтверждённая чистая копия, закрытый путь проникновения и повторный осмотр. Если данные показывают новую запись файлов, расследование продолжается.

Не объявляйте инцидент закрытым сразу после удаления файла.
Я помогу проверить процесс, соединения и файлы, сохранить данные для разбора и составить план очистки. Начинаем с признаков и влияния на работающий сайт. Обсудить задачу
Порядок действий: Очистка, восстановление и защита от повтора — схема
Порядок действий: Очистка, восстановление и защита от повтора. Открыть схему в полном размере

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

Высокий CPU означает, что на сайте майнер?

Нет. Это сигнал к проверке. Сопоставьте процесс с трафиком, журналами, задачами CMS и сетевыми соединениями.

Можно ли остановить подозрительный процесс командой kill -9?

Не до фиксации данных и оценки влияния. Сначала сохраните PID, время, пользователя, аргументы и доступные журналы.

Что показывает команда ss -tunap?

Сокеты и, при достаточных правах, связанные процессы. Вывод отражает состояние на момент проверки и сам по себе не доказывает заражение.

Помогает ли поиск eval и base64_decode?

Он находит часть подозрительных совпадений, но эти функции встречаются в обычном коде и могут отсутствовать в вредоносном. Сравните файл с чистой версией.

Нужно ли загружать сайт в онлайн-антивирус?

Сканер может дать дополнительную зацепку. Не передавайте архив с конфигурацией и секретами сервису, не проверив его условия обработки данных.

Столкнулись с похожей задачей? Обращайтесь — решим

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

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи