Side view of crop anonymous cyber spy in hoodie hacking computer system with information on screen at night

Sigma Rules: Writing Detections That Port Across Any SIEM

Detection logic written in one SIEM’s query language is trapped there. Change platform, or work across two of them, and you rewrite everything by hand. Sigma rules solve that: the detection is YAML, and a compiler turns it into whatever query language you actually run.

What Sigma rules actually are

A Sigma rule describes three things: which log source it applies to, what pattern counts as a match, and the metadata a human needs to triage it. It deliberately says nothing about your field names or index layout. That mapping lives in a separate pipeline, which is why the same rule can target Sysmon on one estate and Windows Event Log on another.

The public SigmaHQ repository ships several thousand of these. That matters more than the format itself: you are inheriting a community rule set instead of starting from an empty search bar.

Anatomy of a rule

Here is a complete, working rule for encoded PowerShell execution. Save it as proc_creation_win_powershell_encoded.yml.

title: Encoded PowerShell Command Line
id: 3d4f6a12-9b77-4c2e-8f51-0d1a77b6e9c4
status: experimental
description: Detects powershell.exe launched with a base64 encoded command,
  a common first stage in loader and phishing payload chains.
author: Jonathan Mitchell
date: 2026/09/14
logsource:
    product: windows
    category: process_creation
detection:
    selection_img:
        Image|endswith: '\powershell.exe'
    selection_flag:
        CommandLine|contains:
            - ' -enc '
            - ' -EncodedCommand '
            - ' -ec '
    filter_sccm:
        ParentImage|endswith: '\ccmexec.exe'
    condition: selection_img and selection_flag and not filter_sccm
falsepositives:
    - Configuration management agents wrapping their own scripts
    - Vendor installers that encode a post-install step
level: high
tags:
    - attack.execution
    - attack.t1059.001

Two conventions are worth copying. Split the selection into named blocks rather than one big map, because it makes the condition readable. And write every exclusion as a filter_ block joined with not, so the exception is visible in the rule rather than buried in a saved search somewhere.

Installing the sigma CLI

pipx install sigma-cli
sigma plugin list
sigma plugin install splunk
sigma plugin install elasticsearch
sigma version

Backends are plugins; so are pipelines. sigma plugin list shows what is available and what you have, and it is the fastest way to find out whether your platform is supported before you invest in writing rules for it.

Converting to two backends

Same rule, two very different query languages. First Splunk, with the Sysmon pipeline so Image maps to the Sysmon event fields:

sigma convert -t splunk -p sysmon proc_creation_win_powershell_encoded.yml
Image="*\\powershell.exe" (CommandLine="* -enc *" OR CommandLine="* -EncodedCommand *"
OR CommandLine="* -ec *") NOT ParentImage="*\\ccmexec.exe"

Now Elasticsearch, emitting Lucene against ECS-normalised Windows logs:

sigma convert -t elasticsearch -f lucene -p ecs_windows \
  proc_creation_win_powershell_encoded.yml
process.executable:*\\powershell.exe AND (process.command_line:* \-enc * OR
process.command_line:* \-EncodedCommand * OR process.command_line:* \-ec *)
AND (NOT process.parent.executable:*\\ccmexec.exe)

Note what changed: not just the syntax, but the field names. Image became process.executable because the ECS pipeline said so. That separation is the whole value proposition — swap the -p and the rule follows your schema.

Add -f siem_rule on the Elasticsearch backend and you get a ready-to-import detection rule object rather than a bare query, which is how you get from a YAML directory to something that alerts without clicking through a UI.

Keeping the rule set honest

  • Run sigma check rules/ in CI. It catches schema errors, duplicate UUIDs and broken conditions before they reach the SIEM.
  • Convert a whole directory at once with sigma convert -t splunk -p sysmon rules/windows/process_creation/ and diff the output between runs — an unexpected query change usually means a pipeline updated under you.
  • Tune with filter_ blocks in the rule, committed to git, not with per-platform exclusions. Otherwise the portability you paid for evaporates the first time you migrate.
  • Set level honestly. Everything marked critical means nothing is.

Sigma rules cover single events well and stateful correlation poorly. Sigma does have correlation rules now, but backend support is uneven, so anything involving counts over time is still better expressed natively. That is the boundary where portable detection stops and platform-specific threat hunting and detection engineering takes over.

My recommendation

Treat your detections as a git repository of Sigma rules and your SIEM as a build target, not as the place the logic lives. Clone SigmaHQ, convert the subset relevant to the logs you actually collect, and write your exclusions as filters in the YAML. It takes an afternoon, and it means the next platform migration costs you a re-run of sigma convert rather than a quarter of rewriting.


Leave a Reply