Перейти к содержимому
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after a top-up of $10 or more. Until Nov 30.

How it works

Первое правило Sigma: пишем детект и проверяем его на событиях

Напишите правило Sigma для неудачных входов в Windows, проверьте его, сконвертируйте для Splunk и протестируйте на заведомо хороших и заведомо плохих событиях.

Средний12 мин чтенияАвтор: NotHoly

Что такое правило Sigma

Sigma — открытый формат описания детектов, не привязанный к вендору. Логику вы пишете один раз, в небольшом YAML-файле, а конвертер превращает её в язык запросов той SIEM или лог-платформы, которая у вас стоит. Конвертеры есть для Splunk, Elastic, Microsoft Sentinel и других бэкендов, и одно правило может работать сразу на нескольких.

Формат поддерживает проект SigmaHQ. Спецификация лежит в репозитории sigma-specification, а документация по правилам на sigmahq.io разбирает поля по одному. Если вы умеете читать событие Windows, самое сложное вы уже знаете. Правило Sigma — это лишь способ сказать «вот это событие, вот с такими значениями полей» в форме, понятной другим людям и другим инструментам.

Зачем это нужно

Большую часть логики детектов пишут прямо на языке запросов конкретного продукта. Поиск Splunk не запустится в Sentinel, а запрос KQL не запустится в Splunk. Когда команда переезжает на другую платформу или сообщество делится детектом, логику приходится переписывать с нуля. Это долго, и при переписывании появляются ошибки.

Sigma отделяет логику детекта от языка запросов. Правило описывает источник логов и условие, бэкенд превращает это в запрос. Отсюда два следствия:

  • Правилом можно делиться, его можно ревьюить и версионировать как текст, так же, как код.
  • Одно и то же правило можно проверить на образцах событий до того, как оно попадёт в продуктивную SIEM.

Эта статья про второй пункт. Правило Sigma, которое парсится и конвертируется, ещё не готово: оно лишь синтаксически верно. Пользу оно приносит, когда вы можете показать, что оно срабатывает на нужных событиях и молчит на тех, которые должно игнорировать.

Из чего состоит правило

Вот правило, которое вы соберёте в лабораторной, с объяснением каждого поля.

yaml
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.t1110

UUID у вас будет другой. Сгенерируйте свой любой библиотекой UUID, например python -c "import uuid; print(uuid.uuid4())", и сохраняйте его при дальнейших правках правила. По id другие инструменты отслеживают одно и то же правило между версиями.

  • title — короткое название для людей. Оно появляется в алертах и списках правил.
  • id — UUID, который идентифицирует само правило, а его содержимое может меняться. При изменении логики оставляйте id прежним.
  • status говорит читателю, насколько правилу можно доверять. Допустимые значения: stable, test, experimental, deprecated и unsupported. Новому правилу, которое не проверяли в реальной среде, подходит experimental.
  • description в одном-двух предложениях говорит, что ищет правило.
  • logsource говорит, откуда приходят события. product: windows и service: security указывают на журнал Windows Security. Другие поля, например category, описывают класс логов, скажем создание процессов, без указания конкретного канала.
  • detection содержит логику сопоставления. Каждый именованный блок (здесь selection) — это набор условий по полям. Имена полей те же, что использует источник логов. С этими полями сравниваются значения.
  • condition говорит, как объединяются блоки. selection сам по себе означает «события, совпавшие с блоком selection». Позже вы добавите блоки-фильтры и объедините их через and и not.
  • falsepositives перечисляет безобидные случаи, которые тоже совпадут. Эта запись входит в правило наравне с остальными полями.
  • level — уровень серьёзности при срабатывании правила. Допустимые значения: informational, low, medium, high и critical. Выбирайте уровень по тому, что срабатывание значит для вашей среды, и не оглядывайтесь на то, как эффектно звучит техника.
  • tags привязывают правило к фреймворкам. Префикс attack. указывает на тактику MITRE ATT&CK, а attack.t1110 — на технику T1110, Brute Force.

Два замечания по этому правилу. Первое: EventID — имя поля в мире Sigma, оно соответствует Event ID, который вы видите в Event Viewer. Второе: level: low — осознанный выбор. Единичный неудачный вход встречается часто. В нынешнем виде правило срабатывает на каждый 4625, поэтому низкий уровень будет честной отправной точкой, пока вы не добавите порог.

Как Sigma ложится на язык запросов SIEM

Sigma ничего не знает о вашей SIEM. О ней знает бэкенд. Конвертер читает детект, применяет пайплайн обработки, который переименовывает поля и добавляет ограничения по индексу или источнику, и пишет запрос на целевом языке.

Пайплайн обработки — это набор правил сопоставления. Он отвечает на вопросы такого рода: как в Splunk называется поле Event ID, в каком индексе лежат события Windows Security и по какому sourcetype должен искать запрос. Без пайплайна конвертер может вывести имя поля Sigma как есть. На вашей платформе такой вывод часто непригоден.

