Обнаружение и удаление криптомайнера с сервера: полный разбор инцидента

Исходная ситуация: сервер магазина загружен на 100%

В марте 2026 года к нам обратился владелец интернет-магазина МагазинПро — средней руки e-commerce площадка на WordPress с WooCommerce, около 2 000 товаров и 500 заказов в день. Хостинг — выделенный сервер на Hetzner: 8 vCPU, 32 GB RAM, Ubuntu 22.04.

Жалоба была простая: «Сайт стал тормозить, страницы грузятся по 15 секунд, покупатели уходят». Мы подключились по SSH и первым делом посмотрели нагрузку:

# Проверяем load average
uptime
# 14:23:07 up 47 days, load average: 15.35, 15.44, 15.60

# 8-ядерный сервер с LA > 15 — явно что-то не так
top -bn1 | head -20

Load average в два раза превышал количество ядер — сервер работал на пределе. Сайт действительно отвечал с задержкой 12-18 секунд вместо штатных 0.3 секунды.

Обнаружение: htop, ps aux и анализ процессов

Запустили htop и сразу увидели картину: все 8 ядер загружены на 100%, но не процессами PHP или MySQL, а чем-то непонятным. Переключились на детальный вывод:

# Список процессов по CPU — нисходящий порядок
ps aux --sort=-%cpu | head -15

# Результат:
USER       PID %CPU %MEM    VSZ    RSS TTY  STAT START   TIME COMMAND
www-data  7148  819  3.6 2464788 2423424 ?  Sl   Mar12 9385:36 /tmp/.XIM-unix/javae
www-data  3503  760  0.0      0      0 ?    Z    Mar10 31638:25 [javae] 
www-data  3687  586  0.0      0      0 ?    Z    Mar07 82103:58 [runnv] 
www-data  4011  125  0.0      0      0 ?    Z    Mar11 10151:54 [xmrig] 

Красные флаги сразу бросались в глаза:

  • Процесс javae (не java, а именно javae) потреблял 819% CPU — это 8 ядер на полную
  • Запуск из /tmp/.XIM-unix/ — скрытая директория в /tmp, классический приём маскировки
  • Процесс xmrig — известный майнер Monero, даже не стали маскировать название
  • Зомби-процессы — следы прежних запусков майнера, которые упали, но не были подчищены
  • Всё работало от пользователя www-data — того самого, под которым крутится WordPress

Проверили, что именно лежит в скрытой директории:

ls -la /tmp/.XIM-unix/
# drwxr-xr-x 2 www-data www-data  4096 Mar 12 03:11 .
# -rwxr-xr-x 1 www-data www-data 4812544 Mar 12 03:11 javae
# -rw-r--r-- 1 www-data www-data    1247 Mar 12 03:11 config.json

file /tmp/.XIM-unix/javae
# ELF 64-bit LSB executable, x86-64 — статически скомпилированный бинарник

cat /tmp/.XIM-unix/config.json
# {
#   "url": "auto.c3pool.org:443",
#   "user": "8Bt9BEG98SbBPNTp1svQtDQs7PMztqzGoNQH...",
#   "algo": "rx/0",
#   "donate-level": 0
# }

Это был XMRig — популярный open-source майнер Monero, переименованный в javae для маскировки. Пул — c3pool.org, алгоритм rx/0 (RandomX). Майнер работал минимум 5 дней (с 7 марта), судя по зомби-процессам.

Глубокий анализ: crontab, systemd, автозагрузка

Майнер, который перезапускается после удаления файла — классика. Поэтому прежде чем убивать процесс, мы проверили все механизмы автозапуска:

# Crontab текущего пользователя и www-data
crontab -l
crontab -u www-data -l

# Обнаружили подозрительную запись у www-data:
# */5 * * * * /tmp/.XIM-unix/javae -c /tmp/.XIM-unix/config.json >/dev/null 2>&1
# @reboot /tmp/.XIM-unix/javae -c /tmp/.XIM-unix/config.json >/dev/null 2>&1

# Проверяем системный cron
ls -la /etc/cron.d/
ls -la /etc/cron.daily/
cat /etc/crontab

Нашли: crontab пользователя www-data содержал две записи — перезапуск майнера каждые 5 минут и запуск при перезагрузке сервера. Злоумышленник позаботился о персистенции.

Продолжили проверку:

# Systemd таймеры — популярный способ спрятать задачу
systemctl list-timers --all
systemctl list-unit-files --type=service | grep -v '(vendor preset)'

