| | @@ -0,0 +1,77 @@ |
| + | # Detection-as-Code |
| + | |
| + | Detection rules kept the way code is kept: written once in [Sigma](https://sigmahq.io/), |
| + | version-controlled, linted and tested in CI, and compiled to whatever SIEM is in front of |
| + | me. I spend my day tuning rules in Sentinel and Splunk by hand; this is that work done as a |
| + | pipeline instead of a console click. |
| + | |
| + | Every rule here converts cleanly to **Splunk SPL**, **Elastic ES|QL**, and **Microsoft |
| + | Sentinel / Defender KQL**, and is tagged to MITRE ATT&CK so coverage is something you can |
| + | measure instead of guess at. |
| + | |
| + | ## Why |
| + | |
| + | A detection written in one SIEM's query language is stranded there. Writing it in Sigma |
| + | once and compiling it means the same logic ships to Splunk, Elastic, and Sentinel without |
| + | re-deriving it - and the rule gets reviewed, diffed, and tested like any other code. The |
| + | goal is fewer false positives and provable coverage, not more dashboards. |
| + | |
| + | ## Layout |
| + | |
| + | ``` |
| + | rules/ |
| + | windows/ credential-access, execution, persistence, defense-evasion, initial-access |
| + | linux/ credential-access, execution, persistence |
| + | tools/convert.py compile every rule to Splunk / Elastic / Sentinel |
| + | tests/test_rules.py schema, ATT&CK tagging, unique IDs, correlation references |
| + | .github/workflows/ lint -> test -> convert on every push |
| + | dist/ generated queries (CI artifact; gitignored) |
| + | ``` |
| + | |
| + | ## The rules |
| + | |
| + | Ten detections across both platforms, each mapped to ATT&CK and tuned past the naive |
| + | version (e.g. LSASS access filtered to the granted-access masks tooling actually uses, not |
| + | the broad `0x1010`). Full table in [docs/coverage.md](docs/coverage.md). |
| + | |
| + | | Technique | Detection | Platform | |
| + | |-----------|-----------|----------| |
| + | | T1003.001 | Suspicious LSASS process access | Windows | |
| + | | T1059.001 | PowerShell EncodedCommand | Windows | |
| + | | T1566 / T1059.001 | Office spawns scripting host / LOLBin | Windows | |
| + | | T1218.011 | Suspicious rundll32 | Windows | |
| + | | T1543.003 | New service installed | Windows | |
| + | | T1053.005 | Scheduled task created | Windows | |
| + | | T1110 | SSH brute force (correlation) | Linux | |
| + | | T1059.004 | Reverse shell one-liner | Linux | |
| + | | T1543.002 | Systemd persistence | Linux | |
| + | |
| + | ## Use it |
| + | |
| + | ```bash |
| + | pip install -r requirements.txt |
| + | sigma check rules/ # lint |
| + | pytest -q # schema + ATT&CK validation |
| + | python tools/convert.py # compile to dist/{splunk,esql,kusto}/ |
| + | ``` |
| + | |
| + | Convert a single rule on the fly: |
| + | |
| + | ```bash |
| + | sigma convert -t splunk -p sysmon rules/windows/credential-access/T1003.001_lsass_memory_access.yml |
| + | sigma convert -t kusto -p sysmon rules/windows/credential-access/T1003.001_lsass_memory_access.yml |
| + | ``` |
| + | |
| + | `convert.py` picks the right processing pipeline per rule from its `logsource` (Sysmon for |
| + | process/file telemetry, Windows-audit for Security/System channels). Correlation rules like |
| + | the SSH brute force are compiled together with the base rule they reference - `make |
| + | correlations` does that, since they need their referenced rule in the same collection. |
| + | |
| + | ## Validation |
| + | |
| + | CI lints with `sigma check`, runs the schema/ATT&CK test suite, and compiles all rules to |
| + | the three backends, failing on any conversion error. The rules themselves are validated |
| + | *behaviourally* in the companion [purple-team lab](https://github.com/zionboggan) - Atomic |
| + | Red Team fires each technique and the matching detection is confirmed in the Wazuh SIEM |
| + | before a rule is promoted here. The Wazuh-native versions of several of these live in the |
| + | [SOC automation lab](https://github.com/zionboggan/soc-automation-lab). |