ElastAlert поверх ELK: правила для SSH-брутфорса, аномальных 4xx и sudo - и первый живой сканер внутри сети
Подключаем ElastAlert от Yelp к нашему ELK-стеку. Три правила корреляции событий безопасности - и сразу находим активный сканер во внутренней сети.
ElastAlert от Yelp становится стандартным инструментом алертинга для ELK-стека, позволяя строить корреляцию событий безопасности поверх Elasticsearch
ELK-стек у нас работал уже несколько месяцев: логи со всех серверов летят в Elasticsearch, Kibana показывает красивые дашборды. Проблема в том, что дашборды надо смотреть. Если никто не смотрит - это архив, а не мониторинг. Задача «добавить алертинг» висела в беклоге, пока мы не наткнулись на ElastAlert.
ElastAlert - это демон на Python от Yelp, который периодически запускает запросы к Elasticsearch и отправляет уведомления, если что-то совпало с правилом. Правила описываются в YAML. Поддерживаемые типы: frequency (N событий за период), spike (аномальный рост), flatline (исчезновение ожидаемых событий), any (любое совпадение). Под наши задачи безопасности это подходит почти идеально.
Почему не Kibana Alerting
Kibana 4.x на тот момент не имела встроенного алертинга - его планировали добавить в Watcher как платную фичу X-Pack. Нам платный X-Pack казался излишеством для задачи «пришли письмо если что-то подозрительное». ElastAlert свободный, устанавливается через pip, конфиги в git - как раз то, что нужно.
Установка и базовая конфигурация
pip install elastalert
elastalert-create-index # создаёт индекс для хранения состояния алертов
Главный конфиг (config.yaml) минимальный:
es_host: elasticsearch.internal
es_port: 9200
rules_folder: /etc/elastalert/rules
run_every:
minutes: 1
buffer_time:
minutes: 15
alert_time_limit:
days: 2
buffer_time - это окно, за которое ElastAlert смотрит назад при каждом запуске. Для медленных атак (брутфорс растянутый на часы) нужно увеличивать. Мы поставили 15 минут для оперативных правил и до 60 минут для аномалий.
Три правила, с которых начали
Первое - брутфорс SSH. Классика: если один IP генерирует больше N неудачных попыток аутентификации за промежуток времени - это надо знать. Логи auth.log идут в нас через Filebeat, парсятся в Logstash через grok, и в Elasticsearch падают с полями event_type: sshd_failed_auth и src_ip.
name: SSH Brute Force
type: frequency
index: logstash-*
num_events: 20
timeframe:
minutes: 5
filter:
- term:
event_type: sshd_failed_auth
query_key: src_ip
alert:
- email
email:
- security@adg.ru
query_key: src_ip означает, что ElastAlert группирует события по исходному IP и триггерит алерт отдельно на каждый IP, превысивший порог. Без этого поля - считал бы все неудачные логины в сумме по всем серверам, что бессмысленно.
Второе - аномальный рост ошибок 4xx. Для веб-приложений всплеск 404/403 часто означает сканирование директорий или перебор путей. Тип правила spike считает отношение текущего окна к предыдущему:
name: HTTP 4xx Spike
type: spike
index: logstash-*
spike_height: 5
spike_type: up
timeframe:
minutes: 10
filter:
- range:
http_status:
gte: 400
lt: 500
alert:
- email
email:
- security@adg.ru
spike_height: 5 - текущее окно в пять раз превышает предыдущее. Порог подбирали опытным путём: при 3 было слишком много ложных срабатываний от легитимных всплесков трафика.
Третье - неожиданный sudo. Sudo-команды на серверах - событие не ежесекундное, и неожиданный sudo su или sudo bash с незнакомого пользователя - повод посмотреть. Тип any: просто уведомлять о каждом событии из определённого паттерна.
name: Unexpected Sudo
type: any
index: logstash-*
filter:
- term:
event_type: sudo_command
- not:
terms:
sudo_user: ["deploy", "ansible", "nagios"]
alert:
- email
email:
- security@adg.ru
В whitelist вошли сервисные пользователи, которые легитимно используют sudo: деплой через Ansible, мониторинг через Nagios. Всё остальное - в алерт.
Первые результаты и неожиданная находка
Запустили в пятницу вечером. К утру понедельника в ящике было несколько алертов по SSH - в основном внешние сканеры, которые молотят по 22 порту из интернета. Это ожидаемо и малоинтересно, fail2ban с ними и так работает.
Но среди алертов по HTTP 4xx оказался один нетривиальный. Источником аномалии был внутренний IP - адрес из нашего же офисного диапазона. Паттерн запросов - перебор типичных путей: /admin, /phpmyadmin, /wp-admin, /backup, /config.php и ещё несколько десятков вариантов. Целью были несколько серверов из внутренней сети.
Это был активный сканер внутри сети. IP оказался принадлежать одной из рабочих станций - на ней обнаружился запущенный инструмент сканирования, установленный, судя по всему, давно и ранее никем не замеченный. Как он там оказался - отдельное расследование, которое ещё не закончено на момент написания.
Важно то, что без алертинга поверх ELK этого бы не нашли - по крайней мере не так быстро. Kibana-дашборд с 4xx мы смотрели от случая к случаю, а не постоянно.
Что ещё настраиваем
ElastAlert умеет слать уведомления не только по email - есть интеграции со Slack, PagerDuty, HipChat. Мы пробуем Slack-канал для оперативных алертов: письмо можно пропустить, а в Slack видно сразу.
Количество правил сейчас небольшое - три рабочих плюс пара в тестировании. Главная работа сейчас - калибровка порогов, чтобы не захлебнуться в ложных срабатываниях. Слишком чувствительный алерт, который срабатывает десять раз в день, перестают читать быстрее, чем кажется.
Весь этот слой детектирования - часть того, что мы делаем в рамках аудита безопасности: не только разовая проверка, но и помощь с инструментами, которые работают после того, как мы ушли.