У каждого бэкенда свои пайплайны. Некоторые обязательны: без них конвертер отказывается работать, если вы явно не попросите пропустить пайплайн. В лабораторной вы это увидите.

Идея простая: правило остаётся прежним, а пайплайн подгоняет его под платформу. При переезде со Splunk на другую SIEM вы меняете бэкенд и пайплайн, а детект не трогаете.

Лабораторная: пишем, проверяем и конвертируем правило

Лабораторная идёт на вашей машине. Домен, контроллер домена или какая-либо целевая система не нужны. Вы пишете и конвертируете правило. Неудачные входы вы ни против чего не генерируете, и не стоит пытаться делать это на системе, которая вам не принадлежит, если у вас нет письменного разрешения на её тестирование.

Лабораторная выполнялась на Windows 11 с Git Bash, Python 3.12 и стандартным журналом Windows Security. На Linux и macOS команды те же, отличается только путь к виртуальному окружению.

Шаг 1: создайте виртуальное окружение и установите sigma-cli

Создайте папку для лабораторной и выполните:

bash
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, поэтому активируйте его так:

bash
. .venv/Scripts/activate

Проверьте установку:

bash
sigma version

На машине, где готовилась статья, установились sigma-cli 4.0.0 с pysigma 2.0.2 и Python 3.12.10. У вас версии могут быть новее. В свои заметки записывайте то, что выведет команда, цифры выше для этого не годятся.

Шаг 2: напишите правило

Создайте файл failed_logon.yml с содержимым из предыдущего раздела. В поле id подставьте свой UUID. Сохраните файл в UTF-8, без табов в отступах YAML.

Шаг 3: проверьте правило

bash
sigma check failed_logon.yml

sigma check парсит файл и запускает валидаторы. Он находит отсутствующее поле, некорректный тег, неизвестный статус или уровень и ряд проблем стиля.

На машине, где готовилась статья, этот шаг не завершился. Валидатор тегов загружает данные MITRE ATT&CK по сети. Запрос вернул HTTP 504 gateway timeout, и ошибка повторялась при каждой новой попытке. На выходе был трейсбек, заканчивающийся строкой RuntimeError: Failed to load MITRE ATT&CK data, а код возврата равнялся 1.

Это сетевая зависимость, ошибки в правиле тут нет. Когда данные загрузятся, вы должны увидеть успешный результат или список замечаний валидатора. Если проверка падает с тем же сообщением про MITRE, повторите её позже или из сети, откуда доступны исходные данные. Не считайте правило проверенным, пока проверка не завершится.

Если проверка выдала замечания, прочитайте каждое. Исправляйте правило, а валидатор не трогайте. Замечание о теге обычно означает опечатку вроде attack.t1100 вместо attack.t1110.

Шаг 4: установите бэкенд Splunk

bash
sigma plugin install splunk

На машине, где готовилась статья, команда вывела Successfully installed plugin 'splunk' и pySigma version is compatible with sigma-cli.

Шаг 5: сконвертируйте без пайплайна

bash
sigma convert -t splunk --without-pipeline failed_logon.yml

Вывод:

text
Parsing Sigma rules
EventID=4625

Так правило выглядит до какого-либо маппинга под Splunk. Поле по-прежнему носит имя из Sigma, EventID. Поиск Splunk по событиям Windows обычно использует EventCode и source, поэтому при стандартной настройке Windows add-on этот запрос не найдёт нужные события.

Шаг 6: сконвертируйте с пайплайном Splunk

Попробуйте ту же конвертацию без --without-pipeline:

bash
sigma convert -t splunk failed_logon.yml

Конвертер остановился и объяснил, что бэкенду Splunk нужен пайплайн обработки. В сообщении было сказано добавлять --without-pipeline, только если вы понимаете, что делаете. Здесь пайплайн обязателен, поэтому без него конвертер запрос не выдаёт. Считайте это сообщение защитной мерой.

Теперь добавьте пайплайн для Windows:

bash
sigma list pipelines
sigma convert -t splunk -p splunk_windows failed_logon.yml

В списке оказалось три пайплайна Splunk: splunk_windows, splunk_sysmon_acceleration и splunk_cim. Конвертация с splunk_windows вывела:

text
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!. Не всякое правило конвертируется под любой пайплайн. Такая ошибка полезна: она говорит, что правило или бэкенд не подходит под запрошенный маппинг.

Шаг 7: сравните с событием, которое вы сгенерировали

В статье о журналах событий Windows вы смотрели событие в Event Viewer. Откройте его снова и сравните с запросом:

  • Поле Event ID в Event Viewer должно быть равно 4625. Именно это значение проверяет блок selection в Sigma.
  • В Event Viewer поле называется Event ID. В выводе Splunk оно выглядит как EventCode, потому что пайплайн приводит его к имени, которое использует Windows add-on.
  • source в запросе, WinEventLog:Security, соответствует каналу Security, который вы читали в Event Viewer.

Если у вашего события в Event Viewer Event ID отличается от 4625, правило его не поймает. Так и должно быть. Правило написано про неудачные входы, остальные события журнала его не касаются.

Проверка правила

Правило, которое конвертируется, всё ещё остаётся догадкой, пока вы его не протестируете. Минимальный тест состоит из двух половин:

  • Заведомо плохие события. События, на которых правило обязано сработать. Для этого правила это события 4625.
  • Заведомо хорошие события. События, на которых правило срабатывать не должно. Хорошие негативные примеры: успешные входы (4624), выходы из системы (4634) и создание процессов (4688).

Без негативных примеров у вас нет доказательств, что правило специфично. Без позитивных нет доказательств, что оно вообще работает.

В этой лабораторной тест использует небольшой файл-фикстуру с синтетическими событиями, events.json, в нём пять записей: два события 4625 и три события, которые не должны совпасть. Скрипт загружает блок selection из правила и проверяет каждое событие. Тест упрощён. Он показывает, что логика блока делает то, что вы написали. Проверку сконвертированного запроса на реальных данных он не заменяет.

python
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)

Файл-фикстура выглядит так:

json
[
  {"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"}
]

Запустите:

bash
python test_failed_logon.py

На машине, где готовилась статья, вывод был таким:

text
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:

yaml
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 и сконвертируйте тем же пайплайном:

bash
sigma convert -t splunk -p splunk_windows multi.yml

Вывод:

text
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 минут условные. Подберите их по своим данным и проверьте результат на тех же заведомо хороших и заведомо плохих событиях. Не каждый бэкенд поддерживает все типы корреляций, так что сверяйте вывод конвертера, прежде чем на него полагаться.

Первую версию правила сохраните. Это базовая линия, и сравнение с коррелированной версией покажет, помогает ли порог.

Частые ошибки

  • Написать правило и пропустить негативные примеры. Правило с одними позитивными тестами может совпадать со всем подряд и всё равно проходить. Добавляйте заведомо хорошие события намеренно.
  • Называть поле по подписи из Event Viewer. В Sigma это EventID. В Splunk после пайплайна это EventCode. Смешение двух имён в одном правиле ведёт к тихим пропускам.
  • Конвертировать без пайплайна и верить выводу. --without-pipeline — флаг для осознанного применения, срезать путь с ним не выйдет. Вывод может не запуститься на вашей платформе.
  • Ставить level: high шумному правилу. Серьёзность должна соответствовать тому, что значит срабатывание. Частое событие без контекста начинают с низкого уровня.
  • Забывать про поле falsepositives. Если вы не можете назвать безобидный случай, вы, скорее всего, пока недостаточно продумали среду.
  • Менять id при правке логики. id должен оставаться за правилом всё время его существования. Новое правило получает новый id. Отредактированное сохраняет свой.
  • Считать пройденную проверку доказательством. sigma check проверяет структуру файла. Находит ли детект нужные события, он не проверяет.

Что дальше

Когда правило проходит проверку, конвертируется и выдерживает тесты, следующие шаги очевидны:

  • Настройте правило корреляции на реальных данных: меняйте порог и временное окно и сравнивайте число срабатываний и ложных срабатываний с базовым правилом.
  • Прочитайте остальную спецификацию Sigma, чтобы узнать о фильтрах, модификаторах вроде |contains и |endswith и поле category.
  • Сконвертируйте то же правило для второго бэкенда, например Elastic или Splunk SPL2, и сравните запросы. Отметьте, где пайплайн меняет логику, а где только переименовывает поля.
  • Соберите набор фикстур побольше, добавив события из лаборатории, где вы контролируете активность. Неудачные входы генерируйте только на принадлежащих вам учётных записях и системах и только в лаборатории, которую вам разрешено тестировать.

Вкратце: правило — это утверждение о событиях. Запишите утверждение, сконвертируйте его, а затем подтвердите событиями, которые должны совпасть и которые не должны.

Источники

Источники

  1. SigmaHQ, Sigma specification
  2. SigmaHQ, Sigma rules documentation
  3. SigmaHQ, sigma-cli
  4. MITRE ATT&CK, T1110 Brute Force
  5. SigmaHQ, Sigma correlation rules specification

Ещё по теме: Детектирование и blue team

Детектирование и blue team

Что такое SIEM? Логи, запросы и алерты

SIEM собирает логи, нормализует их, применяет правила корреляции и поднимает алерты для триажа. Разбираем весь конвейер на примере, который можно запустить.

Начальный12 мин чтения