← THE INDEX  ·  DETECTION ENG

Detection-as-Code

Detection rules treated like code: written once in Sigma, version-controlled, CI-tested, and compiled to three SIEMs from the same source.

Detection-as-Code

The problem with SIEM-native detections

A detection written in Splunk SPL is stranded in Splunk. Porting it to Sentinel means re-deriving the same logic in KQL, which introduces drift and makes coverage something you can only estimate. Writing the rule once in Sigma and compiling it solves both problems: the logic lives in one place, every SIEM target is generated from the same source, and the rule gets reviewed and diffed like any other code.

Every rule here converts to Splunk SPL, Elastic ES|QL, and Microsoft Sentinel / Defender KQL. Each one is tagged to MITRE ATT&CK so coverage is a number you can compute rather than guess at.

rules/windows/credential-access/T1003.001_lsass_memory_access.yml: Sigma rule for LSASS credential dumping
title: Suspicious LSASS Process Access
id: dcfda42d-c1a7-4106-aa96-7912201d9221
status: experimental
description: >
  Detects process access to lsass.exe with access rights commonly used to read
  process memory (credential dumping). Tuned to the granted-access masks seen with
  Mimikatz, comsvcs MiniDump, and similar tooling rather than the broad 0x1010 alone.
tags:
  - attack.credential_access
  - attack.t1003.001
logsource:
  product: windows
  category: process_access
detection:
  selection:
    TargetImage|endswith: '\lsass.exe'
    GrantedAccess:
      - '0x1010'
      - '0x1410'
      - '0x143a'
      - '0x1438'
      - '0x1fffff'
  filter_known:
    SourceImage|endswith:
      - '\wininit.exe'
      - '\csrss.exe'
      - '\MsMpEng.exe'
      - '\wmiprvse.exe'
  condition: selection and not filter_known
falsepositives:
  - EDR and AV products legitimately reading LSASS; baseline and add to filter_known.
level: high

Ten rules, three SIEMs, one pipeline

The rule set covers credential access, execution, persistence, and defense evasion across Windows and Linux:

  • T1003.001: Suspicious LSASS process access (tuned access masks, not just 0x1010)
  • T1059.001: PowerShell EncodedCommand
  • T1566 / T1059.001: Office spawns scripting host or LOLBin
  • T1218.011: Suspicious rundll32
  • T1543.003: New service installed
  • T1053.005: Scheduled task created
  • T1110: SSH brute force (correlation rule)
  • T1059.004: Reverse shell one-liner
  • T1543.002: Systemd persistence

convert.py picks the right processing pipeline per rule from its logsource field. Sysmon handles process/file telemetry; windows-audit covers Security/System channels. Correlation rules like the SSH brute force are compiled alongside their referenced base rules.

CI and behavioural validation

The GitHub Actions workflow lints with sigma check, runs the schema and ATT&CK test suite, and compiles all rules to all three backends, failing the build on any conversion error. That catches the common problem of writing a rule that looks valid but produces an empty query on the target backend.

The more important validation happens in the companion purple-team lab: Atomic Red Team fires each technique against an instrumented Ubuntu endpoint enrolled in the SOC automation lab, and the matching detection has to fire in Wazuh before the rule is promoted here. CI validates the rule structure; the purple-team lab validates that it actually catches the technique.