Детектирование и blue team
Что такое SIEM? Логи, запросы и алерты
SIEM собирает логи, нормализует их, применяет правила корреляции и поднимает алерты для триажа. Разбираем весь конвейер на примере, который можно запустить.
Напишите правило Sigma для неудачных входов в Windows, проверьте его, сконвертируйте для Splunk и протестируйте на заведомо хороших и заведомо плохих событиях.
Sigma — открытый формат описания детектов, не привязанный к вендору. Логику вы пишете один раз, в небольшом YAML-файле, а конвертер превращает её в язык запросов той SIEM или лог-платформы, которая у вас стоит. Конвертеры есть для Splunk, Elastic, Microsoft Sentinel и других бэкендов, и одно правило может работать сразу на нескольких.
Формат поддерживает проект SigmaHQ. Спецификация лежит в репозитории sigma-specification, а документация по правилам на sigmahq.io разбирает поля по одному. Если вы умеете читать событие Windows, самое сложное вы уже знаете. Правило Sigma — это лишь способ сказать «вот это событие, вот с такими значениями полей» в форме, понятной другим людям и другим инструментам.
Большую часть логики детектов пишут прямо на языке запросов конкретного продукта. Поиск Splunk не запустится в Sentinel, а запрос KQL не запустится в Splunk. Когда команда переезжает на другую платформу или сообщество делится детектом, логику приходится переписывать с нуля. Это долго, и при переписывании появляются ошибки.
Sigma отделяет логику детекта от языка запросов. Правило описывает источник логов и условие, бэкенд превращает это в запрос. Отсюда два следствия:
Эта статья про второй пункт. Правило Sigma, которое парсится и конвертируется, ещё не готово: оно лишь синтаксически верно. Пользу оно приносит, когда вы можете показать, что оно срабатывает на нужных событиях и молчит на тех, которые должно игнорировать.
Вот правило, которое вы соберёте в лабораторной, с объяснением каждого поля.
title: Failed Logon Event
id: bd37e49d-15ab-4e88-a3fb-53594e831b27
status: experimental
description: Detects Windows Security event 4625 (an account failed to log on).
logsource:
product: windows
service: security
detection:
selection:
EventID: 4625
condition: selection
falsepositives:
- Users mistyping passwords
level: low
tags:
- attack.credential-access
- attack.t1110UUID у вас будет другой. Сгенерируйте свой любой библиотекой UUID, например python -c "import uuid; print(uuid.uuid4())", и сохраняйте его при дальнейших правках правила. По id другие инструменты отслеживают одно и то же правило между версиями.
stable, test, experimental, deprecated и unsupported. Новому правилу, которое не проверяли в реальной среде, подходит experimental.product: windows и service: security указывают на журнал Windows Security. Другие поля, например category, описывают класс логов, скажем создание процессов, без указания конкретного канала.selection) — это набор условий по полям. Имена полей те же, что использует источник логов. С этими полями сравниваются значения.selection сам по себе означает «события, совпавшие с блоком selection». Позже вы добавите блоки-фильтры и объедините их через and и not.informational, low, medium, high и critical. Выбирайте уровень по тому, что срабатывание значит для вашей среды, и не оглядывайтесь на то, как эффектно звучит техника.attack. указывает на тактику MITRE ATT&CK, а attack.t1110 — на технику T1110, Brute Force.Два замечания по этому правилу. Первое: EventID — имя поля в мире Sigma, оно соответствует Event ID, который вы видите в Event Viewer. Второе: level: low — осознанный выбор. Единичный неудачный вход встречается часто. В нынешнем виде правило срабатывает на каждый 4625, поэтому низкий уровень будет честной отправной точкой, пока вы не добавите порог.
Sigma ничего не знает о вашей SIEM. О ней знает бэкенд. Конвертер читает детект, применяет пайплайн обработки, который переименовывает поля и добавляет ограничения по индексу или источнику, и пишет запрос на целевом языке.
Пайплайн обработки — это набор правил сопоставления. Он отвечает на вопросы такого рода: как в Splunk называется поле Event ID, в каком индексе лежат события Windows Security и по какому sourcetype должен искать запрос. Без пайплайна конвертер может вывести имя поля Sigma как есть. На вашей платформе такой вывод часто непригоден.
У каждого бэкенда свои пайплайны. Некоторые обязательны: без них конвертер отказывается работать, если вы явно не попросите пропустить пайплайн. В лабораторной вы это увидите.
Идея простая: правило остаётся прежним, а пайплайн подгоняет его под платформу. При переезде со Splunk на другую SIEM вы меняете бэкенд и пайплайн, а детект не трогаете.
Лабораторная идёт на вашей машине. Домен, контроллер домена или какая-либо целевая система не нужны. Вы пишете и конвертируете правило. Неудачные входы вы ни против чего не генерируете, и не стоит пытаться делать это на системе, которая вам не принадлежит, если у вас нет письменного разрешения на её тестирование.
Лабораторная выполнялась на Windows 11 с Git Bash, Python 3.12 и стандартным журналом Windows Security. На Linux и macOS команды те же, отличается только путь к виртуальному окружению.
Создайте папку для лабораторной и выполните:
python3 -m venv .venv
. .venv/bin/activate
pip install sigma-cliВ Windows с Git Bash python3 может не оказаться в PATH. Используйте полный путь к установленному Python 3.12 или py -3.12. Кроме того, виртуальное окружение кладёт скрипты в .venv/Scripts вместо .venv/bin, поэтому активируйте его так:
. .venv/Scripts/activateПроверьте установку:
sigma versionНа машине, где готовилась статья, установились sigma-cli 4.0.0 с pysigma 2.0.2 и Python 3.12.10. У вас версии могут быть новее. В свои заметки записывайте то, что выведет команда, цифры выше для этого не годятся.
Создайте файл failed_logon.yml с содержимым из предыдущего раздела. В поле id подставьте свой UUID. Сохраните файл в UTF-8, без табов в отступах YAML.
sigma check failed_logon.ymlsigma check парсит файл и запускает валидаторы. Он находит отсутствующее поле, некорректный тег, неизвестный статус или уровень и ряд проблем стиля.
На машине, где готовилась статья, этот шаг не завершился. Валидатор тегов загружает данные MITRE ATT&CK по сети. Запрос вернул HTTP 504 gateway timeout, и ошибка повторялась при каждой новой попытке. На выходе был трейсбек, заканчивающийся строкой RuntimeError: Failed to load MITRE ATT&CK data, а код возврата равнялся 1.
Это сетевая зависимость, ошибки в правиле тут нет. Когда данные загрузятся, вы должны увидеть успешный результат или список замечаний валидатора. Если проверка падает с тем же сообщением про MITRE, повторите её позже или из сети, откуда доступны исходные данные. Не считайте правило проверенным, пока проверка не завершится.
Если проверка выдала замечания, прочитайте каждое. Исправляйте правило, а валидатор не трогайте. Замечание о теге обычно означает опечатку вроде attack.t1100 вместо attack.t1110.
sigma plugin install splunkНа машине, где готовилась статья, команда вывела Successfully installed plugin 'splunk' и pySigma version is compatible with sigma-cli.
sigma convert -t splunk --without-pipeline failed_logon.ymlВывод:
Parsing Sigma rules
EventID=4625Так правило выглядит до какого-либо маппинга под Splunk. Поле по-прежнему носит имя из Sigma, EventID. Поиск Splunk по событиям Windows обычно использует EventCode и source, поэтому при стандартной настройке Windows add-on этот запрос не найдёт нужные события.
Попробуйте ту же конвертацию без --without-pipeline:
sigma convert -t splunk failed_logon.ymlКонвертер остановился и объяснил, что бэкенду Splunk нужен пайплайн обработки. В сообщении было сказано добавлять --without-pipeline, только если вы понимаете, что делаете. Здесь пайплайн обязателен, поэтому без него конвертер запрос не выдаёт. Считайте это сообщение защитной мерой.
Теперь добавьте пайплайн для Windows:
sigma list pipelines
sigma convert -t splunk -p splunk_windows failed_logon.ymlВ списке оказалось три пайплайна Splunk: splunk_windows, splunk_sysmon_acceleration и splunk_cim. Конвертация с splunk_windows вывела:
Parsing Sigma rules
source="WinEventLog:Security" EventCode=4625Пайплайн изменил две вещи: сопоставил EventID с EventCode и добавил ограничение источника WinEventLog:Security. Получился запрос, который может выполнить инстанс Splunk с Windows add-on. Индекс и sourcetype у вас могут быть другими, так что считайте это отправной точкой и сверьте запрос со своими данными.
Попытка использовать ещё и пайплайн CIM завершилась ошибкой Rule type not yet supported by the Splunk data model CIM pipeline!. Не всякое правило конвертируется под любой пайплайн. Такая ошибка полезна: она говорит, что правило или бэкенд не подходит под запрошенный маппинг.
В статье о журналах событий Windows вы смотрели событие в Event Viewer. Откройте его снова и сравните с запросом:
Event ID. В выводе Splunk оно выглядит как EventCode, потому что пайплайн приводит его к имени, которое использует Windows add-on.source в запросе, WinEventLog:Security, соответствует каналу Security, который вы читали в Event Viewer.Если у вашего события в Event Viewer Event ID отличается от 4625, правило его не поймает. Так и должно быть. Правило написано про неудачные входы, остальные события журнала его не касаются.
Правило, которое конвертируется, всё ещё остаётся догадкой, пока вы его не протестируете. Минимальный тест состоит из двух половин:
Без негативных примеров у вас нет доказательств, что правило специфично. Без позитивных нет доказательств, что оно вообще работает.
В этой лабораторной тест использует небольшой файл-фикстуру с синтетическими событиями, events.json, в нём пять записей: два события 4625 и три события, которые не должны совпасть. Скрипт загружает блок selection из правила и проверяет каждое событие. Тест упрощён. Он показывает, что логика блока делает то, что вы написали. Проверку сконвертированного запроса на реальных данных он не заменяет.
import json, sys
import yaml
rule = yaml.safe_load(open("failed_logon.yml", encoding="utf-8"))
events = json.load(open("events.json", encoding="utf-8"))
selection = rule["detection"]["selection"]
def selection_matches(event):
return all(str(event.get(k)) == str(v) for k, v in selection.items())
failures = 0
for ev in events:
got = "match" if selection_matches(ev) else "no match"
ok = got == ev["expect"]
failures += 0 if ok else 1
print(f"{'PASS' if ok else 'FAIL'} {ev['name']:<40} expected={ev['expect']:<9} got={got}")
print(f"{len(events) - failures}/{len(events)} passed")
sys.exit(1 if failures else 0)Файл-фикстура выглядит так:
[
{"name": "known-bad: failed logon", "EventID": 4625, "expect": "match"},
{"name": "known-bad: failed logon, second try", "EventID": 4625, "expect": "match"},
{"name": "known-good: successful logon", "EventID": 4624, "expect": "no match"},
{"name": "known-good: logoff", "EventID": 4634, "expect": "no match"},
{"name": "known-good: process creation", "EventID": 4688, "expect": "no match"}
]Запустите:
python test_failed_logon.pyНа машине, где готовилась статья, вывод был таким:
PASS known-bad: failed logon expected=match got=match
PASS known-bad: failed logon, second try expected=match got=match
PASS known-good: successful logon expected=no match got=no match
PASS known-good: logoff expected=no match got=no match
PASS known-good: process creation expected=no match got=no match
5/5 passedОбратите внимание, что этот тест показывает и чего не показывает. Он показывает, что правило совпадает с нужными событиями и игнорирует остальные. Что правило хорошее, он не доказывает. Правило, совпадающее с каждым 4625, пройдёт этот тест, потому что каждый 4625 в фикстуре должен совпасть. Польза от теста есть, но это лишь нижняя планка.
Следующий шаг в реальной среде: запустите сконвертированный запрос Splunk на отрезке логов Windows Security, про который вы знаете, что в нём есть неудачные входы и обычная активность. Посчитайте результаты и откройте выборку. Каждое срабатывание должно быть событием 4625. Если запрос возвращает другие Event ID, неверен пайплайн или маппинг полей.
Это правило срабатывает на каждый 4625. Срабатывание даст один неверно набранный пароль, и то же самое сделает сервисная учётная запись с просроченным паролем, которая повторяет попытку каждую минуту. Брутфорс — это множество неудач по одной учётной записи за короткое время, и первая версия правила выразить это не может.
В Sigma для этого есть правила корреляции, описанные в отдельной спецификации. Правило корреляции само события не сопоставляет. Оно ссылается на одно или несколько базовых правил по name, группирует их совпадения по полю и считает их во временном окне. Тип event_count считает совпадения, а condition: gte: 5 означает пять или больше. Поместите оба правила в один файл, разделив их через ---, и задайте базовому правилу name:
title: Failed Logon Event
name: failed_logon_event
id: bd37e49d-15ab-4e88-a3fb-53594e831b27
status: experimental
description: Detects Windows Security event 4625 (an account failed to log on).
logsource:
product: windows
service: security
detection:
selection:
EventID: 4625
condition: selection
falsepositives:
- Users mistyping passwords
level: low
tags:
- attack.credential-access
- attack.t1110
---
title: Many Failed Logons For One Account
id: 3f6c1d52-8a0e-4b7e-9d2a-6c41e0b7a915
status: experimental
description: Five or more failed logons for the same target account within ten minutes.
correlation:
type: event_count
rules:
- failed_logon_event
group-by:
- TargetUserName
timespan: 10m
condition:
gte: 5
falsepositives:
- Service accounts with an expired password
level: mediumСохраните его как multi.yml и сконвертируйте тем же пайплайном:
sigma convert -t splunk -p splunk_windows multi.ymlВывод:
Parsing Sigma rules
source="WinEventLog:Security" EventCode=4625
| bin _time span=10m
| stats count as event_count by _time TargetUserName
| search event_count >= 5Первая строка — базовое правило. Три строки после неё — корреляция: разбить события на десятиминутные окна, посчитать их по TargetUserName, оставить группы с пятью и более событиями. Значения 5 и 10 минут условные. Подберите их по своим данным и проверьте результат на тех же заведомо хороших и заведомо плохих событиях. Не каждый бэкенд поддерживает все типы корреляций, так что сверяйте вывод конвертера, прежде чем на него полагаться.
Первую версию правила сохраните. Это базовая линия, и сравнение с коррелированной версией покажет, помогает ли порог.
EventID. В Splunk после пайплайна это EventCode. Смешение двух имён в одном правиле ведёт к тихим пропускам.--without-pipeline — флаг для осознанного применения, срезать путь с ним не выйдет. Вывод может не запуститься на вашей платформе.level: high шумному правилу. Серьёзность должна соответствовать тому, что значит срабатывание. Частое событие без контекста начинают с низкого уровня.sigma check проверяет структуру файла. Находит ли детект нужные события, он не проверяет.Когда правило проходит проверку, конвертируется и выдерживает тесты, следующие шаги очевидны:
|contains и |endswith и поле category.Вкратце: правило — это утверждение о событиях. Запишите утверждение, сконвертируйте его, а затем подтвердите событиями, которые должны совпасть и которые не должны.
Детектирование и blue team
SIEM собирает логи, нормализует их, применяет правила корреляции и поднимает алерты для триажа. Разбираем весь конвейер на примере, который можно запустить.
Детектирование и blue team
Как читать журнал Security: политика аудита, события 4624, 4625, 4634, 4672, 4688 и 1102, что добавляет Sysmon и как найти собственный неудачный вход.