Сервер начал рассылать спам ночью: как понять, что вы уже не хозяин
Утро начинается не с алерта о нагрузке, а с письма от почтового провайдера: "your IP has been listed" — или с жалобы клиента, что счёт от вашей компании ушёл в спам. CPU в норме, диск не заполнен, сайт открывается — по обычным метрикам сервер здоров. Но ночью, пока никто не смотрел, он отправил несколько тысяч писем, о которых вы не просили. Ниже — как быстро понять, где дыра, отличить это от честного всплеска рассылки и остановить кровотечение, не сломав легитимную почту заодно.
Содержание
- Как обычно узнают о проблеме
- Диагностика: что показывает очередь исходящей почты
- Кто инициирует отправку: локальный источник или внешний
- Три типичных источника и их сигнатуры в логах
- Как отличить вредоносную рассылку от легитимного всплеска
- Первоочередные действия: остановить, найти, закрыть
- Репутация IP после чистки и как не допустить повтора
Как обычно узнают о проблеме
Метрики CPU, RAM и диска почти всегда остаются в норме — рассылка спама не требует особых ресурсов, поэтому обычный мониторинг сервера её не ловит. Сигнал приходит снаружи и делится на три типа: bounce-сообщения на легитимный обратный адрес с кодом вида 550 5.7.1 и упоминанием DNSBL, прямая жалоба клиента или партнёра, что письмо ушло в спам или не проходит их фильтр, и — самый ранний вариант — собственный мониторинг репутации, если он уже настроен. Ждать первых двух сигналов значит терять репутацию, которая потом восстанавливается неделями.
Проверить статус по нескольким независимым списками можно так:
IP=203.0.113.10
REV=$(echo $IP | awk -F. '{print $4"."$3"."$2"."$1}')
for zone in zen.spamhaus.org bl.spamcop.net b.barracudacentral.org; do
echo -n "$zone: "; dig +short "$REV.$zone"
done
Пустой ответ — не в списке, любой IP в ответе (обычно 127.0.0.x) — сервер уже числится. Один список может молчать, а другой уже банить — это нормально, реагируют они с разной скоростью и по разным правилам.
Диагностика: что показывает очередь исходящей почты
Первый практический шаг — посмотреть, что стоит в очереди прямо сейчас. Для Postfix:
postqueue -p | tail -n 30
mailq | grep -c "^[A-F0-9]"
qshape deferred | head -n 20
qshape полезнее простого счётчика — группирует отложенные письма по доменам получателей и по возрасту (сколько висит меньше 5 минут, сколько уже часами). Резкий пик по десяткам разных внешних доменов в колонке "новые за последние минуты" — признак активной рассылки прямо сейчас, а не старого хвоста.
Для exim аналог:
exim -bp | wc -l
exiqsumm
exiqsumm группирует очередь по доменам получателей так же, как qshape у Postfix.
Дальше важно посмотреть не только на количество, но и на содержимое нескольких писем:
postqueue -p | awk '/^[A-F0-9]/{print $1}' | tr -d '*!' | head -5
postcat -q <queue_id> # Postfix
exim -Mvb <message_id> # exim, тело
Смотрите на три вещи: тему письма (часто шаблонная — реклама препаратов, крипты, фишинг под смену пароля), получателей (десятки внешних адресов из доменов, которых нет в CRM) и заголовок From (подделан под ваш домен или произвольный).
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверКто инициирует отправку: локальный источник или внешний
Дальше нужно понять, письма рождаются локально (скрипт вызывает mail()/sendmail) или уходят снаружи через SMTP AUTH — это разные проблемы с разным лечением.
grep "postfix/pickup\|postfix/local" /var/log/mail.log | tail -50
grep "postfix/smtpd.*client=" /var/log/mail.log | tail -50
Письма через pickup создаёт локальный процесс: уязвимая PHP-форма, взломанная CMS, вредоносный cron или веб-шелл. Письма через smtpd с внешним client= — либо Postfix используют как открытый релей (проверьте postconf mynetworks и smtpd_recipient_restrictions), либо это авторизованная отправка через угнанный SMTP AUTH — тогда в логе есть sasl_username:
grep "sasl_username" /var/log/mail.log | awk -F'sasl_username=' '{print $2}' | awk '{print $1}' | sort | uniq -c | sort -rn
Один и тот же логин с тысячами исходящих за ночь при обычной норме в десяток писем в день — почти наверняка скомпрометированный почтовый ящик.
Если источник локальный, ищем процесс:
ps aux | grep -iE "sendmail|mail|smtp" | grep -v grep
grep -r "mail(" /var/www/*/public_html --include=*.php -l 2>/dev/null
find /var/www -path "*/uploads/*" -name "*.php" -newer /var/log/mail.log
for u in $(cut -f1 -d: /etc/passwd); do crontab -l -u "$u" 2>/dev/null; done
Точку входа обычно выдаёт access-лог веб-сервера — резкий рост POST-запросов на конкретный скрипт с десятков разных IP:
grep "POST" /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20
Если аномалия совпадает по времени со всплеском в очереди почты — это и есть точка входа. Похожий разбор конкретного случая, когда источником оказалась форма обратной связи с инъекцией заголовков в PHP mail(), — в статье форма обратной связи стала открытым релеем.
Три типичных источника и их сигнатуры в логах
Уязвимая веб-форма (инъекция заголовков в mail()). Письма идут через pickup, From совпадает с доменом сайта, получатели — случайный набор внешних адресов, всплеск синхронен с ростом POST-запросов к конкретному скрипту. Файлы CMS и плагинов обычно не менялись — уязвимость в собственном коде.
Скомпрометированная учётная запись почты. Письма идут через smtpd с валидным sasl_username, иногда с разных IP за короткое время — видно по client= при одном и том же логине. Тема писем чаще фишинговая или рекламная, привязки к конкретному скрипту на сайте нет. Похожий случай с перебором паролей к почтовому ящику разобран в статье перебор паролей к почте: увидеть до начала рассылки.
Установленный вредоносный релей или веб-шелл. Самый неприятный вариант — на сервере появился отдельный процесс или файл, который сам генерирует и рассылает письма, не привязанный к легитимному скрипту сайта:
ss -tulnp | grep -vE "22|80|443|25|587"
find / -mtime -2 -type f \( -name "*.php" -o -name "*.py" -o -name "*.sh" \) 2>/dev/null | grep -vE "^/var/log|^/proc"
Проверяйте не только веб-директории, но и /tmp, /var/tmp, домашние каталоги — типичные места для вредоносных скриптов, если путь заражения не веб-приложение, а, например, украденный SSH-ключ. Если подозреваете взлом сервера целиком, план действий шире одной очереди почты — он описан в статье что делать при взломе: план реагирования.
Как отличить вредоносную рассылку от легитимного всплеска
Не любой резкий рост очереди — это спам: маркетинговая рассылка, выгрузка чеков за период, массовая пересылка уведомлений после релиза тоже дают скачок исходящих.
| Признак | Легитимный всплеск | Вредоносная рассылка |
|---|---|---|
| Получатели | Известная база (CRM, подписчики) | Случайные/чужие домены вне базы |
| Отправитель | Один настоящий адрес компании | Подделан или чужой скомпрометированный ящик |
| Точка входа | Известный скрипт рассылки, запущен вручную/по плану | Форма, cron или файл, о которых никто не знает |
| Содержание | Соответствует бизнесу (счета, новости) | Шаблонный спам, фишинг, часто на других языках |
| Время | Совпадает с рабочим циклом | Часто ночью либо ровным потоком круглосуточно |
| Реакция получателей | Открытия, нормальный bounce rate | Массовые жалобы, аномально высокий bounce |
Ключевая проверка — сверить получателей из очереди с реальной базой контактов (CRM, подписка, биллинг). Если пересечение близко к нулю — это не ваша рассылка, кто бы её ни инициировал технически. Если сомневаетесь — спросите тех, кто мог её запустить: маркетинг, биллинг, разработчика после недавнего деплоя с новым email-шаблоном. Часто "спам" оказывается кривым тестовым скриптом, случайно ушедшим на прод-базу целиком вместо тестовой выборки — неприятно, но не взлом.
Первоочередные действия: остановить, найти, закрыть
Порядок имеет значение — сначала стоп-кран, потом разбор: пока вы ищете причину, очередь продолжает бить по репутации.
- Остановить отправку, не убивая сервис целиком:
postsuper -h ALL # перевести все письма в очереди в hold
systemctl stop postfix # если нужно жёстче
hold не удаляет письма и не отправляет их — удобно, если часть очереди на самом деле легитимна.
- Найти и остановить процесс-источник: отключить уязвимый скрипт, убить вредоносный процесс, снять права на выполнение с подозрительного файла:
mv /var/www/site/vulnerable.php /var/www/site/vulnerable.php.disabled
kill -9 <pid>
chmod 000 /path/to/suspicious/file
- Сменить пароль и отозвать сессии, если источник — скомпрометированный почтовый ящик: смена пароля SMTP AUTH, принудительный logout активных сессий, проверка на форвардинг-правила и сторонние OAuth-приложения с доступом к ящику.
- Очистить очередь от вредоносных писем, не трогая легитимные:
for id in $(cat /tmp/bad_qids.txt); do postsuper -d "$id"; done
postsuper -d ALL # в критичном случае — снести всю очередь
- Закрыть точку входа окончательно — не просто отключить скрипт, а исправить уязвимость: валидация ввода, патч CMS или плагина, смена скомпрометированного пароля или ключа. Иначе после снятия hold атака возобновится тем же путём.
- Возобновить отправку легитимной почты точечно, а не разом всей очередью — резкий скачок объёма с недавно проблемного IP сам по себе выглядит подозрительно:
systemctl start postfix
postsuper -H <id> # снять hold с конкретных писем
Репутация IP после чистки и как не допустить повтора
Устранить причину — половина дела. Сама по себе очистка сервера из чёрного списка не выкидывает — большинство DNSBL требуют либо автоматического таймаута (от часов до нескольких дней без новой вредоносной активности), либо ручной заявки на делистинг через форму провайдера списка. Проверьте статус тем же скриптом с dig, что и в начале — попадание в один список не всегда тянет за собой остальные. Не отправляйте резко весь скопившийся объём легитимной почты сразу после делистинга: крупные провайдеры вроде Gmail и Outlook смотрят не только на присутствие в списках, но и на паттерн отправки. Если делистинг затягивается, а бизнес ждать не может — рассмотрите перенос почты на отдельный релей или выделенный IP, пока старый отстаивается. Подробный разбор восстановления репутации по шагам, включая сроки у разных списков, — в статье IP попал в чёрные списки: восстановление репутации.
Минимальный набор, который стоит поставить сразу после инцидента, чтобы не узнавать о следующем по жалобам:
- Мониторинг размера очереди — крон-скрипт, сравнивающий текущее число писем с обычным фоном:
COUNT=$(mailq | grep -c "^[A-F0-9]")
BASELINE=50
[ "$COUNT" -gt $((BASELINE * 3)) ] && echo "Mail queue spike: $COUNT" | mail -s "ALERT: queue spike" ops@example.com
- Периодическая проверка IP по DNSBL тем же способом через
dig, раз в 15-30 минут. - Rate-limit на все точки, умеющие отправлять почту — формы, API, скрипты рассылки — на уровне nginx (
limit_req) и приложения. - Валидация ввода везде, где значение попадает в заголовки письма, и переход с ручной конкатенации строк на проверенные библиотеки отправки.
- Двухфакторная аутентификация на почтовых ящиках и отдельные пароли для SMTP AUTH — компрометация ящика через утечку пароля с другого сервиса встречается чаще, чем целевой взлом сервера.
- Регулярный аудит крон-задач и процессов, особенно там, где к серверу давно не пересматривали список тех, у кого есть доступ.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько времени обычно есть до того, как жалобы получателей превратятся в блокировку IP?
По-разному и без формальной гарантии — иногда счёт идёт на часы, если письма массово попадают в спам-ловушки или получают жалобы у нескольких крупных провайдеров сразу, иногда на сутки-двое при менее агрессивной рассылке. Реагировать нужно сразу по первому сигналу, не дожидаясь запаса времени.
Можно ли просто остановить Postfix и разбираться дальше, не потеряв легитимную почту?
Лучше использовать postsuper -h ALL вместо остановки сервиса целиком — письма зависают со статусом hold, ничего не теряется, а после разбора легитимные можно точечно отпустить командой postsuper -H <id>, вредоносные — удалить.
Если письма шли через SMTP AUTH с валидным логином, точно ли дело в скомпрометированном пароле, а не в дыре у самого хостера?
Не на 100%, но это самое частое объяснение. Проверьте /var/log/mail.log на IP-адреса, с которых логинился этот sasl_username: если это разные страны и провайдеры за короткий период, пароль почти наверняка утёк. Смена пароля и включение 2FA снимают проблему в большинстве таких случаев.
Нужно ли переустанавливать сервер с нуля после подобного инцидента?
Если источником была одна уязвимая форма или скомпрометированный почтовый пароль, а признаков более глубокого проникновения (посторонние SSH-ключи, новые пользователи, изменённые системные бинарники) не нашли — переустановка избыточна, достаточно закрыть конкретную дыру. Если обнаружен веб-шелл или следы бокового перемещения по системе — это уже полноценный взлом, и решение стоит принимать по итогам более широкого аудита.
Как быстро проверить, не рассылает ли сервер спам прямо сейчас, если жалоб ещё не было?
qshape deferred в Postfix или exiqsumm в exim: если верхние строки по объёму занимают домены, которых не должно быть в адресной книге, и счётчик писем за последние минуты аномально высокий — сервер, скорее всего, уже рассылает. Для постоянного контроля лучше завести крон-алерт на размер очереди, а не проверять руками.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →