Zion Boggan zionboggan.com ↗

sigma rules: windows + linux detections mapped to ATT&CK

754c2db   Zion Boggan committed on May 29, 2026 (3 weeks ago)
.gitignore +6 -0
@@ -0,0 +1,6 @@
+dist/
+__pycache__/
+*.pyc
+.pytest_cache/
+.venv/
+venv/
requirements.txt +8 -0
@@ -0,0 +1,8 @@
+sigma-cli==3.0.2
+pysigma-backend-splunk==2.1.0
+pysigma-backend-elasticsearch==2.0.3
+pysigma-backend-kusto==1.0.1
+pysigma-pipeline-sysmon==2.0.0
+pysigma-pipeline-windows==2.0.0
+pytest==8.3.3
+PyYAML==6.0.3
rules/linux/credential-access/T1110_ssh_bruteforce.yml +24 -0
@@ -0,0 +1,24 @@
+title: SSH Brute Force
+id: 975ada2e-e9a5-4ac0-b420-f8c020c64a24
+status: experimental
+description: >
+ Correlates repeated SSH authentication failures from a single source within a short
+ window. This is the alerting rule; the per-event base rule (ssh_auth_failure) is
+ informational on its own.
+references:
+ - https://attack.mitre.org/techniques/T1110/
+author: Zion Boggan
+date: 2026-05-15
+tags:
+ - attack.credential_access
+ - attack.t1110
+correlation:
+ type: event_count
+ rules:
+ - ssh_auth_failure
+ group-by:
+ - src_ip
+ timespan: 2m
+ condition:
+ gte: 8
+level: high
rules/linux/credential-access/T1110_ssh_failed_auth.yml +24 -0
@@ -0,0 +1,24 @@
+title: SSH Authentication Failure
+name: ssh_auth_failure
+id: cc6fd1c9-b264-4be8-bb53-b6f4e2af9776
+status: experimental
+description: Base detection for a single failed SSH authentication, used by the brute-force correlation.
+references:
+ - https://attack.mitre.org/techniques/T1110/
+author: Zion Boggan
+date: 2026-05-15
+tags:
+ - attack.credential_access
+ - attack.t1110
+logsource:
+ product: linux
+ service: sshd
+detection:
+ selection:
+ - Message|contains: 'Failed password for'
+ - Message|contains: 'Invalid user'
+ - Message|startswith: 'Connection closed by authenticating user'
+ condition: selection
+falsepositives:
+ - Users fat-fingering passwords; the correlation rule is what should alert.
+level: informational
rules/linux/execution/T1059.004_reverse_shell.yml +35 -0
@@ -0,0 +1,35 @@
+title: Potential Reverse Shell via Shell Interpreter
+id: 389cb62c-20d8-4367-a9e7-a809e0ba71d0
+status: experimental
+description: >
+ Detects common reverse-shell one-liners spawned through a Unix shell - bash/sh redirecting
+ to a TCP device, or interpreters opening a socket back to an attacker.
+references:
+ - https://attack.mitre.org/techniques/T1059/004/
+ - https://gtfobins.github.io/
+author: Zion Boggan
+date: 2026-05-16
+tags:
+ - attack.execution
+ - attack.t1059.004
+logsource:
+ product: linux
+ category: process_creation
+detection:
+ selection_bash_tcp:
+ CommandLine|contains:
+ - '/dev/tcp/'
+ - '/dev/udp/'
+ selection_interpreters:
+ CommandLine|contains:
+ - 'socket.socket('
+ - 'sh -i'
+ - 'bash -i'
+ - 'mkfifo /tmp/'
+ - 'nc -e'
+ - 'ncat -e'
+ - 'socat tcp'
+ condition: selection_bash_tcp or selection_interpreters
+falsepositives:
+ - Legitimate use of netcat/socat by admins; baseline expected usage.
+level: high
rules/linux/persistence/T1543.002_systemd_service_persistence.yml +35 -0
@@ -0,0 +1,35 @@
+title: Systemd Service Created in User-Writable or Temp Path
+id: d4a5c6f7-0f65-4c8c-a1a7-d4428e73bb05
+status: experimental
+description: >
+ Detects creation of a systemd unit file outside the standard package-managed locations
+ or pointing ExecStart at a temp/home path - a common Linux persistence technique.
+references:
+ - https://attack.mitre.org/techniques/T1543/002/
+author: Zion Boggan
+date: 2026-05-16
+tags:
+ - attack.persistence
+ - attack.t1543.002
+logsource:
+ product: linux
+ category: file_event
+detection:
+ selection_unit:
+ TargetFilename|endswith: '.service'
+ TargetFilename|contains:
+ - '/etc/systemd/system/'
+ - '/.config/systemd/user/'
+ - '/run/systemd/system/'
+ filter_pkg:
+ Image|endswith:
+ - '/dpkg'
+ - '/rpm'
+ - '/apt'
+ - '/yum'
+ - '/dnf'
+ - '/systemctl'
+ condition: selection_unit and not filter_pkg
+falsepositives:
+ - Admins hand-installing units; baseline known unit deployments.
+level: medium
rules/windows/credential-access/T1003.001_lsass_memory_access.yml +37 -0
@@ -0,0 +1,37 @@
+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.
+references:
+ - https://attack.mitre.org/techniques/T1003/001/
+ - https://github.com/SwiftOnSecurity/sysmon-config
+author: Zion Boggan
+date: 2026-05-12
+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
rules/windows/defense-evasion/T1218.011_rundll32_suspicious.yml +34 -0
@@ -0,0 +1,34 @@
+title: Suspicious Rundll32 Execution
+id: c7b35acf-1122-4446-8d2d-95e7883f1064
+status: experimental
+description: >
+ Detects rundll32.exe invoked in patterns associated with proxy execution of malicious
+ code: no DLL argument, javascript: protocol handlers, or execution from user-writable paths.
+references:
+ - https://attack.mitre.org/techniques/T1218/011/
+ - https://lolbas-project.github.io/lolbas/Binaries/Rundll32/
+author: Zion Boggan
+date: 2026-05-13
+tags:
+ - attack.defense_evasion
+ - attack.t1218.011
+logsource:
+ product: windows
+ category: process_creation
+detection:
+ selection_img:
+ Image|endswith: '\rundll32.exe'
+ selection_patterns:
+ CommandLine|contains:
+ - 'javascript:'
+ - 'mshtml,RunHTMLApplication'
+ - '.dll,#1'
+ - '\AppData\'
+ - '\Temp\'
+ - '\ProgramData\'
+ selection_nodll:
+ CommandLine|re: 'rundll32(\.exe)?["'']?\s*$'
+ condition: selection_img and (selection_patterns or selection_nodll)
+falsepositives:
+ - Rare legitimate use; baseline expected DLL invocations.
+level: high
rules/windows/execution/T1059.001_powershell_encoded_command.yml +37 -0
@@ -0,0 +1,37 @@
+title: PowerShell EncodedCommand Execution
+id: 99410337-d137-401f-ac19-3977cfa523a4
+status: experimental
+description: >
+ Detects PowerShell launched with an encoded command payload, frequently used to
+ hide intent during initial access and execution. Pairs an -EncodedCommand style flag
+ with the common evasion switches.
+references:
+ - https://attack.mitre.org/techniques/T1059/001/
+author: Zion Boggan
+date: 2026-05-12
+tags:
+ - attack.execution
+ - attack.t1059.001
+logsource:
+ product: windows
+ category: process_creation
+detection:
+ selection_img:
+ - Image|endswith: '\powershell.exe'
+ - Image|endswith: '\pwsh.exe'
+ - OriginalFileName: 'PowerShell.EXE'
+ selection_enc:
+ CommandLine|contains:
+ - ' -enc '
+ - ' -encodedcommand '
+ - ' -ec '
+ selection_flags:
+ CommandLine|contains:
+ - ' -nop'
+ - ' -noprofile'
+ - ' -w hidden'
+ - ' -windowstyle hidden'
+ condition: selection_img and (selection_enc or selection_flags)
+falsepositives:
+ - Some management tooling and installers use encoded commands; baseline by parent process.
+level: medium
rules/windows/initial-access/T1566_office_spawns_lolbin.yml +41 -0
@@ -0,0 +1,41 @@
+title: Office Application Spawns Scripting or LOLBin Process
+id: 67a438b8-b930-4760-ab4e-99810ad450a3
+status: experimental
+description: >
+ Detects a Microsoft Office application spawning a script interpreter or living-off-the-land
+ binary, a classic phishing-to-execution pivot (macro or exploit dropping a child process).
+references:
+ - https://attack.mitre.org/techniques/T1566/
+ - https://attack.mitre.org/techniques/T1059/
+author: Zion Boggan
+date: 2026-05-13
+tags:
+ - attack.initial_access
+ - attack.t1566.001
+ - attack.execution
+ - attack.t1059.001
+logsource:
+ product: windows
+ category: process_creation
+detection:
+ selection:
+ ParentImage|endswith:
+ - '\winword.exe'
+ - '\excel.exe'
+ - '\powerpnt.exe'
+ - '\outlook.exe'
+ - '\mspub.exe'
+ Image|endswith:
+ - '\cmd.exe'
+ - '\powershell.exe'
+ - '\pwsh.exe'
+ - '\wscript.exe'
+ - '\cscript.exe'
+ - '\mshta.exe'
+ - '\rundll32.exe'
+ - '\regsvr32.exe'
+ - '\bitsadmin.exe'
+ condition: selection
+falsepositives:
+ - Some enterprise document templates legitimately call scripts; rare, baseline per environment.
+level: high
rules/windows/persistence/T1053.005_scheduled_task_creation.yml +34 -0
@@ -0,0 +1,34 @@
+title: Scheduled Task Created via Security Log
+id: 7f08d779-de77-47cd-9d21-48774fdb1225
+status: experimental
+description: >
+ Detects creation of a scheduled task (Security event 4698). Scheduled tasks are a durable
+ persistence and execution mechanism; tuned to flag tasks running interpreters or binaries
+ from user-writable locations.
+references:
+ - https://attack.mitre.org/techniques/T1053/005/
+author: Zion Boggan
+date: 2026-05-14
+tags:
+ - attack.persistence
+ - attack.t1053.005
+ - attack.execution
+logsource:
+ product: windows
+ service: security
+detection:
+ selection:
+ EventID: 4698
+ selection_susp:
+ TaskContent|contains:
+ - 'powershell'
+ - 'mshta'
+ - 'rundll32'
+ - 'cmd.exe'
+ - '\AppData\'
+ - '\Temp\'
+ - '\Users\Public\'
+ condition: selection and selection_susp
+falsepositives:
+ - Legitimate software and admin tasks; baseline scheduled tasks per environment.
+level: medium
rules/windows/persistence/T1543.003_new_service_creation.yml +35 -0
@@ -0,0 +1,35 @@
+title: New Windows Service Installed
+id: adfa52d1-fd8a-4095-ae3f-5708ec0ff71b
+status: experimental
+description: >
+ Detects installation of a new Windows service (System event 7045). Service creation is a
+ common persistence and privilege-execution mechanism; tuned to flag services pointing at
+ user-writable paths or script interpreters.
+references:
+ - https://attack.mitre.org/techniques/T1543/003/
+author: Zion Boggan
+date: 2026-05-14
+tags:
+ - attack.persistence
+ - attack.t1543.003
+logsource:
+ product: windows
+ service: system
+detection:
+ selection:
+ EventID: 7045
+ Provider_Name: 'Service Control Manager'
+ selection_susp:
+ ImagePath|contains:
+ - '\Users\'
+ - '\AppData\'
+ - '\Temp\'
+ - '\ProgramData\'
+ - 'powershell'
+ - 'cmd.exe /c'
+ - 'cmd /c'
+ - 'rundll32'
+ condition: selection and selection_susp
+falsepositives:
+ - Some software installs services from ProgramData; baseline known-good ImagePaths.
+level: high
tests/test_rules.py +59 -0
@@ -0,0 +1,59 @@
+import re
+from pathlib import Path
+
+import pytest
+import yaml
+
+RULES = sorted((Path(__file__).resolve().parents[1] / "rules").rglob("*.yml"))
+TACTIC_TAGS = {
+ "attack.reconnaissance", "attack.resource_development", "attack.initial_access",
+ "attack.execution", "attack.persistence", "attack.privilege_escalation",
+ "attack.defense_evasion", "attack.credential_access", "attack.discovery",
+ "attack.lateral_movement", "attack.collection", "attack.command_and_control",
+ "attack.exfiltration", "attack.impact",
+}
+TECHNIQUE_RE = re.compile(r"^attack\.t\d{4}(\.\d{3})?$")
+
+
+def load(path):
+ return yaml.safe_load(path.read_text())
+
+
+def test_rules_exist():
+ assert RULES, "no rules found"
+
+
+@pytest.mark.parametrize("path", RULES, ids=[p.name for p in RULES])
+def test_rule_schema(path):
+ rule = load(path)
+ for field in ("title", "id", "status", "description", "tags", "level"):
+ assert rule.get(field), f"{path.name} missing {field}"
+ assert "detection" in rule or "correlation" in rule, f"{path.name} has no detection/correlation"
+ assert rule["level"] in {"informational", "low", "medium", "high", "critical"}
+ assert rule["status"] in {"experimental", "test", "stable", "deprecated", "unsupported"}
+
+
+@pytest.mark.parametrize("path", RULES, ids=[p.name for p in RULES])
+def test_attack_tags(path):
+ tags = load(path).get("tags", [])
+ techniques = [t for t in tags if TECHNIQUE_RE.match(t)]
+ assert techniques, f"{path.name} has no ATT&CK technique tag"
+ for t in tags:
+ if t.startswith("attack."):
+ assert t in TACTIC_TAGS or TECHNIQUE_RE.match(t), f"{path.name} bad tag {t}"
+
+
+def test_unique_ids():
+ ids = [load(p)["id"] for p in RULES]
+ dupes = {i for i in ids if ids.count(i) > 1}
+ assert not dupes, f"duplicate rule ids: {dupes}"
+
+
+def test_correlation_refs_resolve():
+ names = {load(p).get("name") for p in RULES if load(p).get("name")}
+ for path in RULES:
+ rule = load(path)
+ corr = rule.get("correlation")
+ if corr:
+ for ref in corr.get("rules", []):
+ assert ref in names, f"{path.name} references unknown rule '{ref}'"