Wazuh: обнаружение уязвимостей, обогащение KEV и EPSS и заявка по критичным

Сканер раз в неделю или раз в месяц — это снимок. Между снимками выходят уязвимости, и о них вы узнаёте при следующем запуске. Агент Wazuh, который уже стоит на узлах, каждые несколько часов отправляет список установленных пакетов и сопоставляет его с базой уязвимостей, поэтому он показывает новую дыру почти сразу после выхода записи. Ниже как это включить, как проверить, что оно работает, как добавить сведения об эксплуатации и как превратить критичную находку в заявку или инцидент без ручного разбора каждой.
Сам Wazuh и его первые правила разобраны в статьях установка в Docker и правила обнаружения атак. Чем отличается SIEM от мониторинга, смотрите в разборе SOC и SIEM. Как устроен реестр, куда попадает результат, — реестр уязвимостей.
Что именно делает Wazuh и чем это не сканер
Сканер уязвимостей ходит по сети и проверяет узлы. Wazuh не сканирует: агент передаёт инвентарь (пакеты и версии), а сервер сопоставляет их с каталогами уязвимостей. Из этого следуют плюсы и минусы.
| Свойство | Следствие |
|---|---|
| Работает на постоянной основе, по мере обновления базы | Не нужно ждать расписания скана |
| Использует данные производителя дистрибутива | Учитывает исправления, перенесённые в старые версии пакетов (backport): ложных срабатываний меньше, чем у сканирования по баннерам |
| Видит только то, что ставится пакетами | Вручную установленное ПО, веб-приложения и конфигурации остаются невидимыми: нужен сканер и проверка конфигураций |
| Требует агента | Сетевое оборудование и устройства без агента не покрываются |
Вывод: Wazuh дополняет регулярные сканы, а не заменяет их. Для периметра по-прежнему нужен сканирующий взгляд снаружи.
Шаг 1. Включение (Wazuh 4.8 и новее)
В версии 4.8 детектор уязвимостей переработан: результаты хранятся в индексе индексатора, а не только в оповещениях. Поведение зависит от версии, поэтому сначала проверьте, что у вас стоит.
/var/ossec/bin/wazuh-control info
Ожидаемо: строка WAZUH_VERSION="v4.x.y". Для версий до 4.8 порядок иной (детектор работает по оповещениям, группа правил vulnerability-detector) и поля ниже называются по-другому. В стандартной контейнерной установке модуль обычно включён. Если нет, добавьте блок в конфигурацию менеджера:
<vulnerability-detection>
<enabled>yes</enabled>
<index-status>yes</index-status>
<feed-update-interval>60m</feed-update-interval>
</vulnerability-detection>
Затем перезапустите менеджер и дайте базе загрузиться: первое обновление занимает время. Не включайте детектор на слабой машине без запаса диска и памяти: индекс находок растёт вместе с числом узлов.
Проверка: в интерфейсе откройте модуль Vulnerability Detection. Должен появиться список узлов с числом уязвимостей по серьёзности. Пустая страница при подключённых агентах означает, что инвентарь ещё не передан или база не загружена.
Шаг 2. Выгрузка критичных находок
Для автоматизации нужен доступ к индексу находок. Он хранится в индексе вида wazuh-states-vulnerabilities-*. Запрос к индексатору (создайте отдельного пользователя только на чтение, а не используйте администратора):
curl -sk -u reader:ПАРОЛЬ "https://127.0.0.1:9200/wazuh-states-vulnerabilities-*/_search?size=3" \
-H 'Content-Type: application/json' \
-d '{"query":{"term":{"vulnerability.severity":"Critical"}},
"_source":["agent.name","package.name","package.version","vulnerability.id","vulnerability.score.base"]}'
Ожидаемо: JSON с массивом hits, в каждой записи имя узла, пакет, версия и идентификатор CVE. Названия полей и значение серьёзности («Critical») могут отличаться в вашей версии: сверьте с тем, что видно во вкладке просмотра документов индекса, и поправьте запрос.
Шаг 3. Обогащение: KEV, EPSS и доступность
Серьёзность по базе — это CVSS. Для решения «что делать сегодня» нужны ещё сведения об эксплуатации и о том, виден ли узел из интернета. Скрипт ниже берёт критичные и высокие находки из индекса, добавляет признак KEV и значение EPSS и присваивает приоритет по матрице из основной статьи. Доступность из интернета берётся из вашего файла соответствия «имя узла — периметр или внутренний», потому что Wazuh этого не знает.
#!/usr/bin/env python3
"""Находки Wazuh -> приоритет P1..P4 с учётом KEV, EPSS и доступности узла.
Использование: wazuh_prioritize.py exposure.csv
exposure.csv: строки вида имя_узла,internet|internal
Переменные среды: WAZUH_INDEXER (например https://127.0.0.1:9200), WAZUH_USER, WAZUH_PASSWORD."""
import base64
import csv
import json
import os
import ssl
import sys
import urllib.parse
import urllib.request
KEV = 'https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json'
EPSS = 'https://api.first.org/data/v1/epss'
ctx = ssl.create_default_context()
if os.environ.get('WAZUH_INSECURE') == '1': # только для проверки на стенде
ctx.check_hostname, ctx.verify_mode = False, ssl.CERT_NONE
def get_json(url, body=None, auth=None):
req = urllib.request.Request(url, data=body, headers={'Content-Type': 'application/json'})
if auth:
req.add_header('Authorization', 'Basic ' + base64.b64encode(auth.encode()).decode())
with urllib.request.urlopen(req, timeout=60, context=ctx) as r:
return json.load(r)
exposure = {r[0]: r[1] for r in csv.reader(open(sys.argv[1], encoding='utf-8')) if len(r) >= 2}
kev = {v['cveID'] for v in get_json(KEV)['vulnerabilities']}
q = {'size': 1000, '_source': ['agent.name', 'package.name', 'package.version', 'vulnerability.id', 'vulnerability.score.base'],
'query': {'terms': {'vulnerability.severity': ['Critical', 'High']}}}
hits = get_json(os.environ['WAZUH_INDEXER'] + '/wazuh-states-vulnerabilities-*/_search',
json.dumps(q).encode(), f"{os.environ['WAZUH_USER']}:{os.environ['WAZUH_PASSWORD']}")['hits']['hits']
cves = sorted({h['_source']['vulnerability']['id'] for h in hits})
epss = {}
for i in range(0, len(cves), 50):
data = get_json(EPSS + '?' + urllib.parse.urlencode({'cve': ','.join(cves[i:i + 50])}))
epss.update({d['cve']: float(d['epss']) for d in data['data']})
def priority(cve, host, cvss):
inet = exposure.get(host) == 'internet'
e = epss.get(cve, 0)
if (cve in kev and inet) or (inet and e >= 0.9):
return 'P1'
if cve in kev or e >= 0.5 or (inet and cvss >= 9):
return 'P2'
return 'P3' if cvss >= 7 or e >= 0.1 else 'P4'
rows = []
for h in hits:
s = h['_source']
cve, host = s['vulnerability']['id'], s['agent']['name']
cvss = float(s['vulnerability'].get('score', {}).get('base', 0))
rows.append((priority(cve, host, cvss), host, cve, s['package']['name'], s['package']['version'], cve in kev, epss.get(cve, 0)))
for r in sorted(rows):
print(*r, sep=';')
sys.exit(1 if any(r[0] == 'P1' for r in rows) else 0)
Ожидаемо: строки «приоритет;узел;CVE;пакет;версия;в KEV;EPSS», отсортированные по приоритету, код выхода 1 при наличии P1. Запускайте на хосте, откуда доступен индексатор, и храните учётные данные в переменных среды, а не в файле. Скрипт можно ставить в cron раз в сутки; код выхода 1 используйте как условие для срочного уведомления.
Шаг 4. Заявка или инцидент по P1
Автоматизируйте то, что безопасно: создание заявки и уведомление. Остановку сервиса и блокировку оставьте решением человека, пока не наберётся опыт. Правило эскалации:
| Приоритет | Автоматически | Решает человек |
|---|---|---|
| P1 | Заявка с меткой «срочно», уведомление ответственному за ИБ и владельцу узла, запись в реестр | Снимать сервис с интернета или применять компенсирующую меру; открывать ли инцидент по критериям классификации |
| P2 | Заявка со сроком, запись в реестр | Окно обновления |
| P3 и P4 | Запись в реестр, еженедельный отчёт | Плановое обновление |
Если по P1 есть признаки эксплуатации (необычные входы, новые процессы, исходящий трафик), заводите инцидент: порядок в карточке инцидента и плейбуке критичной уязвимости. Создание заявки через API трекера показано в статье про реестр уязвимостей.
Что считать анализом угроз для малой инфраструктуры
Четвёртый уровень зрелости требует решения класса Threat Intelligence, которое даёт контекст, критичность и актуальность угроз. В большой компании это коммерческая платформа. В небольшой разумный минимум другой, и его можно показать как работающее решение, если оно настроено и используется регулярно.
- Каталог KEV и оценка EPSS как источники контекста об эксплуатации; обновление автоматическое, как в скрипте выше.
- Списки индикаторов компрометации (адреса, домены, хэши) в формате списков Wazuh, которые подключаются к правилам и обогащают оповещения. Обновляйте их по расписанию из надёжных источников.
- Для организаций, которые уже обмениваются индикаторами, платформа вроде MISP как хранилище и источник лент.
Как показать работу: перечень источников с настройками, отчёты по уязвимостям, в которых указаны данные KEV и EPSS, и журнал обновления лент. Выбирайте решение по реальной потребности: покупка платформы, которую никто не смотрит, на проверке не поможет.
Какие артефакты хранить
| Что хранить | Что показывает |
|---|---|
| Конфигурация детектора уязвимостей и список агентов с их состоянием | Обнаружение настроено и покрывает парк |
| Скрипт обогащения и расписание его запуска, журнал выполнения | Данные KEV и EPSS используются при анализе |
| Примеры созданных заявок и инцидентов по P1 | Критичные находки превращаются в действия, а не остаются в панели |
| Правило эскалации по приоритетам | Разделение автоматических и ручных решений |
| Перечень источников анализа угроз с настройками | Решение уровня TI существует и поддерживается |
Диагностика
| Симптом | Причина и что делать |
|---|---|
| В модуле уязвимостей пусто при живых агентах | База ещё не загружена или инвентарь не передан. Проверьте журнал менеджера и состояние модуля инвентаризации на агенте |
| Запрос к индексу возвращает ошибку 401 или 403 | Неверный пользователь или нет прав на индекс. Создайте пользователя на чтение для этого индекса |
| Запрос возвращает ноль записей | Другие названия полей или значение серьёзности. Откройте документ индекса и сверьте |
| Находка есть, а на узле пакет уже обновлён | Инвентарь устарел или пакет в другом каталоге. Дождитесь передачи или перезапустите агент и повторите проверку |
| Слишком много P2 | Порог EPSS слишком низкий для вашей среды. Поднимите значение и пересмотрите матрицу |
Где это в модели зрелости
Материал относится к направлению «Управление уязвимостями» (хаб: уязвимости, карта: карта зрелости). Четвёртый и пятый уровни добавляют анализ с помощью данных об угрозах, классификатор рейтинга с учётом вашего ландшафта и связь системы управления уязвимостями с SIEM для автоматического создания инцидентов по критичным находкам. Цепочка выше закрывает все три пункта в масштабе небольшой компании.
Как проверить
- В модуле уязвимостей Wazuh видны все критичные узлы и числа по серьёзности.
- Скрипт обогащения на тестовом файле доступности выводит P1 для заведомо критичной находки на узле «internet» и P3–P4 для внутреннего узла.
- Для последней находки P1 есть заявка, дата и ответственный.
- Ленты KEV и EPSS обновляются по расписанию, в журнале нет ошибок сети.
Источники
- Wazuh, модуль обнаружения уязвимостей: documentation.wazuh.com.
- CISA, каталог KEV: cisa.gov.
- EPSS, FIRST: first.org/epss.
- NIST SP 800-61 Rev. 3, реагирование на инциденты: csrc.nist.gov. Не закон РФ.


















