Zion Boggan zionboggan.com ↗
79 lines · markdown
History for this file →
1
# Detection-as-Code
2
 
3
Detection rules kept the way code is kept: written once in [Sigma](https://sigmahq.io/),
4
version-controlled, linted and tested in CI, and compiled to whatever SIEM is in front of
5
me. I spend my day tuning rules in Sentinel and Splunk by hand; this is that work done as a
6
pipeline instead of a console click.
7
 
8
Every rule here converts cleanly to **Splunk SPL**, **Elastic ES|QL**, and **Microsoft
9
Sentinel / Defender KQL**, and is tagged to MITRE ATT&CK so coverage is something you can
10
measure instead of guess at.
11
 
12
![One Sigma rule compiled to three SIEMs](docs/screenshots/01-multi-siem-conversion.png)
13
 
14
## Why
15
 
16
A detection written in one SIEM's query language is stranded there. Writing it in Sigma
17
once and compiling it means the same logic ships to Splunk, Elastic, and Sentinel without
18
re-deriving it - and the rule gets reviewed, diffed, and tested like any other code. The
19
goal is fewer false positives and provable coverage, not more dashboards.
20
 
21
## Layout
22
 
23
```
24
rules/
25
  windows/   credential-access, execution, persistence, defense-evasion, initial-access
26
  linux/     credential-access, execution, persistence
27
tools/convert.py        compile every rule to Splunk / Elastic / Sentinel
28
tests/test_rules.py     schema, ATT&CK tagging, unique IDs, correlation references
29
.github/workflows/      lint -> test -> convert on every push
30
dist/                   generated queries (CI artifact; gitignored)
31
```
32
 
33
## The rules
34
 
35
Ten detections across both platforms, each mapped to ATT&CK and tuned past the naive
36
version (e.g. LSASS access filtered to the granted-access masks tooling actually uses, not
37
the broad `0x1010`). Full table in [docs/coverage.md](docs/coverage.md).
38
 
39
| Technique | Detection | Platform |
40
|-----------|-----------|----------|
41
| T1003.001 | Suspicious LSASS process access | Windows |
42
| T1059.001 | PowerShell EncodedCommand | Windows |
43
| T1566 / T1059.001 | Office spawns scripting host / LOLBin | Windows |
44
| T1218.011 | Suspicious rundll32 | Windows |
45
| T1543.003 | New service installed | Windows |
46
| T1053.005 | Scheduled task created | Windows |
47
| T1110 | SSH brute force (correlation) | Linux |
48
| T1059.004 | Reverse shell one-liner | Linux |
49
| T1543.002 | Systemd persistence | Linux |
50
 
51
## Use it
52
 
53
```bash
54
pip install -r requirements.txt
55
sigma check rules/            # lint
56
pytest -q                     # schema + ATT&CK validation
57
python tools/convert.py       # compile to dist/{splunk,esql,kusto}/
58
```
59
 
60
Convert a single rule on the fly:
61
 
62
```bash
63
sigma convert -t splunk -p sysmon rules/windows/credential-access/T1003.001_lsass_memory_access.yml
64
sigma convert -t kusto  -p sysmon rules/windows/credential-access/T1003.001_lsass_memory_access.yml
65
```
66
 
67
`convert.py` picks the right processing pipeline per rule from its `logsource` (Sysmon for
68
process/file telemetry, Windows-audit for Security/System channels). Correlation rules like
69
the SSH brute force are compiled together with the base rule they reference - `make
70
correlations` does that, since they need their referenced rule in the same collection.
71
 
72
## Validation
73
 
74
CI lints with `sigma check`, runs the schema/ATT&CK test suite, and compiles all rules to
75
the three backends, failing on any conversion error. The rules themselves are validated
76
*behaviourally* in the companion [purple-team lab](https://github.com/zionboggan) - Atomic
77
Red Team fires each technique and the matching detection is confirmed in the Wazuh SIEM
78
before a rule is promoted here. The Wazuh-native versions of several of these live in the
79
[SOC automation lab](https://github.com/zionboggan/soc-automation-lab).