Инструкция по обнаружению, изоляции, удалению майнера из контейнера и защите сервера: логи, команды, примеры, чек‑лист и рекомендации по предотвращению повторного взлома.
Введение
Майнеры (например, Kinsing, kdevtmpfsi, xmrig) — частая проблема на публично доступных серверах и контейнерах. Они чаще проникают через открытые/незащищённые сервисы (ssh с паролем, Docker API на 2375, уязвимости веб‑приложений). Важно действовать быстро и аккуратно: минимально останавливать сервисы при критичном продакшне, собрать доказательства и затем восстановить.
Что мы делали (коротко)
- Зафиксировали артефакты из контейнера:
docker cpиsha256sumбинарников. - Остановили/скопировали подозрительный контейнер и удалили майнеры из файловой системы контейнера.
- Просканировали процессы, сетевые соединения и правила iptables/DOCKER-NAT.
- Проверили настройки PHP‑FPM / nginx (fastcgi_pass) и сопоставление портов Docker.
- Ввели временные iptables/ufw‑правила, установили
fail2ban. - Пересобрали инфицированный контейнер из чистого образа, сменили порты и проверили работу.
Детальные шаги и команды (пошагово)
1) Сохранение «вещественных доказательств» и бэкап
- Скопировать бинарники из контейнера локально для анализа:
docker stop tg-crm-app
docker cp tg-crm-app:/tmp/backup_miner /root/backup_miner_from_container
ls -lah /root/backup_miner_from_container
sha256sum /root/backup_miner_from_container/*
file /root/backup_miner_from_container/*
Сохраняйте хэши (sha256) — пригодятся при расследовании и блокировке сигнатур средствами EDR/AV.
2) Поиск и уничтожение запущенных бинарников
ps aux | egrep 'kdevtmpfsi|kinsing|xmrig' -n
# удалить файлы и процессы (осторожно, убедитесь что это именно майнер)
docker exec tg-crm-app rm -f /tmp/kinsing /tmp/kdevtmpfsi /tmp/kinsing* /tmp/kdevtmpfsi*
Примечание: иногда майнеры ставят systemd/unit файлы или crontab; проверьте
systemctl,/etc/cron*,/var/spool/cron.
3) Сетевая проверка — какие порты проброшены и кто слушает
- Список контейнеров и их портов:
docker ps --format "table {{.Names}}\t{{.Ports}}"
- NAT‑правила Docker в
iptables(DNAT):
sudo iptables -t nat -L -n -v
- Общие правила и блокировки:
sudo iptables -L -n -v --line-numbers
sudo iptables -t nat -L DOCKER -n -v
sudo iptables -L DOCKER-USER -n -v --line-numbers
Если сайт не отвечает, проверьте, что php‑fpm слушает на ожидаемом интерфейсе, а nginx настраивает fastcgi на правильный хост/порт:
docker exec tg-crm-app grep -n "^listen" /usr/local/etc/php-fpm.d/www.conf
docker exec nginx-tg-crm grep -Rni "fastcgi_pass|upstream" /etc/nginx
4) Когда сайт упал из‑за блока порта
В реальном случае порт 9000 (php‑fpm) был заблокирован iptables/ufw. Проверили и увидели DROP tcp dpt:9000 / DROP tcp dpt:9567 и DNAT записи в nat цепочке Docker. Решение — либо удалить «drop» правило, либо изменить порт на безопасный и пересобрать контейнер. Примеры команд правки Docker run:
# Пересоздание контейнера с переменной FPM_LISTEN_PORT
docker rm -f tg-crm-app && docker run -d --name tg-crm-app --network tg-crm_default -e FPM_LISTEN_PORT=9567 tg-crm-php-fpm
Если iptables блокирует DNAT трафик — добавьте правило в DOCKER-USER или удалите DROP там.
5) Проверка логов аутентификации (SSH) и истории входов
- Просмотреть попытки входа SSH (journalctl):
journalctl -u ssh -S "2025-10-20" --no-pager | tail -n 200
last,who,sshd— чтобы понять, кем и откуда подключались.
Если вы видите множество Failed password — это брутфорс. Признак успешного взлома — строка Accepted password или Accepted publickey (в логах). Обратите внимание на IP и время.
6) Установка и настройка Fail2Ban
Установите и настройте fail2ban для SSH и других сервисов (пример секции sshd в /etc/fail2ban/jail.local):
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
ignoreip = 127.0.0.1/8 109.71.229.151 144.31.2.208
Запуск:
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
7) Блокировка Docker API и других опасных сервисов
- Проверьте, не слушает ли Docker daemon порт 2375 (небезопасный, без TLS):
sudo ss -ltnp | grep 2375 || true
- Если Docker API открыт — закройте/защитите его (разрешать только через unix socket или включить TLS).
8) Очистка образов/контейнеров и восстановление
- Удалите заражённый контейнер
docker rm -f <name>. - Пересоберите образ из исходников или вытяните чистый образ из доверенного реестра.
- Замените секреты/пароли, пересоздайте контейнер с новыми переменными окружения.
Важно: не перезапускайте заражённый контейнер — сначала создайте копию образа/данных для анализа.
Чек‑лист безопасности (после инцидента)
- Установить Fail2Ban и настроить SSH без паролей (только ключи).
- Отключить root‑логин по паролю в
/etc/ssh/sshd_config(PermitRootLogin prohibit-password). - Отключить Docker API на 2375 или ограничить доступ по сети/TLS.
- Включить UFW:
ufw default deny incoming; ufw allow 22; ufw allow 80; ufw allow 443. - Проверить crontab, systemd‑units, /tmp и /var/tmp на неизвестные исполняемые файлы.
- Просканировать образы на наличия встроенных бэктреков/скриптов сборки.
- Сменить ключи и пароли (особенно для аккаунтов с доступом).
- Внедрить мониторинг (CPU spike alerts), EDR/AV если можно.
Где обычно «прорываются» майнеры
- Открытые SSH с паролями — автоматические брутфорс‑боты.
- Открытый Docker API (2375) — позволяет запустить контейнеры/ползунов прямо удалённо.
- Уязвимости веб‑приложений (RCE) и устаревшие CMS.
- Скомпрометированные CI/CD секреты, ключи доступа.
Почему часто заражается только один контейнер
- Взломщик ищет путь с наименьшим сопротивлением — попав в один контейнер, он может запускать майнеры только в нём (или в контейнер с доступом к сети хоста). Если у контейнера нет прав на Docker socket, он не сможет создать новые контейнеры.
- Возможно, заражённый контейнер был запущен с уязвимыми томами/переменными, через которые загрузили бинарь.
- Если вы быстро остановили и удалили контейнер — «следы» на хосте могут быть минимальны.
Полезные команды для расследования (подборка)
# Поиск странных файлов
find / -type f -name 'kinsing*' -o -name 'kdevtmpfsi*' 2>/dev/null
# Процессы
ps aux | egrep 'kdevtmpfsi|kinsing|xmrig|minerd'
# Docker
docker ps -a
docker inspect --format '{{json .NetworkSettings.Networks}}' <container>
# Сетевые соединения
ss -ltnp
netstat -tnp | grep ESTABLISHED
# Логи SSH
journalctl -u ssh -S "2025-10-20" --no-pager | tail
# Iptables
sudo iptables -L -n -v --line-numbers
sudo iptables -t nat -L -n -v --line-numbers
Рекомендации на будущее (проактивно)
- Запретить вход по паролю (включить
PasswordAuthentication no). - Разогнать доступ SSH по IP (firewall + fail2ban + allowlist).
- Не пробрасывать Docker socket в контейнеры (
-v /var/run/docker.sock:/var/run/docker.sock— опасно). - Хранить секреты в vault (HashiCorp/Cloud provider) вместо ENV.
- Регулярные обновления образов, ОС и зависимостей.
- Ограничить права контейнеров (user namespaces, readonly rootfs, seccomp, capabilities).
Заключение
Инцидент с майнером — неприятен, но часто решается быстро: сохранить доказательства, удалить заражённый контейнер, пересобрать образ из проверенных источников и усилить доступы: отключить SSH‑пароли, поставить fail2ban, закрыть Docker API и настроить firewall. Если нужно — я подготовлю отдельную страницу в формате Markdown/HTML с разметкой для SEO и готовыми картинками/подсказками по скриншотам.