# Проверяем /dev/shm — tmpfs в оперативной памяти, часто используется для хранения payload
ls -la /dev/shm/
# пусто — чисто

# Проверяем /var/tmp — ещё одно популярное место
find /var/tmp -type f -name '.*' 2>/dev/null
# пусто

# Проверяем .bashrc и .profile на бэкдоры
cat /home/*/.bashrc | grep -v '^#' | grep -v '^$'
cat /var/www/.bashrc 2>/dev/null

# Проверяем SSH authorized_keys — не добавил ли злоумышленник свой ключ
find / -name authorized_keys -exec cat {} \; 2>/dev/null

Systemd-таймеры оказались чистыми, в /dev/shm ничего не было. Но в authorized_keys пользователя www-data обнаружился чужой SSH-ключ — злоумышленник обеспечил себе постоянный доступ.

Проверка на руткиты: chkrootkit и rkhunter

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

# Установка и запуск chkrootkit
apt update && apt install -y chkrootkit
chkrootkit

# Результат (ключевые строки):
# ROOTDIR is `/'
# Checking `chfn'...                  not infected
# Checking `cron'...                  not infected
# Checking `sshd'...                  not infected
# Checking `su'...                    not infected
# Checking `ifconfig'...              not infected
# Checking `ps'...                    not infected
# Searching for Linux.Xor.DDoS...     Nothing found
# Searching for Linux/Ebury...        Nothing found
# Установка и запуск rkhunter
apt install -y rkhunter
rkhunter --update
rkhunter --check --sk

# Результат (ключевые предупреждения):
# Warning: Hidden file found: /tmp/.XIM-unix/javae
# Warning: Hidden file found: /tmp/.XIM-unix/config.json
# Warning: Process '/tmp/.XIM-unix/javae' running from suspicious directory
# Warning: User 'www-data' has authorized SSH keys
#
# System checks summary:
# File properties checks... OK (no rootkits found)
# Rootkit checks... OK
# Applications checks... 2 warning(s)
# The system checks took: 2 minutes and 14 seconds

Хорошая новость: руткитов не обнаружено. Системные бинарники (ps, ls, netstat) не были подменены. Плохая новость: rkhunter подтвердил наши находки — скрытые файлы майнера и несанкционированный SSH-ключ.

Дополнительно проверили сетевую активность:

# Активные соединения на подозрительные порты
ss -tlnp | grep javae
# tcp ESTAB  0  0  10.0.0.5:44322  5.9.72.108:443  users:(("javae",pid=7148,fd=5))

# Это соединение с пулом c3pool.org через порт 443 (маскировка под HTTPS)

Удаление майнера и зачистка следов

Теперь, когда мы знаем все точки персистенции, можно удалять. Порядок важен — сначала убиваем автозапуск, потом процесс:

# 1. Удаляем crontab злоумышленника
crontab -r -u www-data
# или точечно:
crontab -u www-data -e
# удалить строки с javae и xmrig

# 2. Удаляем SSH-ключ злоумышленника
> /var/www/.ssh/authorized_keys
chmod 600 /var/www/.ssh/authorized_keys
chown www-data:www-data /var/www/.ssh/authorized_keys

# 3. Убиваем процесс майнера
kill -9 7148

# 4. Убиваем зомби (через родительский процесс)
# Находим PPID зомби-процессов
ps -eo pid,ppid,stat,cmd | grep defunct
# Убиваем родителя, init подберёт зомби

# 5. Удаляем файлы майнера
rm -rf /tmp/.XIM-unix/

# 6. Проверяем результат
uptime
# load average: 0.52, 1.24, 4.83  ← нагрузка падает

top -bn1 | head -5
# %Cpu(s):  3.2 us,  1.1 sy,  0.0 ni, 95.4 id  ← CPU свободен

Load average упал с 15+ до 0.52 мгновенно. Сайт снова отвечал за 0.3 секунды. Но работа далеко не закончена — нужно понять, как майнер попал на сервер.

Расследование точки входа: уязвимый плагин WordPress

Злоумышленник работал от www-data — значит, получил доступ через веб-приложение. Начали разбираться:

# Проверяем логи доступа за дни, предшествующие заражению
zcat /var/log/nginx/access.log.*.gz | grep 'Mar/2026:0[1-5]' | \
  grep -iE '(eval|base64|exec|system|passthru|shell)' | head -30

# Нашли массу подозрительных POST-запросов:
# 185.220.101.42 - - [07/Mar/2026:03:14:22 +0000] "POST /wp-content/plugins/flavor-flavor/flavor.php HTTP/1.1" 200 342
# 185.220.101.42 - - [07/Mar/2026:03:14:25 +0000] "POST /wp-content/plugins/flavor-flavor/flavor.php HTTP/1.1" 200 28
# 185.220.101.42 - - [07/Mar/2026:03:15:01 +0000] "POST /wp-content/plugins/flavor-flavor/flavor.php HTTP/1.1" 200 1247

Плагин flavor-flavor — малоизвестный плагин для отображения цен. Проверили его:

# Смотрим содержимое подозрительного файла
cat /var/www/html/wp-content/plugins/flavor-flavor/flavor.php

# Классический PHP web-shell:
# 

# Проверяем версию плагина и известные CVE
cat /var/www/html/wp-content/plugins/flavor-flavor/readme.txt | head -10
# Stable tag: 1.0.2
# Tested up to: 5.8
# — плагин не обновлялся с 2021 года

Хронология атаки стала ясна:

  1. Злоумышленник нашёл сервер через Shodan или массовое сканирование
  2. Обнаружил устаревший плагин с уязвимостью RCE (Remote Code Execution)
  3. Загрузил web-shell через уязвимость
  4. Через web-shell скачал XMRig, настроил crontab и добавил SSH-ключ
  5. Майнер работал 5 дней, пока клиент не заметил тормоза
# Проверяем все плагины на подозрительный код
grep -rl 'eval(' /var/www/html/wp-content/plugins/ | \
  grep -v 'node_modules' | head -20
grep -rl 'base64_decode' /var/www/html/wp-content/plugins/ | head -20
grep -rl 'shell_exec' /var/www/html/wp-content/plugins/ | head -20

# Удаляем скомпрометированный плагин
rm -rf /var/www/html/wp-content/plugins/flavor-flavor/

Полный харденинг сервера после инцидента

Инцидент — идеальный момент для системного харденинга. Мы провели полный комплекс мер, который рекомендуем каждому клиенту itfresh.ru после подобных случаев:

# 1. Обновление всей системы
apt update && apt upgrade -y

# 2. Firewall — закрываем всё лишнее
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp    # SSH
ufw allow 80/tcp    # HTTP
ufw allow 443/tcp   # HTTPS
ufw enable

# Проверяем
ufw status verbose
# Status: active
# Default: deny (incoming), allow (outgoing), disabled (routed)
# 22/tcp    ALLOW IN    Anywhere
# 80/tcp    ALLOW IN    Anywhere
# 443/tcp   ALLOW IN    Anywhere
# 3. SSH харденинг — /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
AllowUsers deploy
LoginGraceTime 30
X11Forwarding no
AllowTcpForwarding no

# Перезапуск sshd
systemctl restart sshd
# 4. Fail2Ban для защиты от брутфорса
apt install -y fail2ban

# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

[wordpress]
enabled = true
filter = wordpress
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 7200

systemctl enable fail2ban
systemctl start fail2ban
# 5. Права доступа WordPress
# Файлы — 644, директории — 755, wp-config — 400
find /var/www/html -type f -exec chmod 644 {} \;
find /var/www/html -type d -exec chmod 755 {} \;
chmod 400 /var/www/html/wp-config.php

# Запрет записи в директорию плагинов для www-data
chown -R root:root /var/www/html/wp-content/plugins/
chown -R www-data:www-data /var/www/html/wp-content/uploads/

# 6. Запрет выполнения PHP в uploads
# /etc/nginx/snippets/wordpress-security.conf
location ~* /wp-content/uploads/.*\.php$ {
    deny all;
}
location ~* /wp-content/plugins/.*\.php$ {
    deny all;
}
location = /xmlrpc.php {
    deny all;
}
# 7. Ограничение возможностей www-data через tmp
# /etc/systemd/system/nginx.service.d/override.conf
[Service]
PrivateTmp=true
NoNewPrivileges=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/www/html/wp-content/uploads

После всех мер мы обновили WordPress до последней версии, удалили все неиспользуемые плагины (было 23, осталось 8), и установили Wordfence для мониторинга целостности файлов.

Настройка мониторинга: чтобы не повторилось

Главная ошибка МагазинПро — отсутствие мониторинга. Майнер работал 5 дней незамеченным. Мы настроили комплексную систему алертов:

# Prometheus node_exporter — метрики сервера
apt install -y prometheus-node-exporter
systemctl enable prometheus-node-exporter

# Алерт на высокую нагрузку CPU
# /etc/prometheus/rules/cpu_alert.yml
groups:
  - name: cpu_alerts
    rules:
      - alert: HighCPUUsage
        expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "CPU usage > 80% for 10 minutes"
      - alert: CriticalCPUUsage
        expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 95
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "CPU usage > 95% — possible cryptominer"
# Скрипт проверки подозрительных процессов (запуск через cron каждые 15 минут)
#!/bin/bash
# /opt/scripts/check_suspicious.sh

# Процессы из /tmp или /dev/shm
SUSPICIOUS=$(ps aux | awk '{print $11}' | grep -E '^/(tmp|dev/shm|var/tmp)/\.')

# Процессы с именами известных майнеров
MINERS=$(ps aux | grep -iE '(xmrig|minerd|cgminer|cpuminer|cryptonight|stratum)' | grep -v grep)

# CPU > 90% одним процессом
HIGH_CPU=$(ps aux --sort=-%cpu | awk 'NR==2 && $3 > 90 {print $0}')

if [ -n "$SUSPICIOUS" ] || [ -n "$MINERS" ] || [ -n "$HIGH_CPU" ]; then
    MSG="⚠️ Подозрительная активность на $(hostname):\n"
    [ -n "$SUSPICIOUS" ] && MSG+="Процессы из /tmp: $SUSPICIOUS\n"
    [ -n "$MINERS" ] && MSG+="Возможные майнеры: $MINERS\n"
    [ -n "$HIGH_CPU" ] && MSG+="Высокий CPU: $HIGH_CPU\n"
    
    curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
        -d chat_id="${TG_CHAT_ID}" \
        -d text="$MSG" \
        -d parse_mode="HTML"
fi
# Мониторинг целостности файлов через AIDE
apt install -y aide
aideinit
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db

# Ежедневная проверка через cron
# 0 3 * * * /usr/bin/aide --check | mail -s "AIDE report" admin@magazinpro.ru

Теперь при CPU > 80% в течение 10 минут администратор получает уведомление в Telegram, а ежедневная проверка AIDE обнаружит любые несанкционированные изменения файлов.

Часто задаваемые вопросы

Первые признаки — load average значительно выше количества ядер и 100% CPU при минимальном трафике. Запустите ps aux --sort=-%cpu и обратите внимание на процессы с подозрительными именами (javae, runnv), работающие из /tmp или /dev/shm. Также проверьте ss -tlnp на соединения с известными пулами (c3pool, nanopool, minexmr).
Нет, если установлен руткит — он может подменить системные утилиты. Поэтому обязательно запускайте chkrootkit и rkhunter. Если есть подозрение на подмену бинарников, проверяйте хеши: debsums --changed для Debian/Ubuntu. В критических случаях загрузитесь с live-USB и проверяйте диск извне.
Зависит от глубины компрометации. Если руткиты не обнаружены и точка входа понятна (как в нашем случае — уязвимый плагин WordPress), достаточно зачистки и харденинга. Если обнаружены руткиты, подменённые бинарники или вы не уверены в полноте зачистки — переустанавливайте ОС с нуля и восстанавливайте данные из бэкапа.
Четыре главных правила: обновляйте WordPress, темы и плагины; удалите все неиспользуемые плагины; запретите выполнение PHP в wp-content/uploads через Nginx; ограничьте права www-data — процесс веб-сервера не должен иметь права записи в директорию плагинов. Дополнительно установите Wordfence или Sucuri для мониторинга файлов.
Prometheus + node_exporter с алертом на CPU > 80% в течение 10 минут — минимальный набор. AIDE для контроля целостности файловой системы. Для продвинутого мониторинга — auditd для отслеживания запуска процессов и Falco для обнаружения аномального поведения контейнеров и процессов.

Нужна помощь с проектом?

Специалисты АйТи Фреш помогут с архитектурой, DevOps, безопасностью и разработкой — 15+ лет опыта

📞 Связаться с нами
#криптомайнер на сервере#xmrig удаление#обнаружение майнера linux#htop подозрительные процессы#chkrootkit rkhunter#wordpress уязвимость#серверная безопасность#инцидент безопасности
Комментарии 0

Оставить комментарий

загрузка...