The Detection Gap
Most organizations have logs. Most have a SIEM. What most don't have is detection content that fires on real attacks. The gap isn't data collection - it's detection engineering.
Sigma is the open standard that closes this gap. It lets you write detection rules once and convert them to any SIEM query language - Splunk SPL, Elastic KQL, Microsoft Sentinel KQL, QRadar AQL, and dozens more. Think of it as YARA for logs.
This guide walks through writing Sigma rules that are precise enough to catch attacks and quiet enough to not drown your SOC in false positives.
Sigma Rule Anatomy
Every Sigma rule is a YAML file with a defined structure:
title: Suspicious PowerShell Download Cradle
id: 3b6ab547-1298-4a74-8f80-6a42df234567
status: experimental
description: |
Detects PowerShell commands using common download cradle patterns
such as Net.WebClient, Invoke-WebRequest, or Start-BitsTransfer.
references:
- https://attack.mitre.org/techniques/T1059/001/
author: Palavi Tech
date: 2026/03/28
tags:
- attack.execution
- attack.t1059.001
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith:
- '\cmd.exe'
- '\explorer.exe'
selection_powershell:
Image|endswith: '\powershell.exe'
CommandLine|contains:
- 'Net.WebClient'
- 'Invoke-WebRequest'
- 'IWR '
- 'Start-BitsTransfer'
- 'DownloadFile'
- 'DownloadString'
condition: selection_parent and selection_powershell
falsepositives:
- Legitimate software installers using PowerShell download
- SCCM or Intune deployment scripts
level: mediumKey Fields Explained
| Field | Purpose |
|---|---|
title | Human-readable name - shows up in alerts |
id | Unique UUID - used for rule tracking and correlation |
status | experimental, test, or stable - signals confidence level |
logsource | Defines which log data the rule applies to |
detection | The actual logic - selections and conditions |
level | Severity: informational, low, medium, high, critical |
falsepositives | Known FP scenarios - helps analysts triage |
tags | MITRE ATT&CK tags for framework mapping |
The Log Source: Getting It Right
The logsource field is where most beginners make mistakes. It's not just metadata - it determines which log pipeline the rule targets.
Common Log Sources
# Windows process creation (Sysmon Event ID 1 or Security 4688)
logsource:
category: process_creation
product: windows
# Windows PowerShell script block logging
logsource:
product: windows
service: powershell-scriptblock
# Windows Security event log
logsource:
product: windows
service: security
# Web proxy / firewall logs
logsource:
category: proxy
# DNS query logs
logsource:
category: dnsPro tip: Always prefer category over service when possible. Categories are SIEM-agnostic - the Sigma converter maps them to the correct event source for each backend. Service names are backend-specific and reduce portability.
Detection Logic: Selections and Conditions
The detection block is where the rule's precision lives. Understanding how selections compose is critical.
Selection Basics
A selection is a named set of field-value matches. Within a single selection, multiple values for the same field are OR'd, while different fields are AND'd:
detection:
selection:
Image|endswith: '\cmd.exe' # AND
CommandLine|contains:
- '/c whoami' # OR
- '/c ipconfig' # OR
- '/c net user' # OR
condition: selectionThis fires when cmd.exe runs with a command line containing any of those recon commands.
Combining Multiple Selections
Multiple named selections let you build complex logic:
detection:
selection_process:
Image|endswith: '\rundll32.exe'
selection_suspicious:
CommandLine|contains:
- 'javascript:'
- 'vbscript:'
- 'shell32.dll,Control_RunDLL'
filter_legitimate:
CommandLine|contains: 'desk.cpl'
ParentImage|endswith: '\explorer.exe'
condition: selection_process and selection_suspicious and not filter_legitimateThis catches suspicious rundll32.exe usage while filtering out the legitimate desktop settings invocation.
Modifier Reference
Modifiers transform how field values are matched:
| Modifier | Behavior | Example |
|---|---|---|
contains | Substring match | CommandLine|contains: '-enc' |
endswith | Suffix match | Image|endswith: '\powershell.exe' |
startswith | Prefix match | TargetFilename|startswith: 'C:\Temp\' |
re | Regular expression | CommandLine|re: '\\\\[0-9]{1,3}\\.' |
all | All values must match (AND instead of OR) | CommandLine|contains|all: |
base64 | Match base64-encoded variants | CommandLine|base64: 'IEX' |
cidr | IP range matching | SourceIP|cidr: '10.0.0.0/8' |
Five Rules Every SOC Should Deploy
Rule 1: LSASS Memory Access (Credential Dumping)
title: LSASS Memory Access via Process Handle
id: 8a5e3b2c-7d41-4f89-b123-456789abcdef
status: stable
description: |
Detects processes opening a handle to LSASS with memory read access,
a technique used by Mimikatz, ProcDump, and other credential dumpers.
author: Palavi Tech
date: 2026/03/28
tags:
- attack.credential_access
- attack.t1003.001
logsource:
category: process_access
product: windows
detection:
selection:
TargetImage|endswith: '\lsass.exe'
GrantedAccess|contains:
- '0x1010'
- '0x1410'
- '0x1438'
- '0x143a'
filter_system:
SourceImage|startswith:
- 'C:\Windows\System32\'
- 'C:\Program Files\Windows Defender\'
- 'C:\ProgramData\Microsoft\Windows Defender\'
condition: selection and not filter_system
falsepositives:
- Legitimate EDR/AV products accessing LSASS
- Windows Error Reporting
level: highWhy it matters: LSASS contains plaintext passwords, NTLM hashes, and Kerberos tickets. Any unexpected access is a critical signal.
Rule 2: Scheduled Task via Command Line (Persistence)
title: Scheduled Task Created via schtasks.exe
id: 9b6f4c3d-8e52-5a90-c234-567890bcdef0
status: stable
description: |
Detects the creation of scheduled tasks via schtasks.exe,
commonly used for persistence or lateral movement.
author: Palavi Tech
date: 2026/03/28
tags:
- attack.persistence
- attack.t1053.005
logsource:
category: process_creation
product: windows
detection:
selection:
Image|endswith: '\schtasks.exe'
CommandLine|contains|all:
- '/create'
selection_suspicious:
CommandLine|contains:
- '/sc onlogon'
- '/sc onidle'
- '/sc onstart'
- 'powershell'
- 'cmd.exe /c'
- 'mshta'
- 'rundll32'
- 'regsvr32'
- '\AppData\'
- '\Temp\'
- '\ProgramData\'
condition: selection and selection_suspicious
falsepositives:
- IT automation scripts creating legitimate scheduled tasks
- Software installation routines
level: mediumRule 3: DCSync Detection
title: Directory Service Replication from Non-DC Host
id: ac7g5d4e-9f63-6b01-d345-678901cdef12
status: stable
description: |
Detects directory replication requests (DCSync) originating from
machines that are not domain controllers, indicating credential theft.
author: Palavi Tech
date: 2026/03/28
tags:
- attack.credential_access
- attack.t1003.006
logsource:
product: windows
service: security
detection:
selection:
EventID: 4662
Properties|contains:
- '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2'
- '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2'
filter_dc:
SubjectUserName|endswith: '$'
SubjectUserName|contains:
- 'DC01'
- 'DC02'
condition: selection and not filter_dc
falsepositives:
- Azure AD Connect synchronization
level: criticalTuning note: Replace the DC name filter with your actual DC hostnames. This is the most environment-specific rule - get it right and it's one of the highest-fidelity detections you can deploy.
Rule 4: Suspicious DNS Query (C2 Beaconing)
title: DNS Query to Newly Registered or Suspicious TLD
id: bd8h6e5f-0a74-7c12-e456-789012def345
status: experimental
description: |
Detects DNS queries to TLDs and patterns commonly associated
with malware C2 infrastructure.
author: Palavi Tech
date: 2026/03/28
tags:
- attack.command_and_control
- attack.t1071.004
logsource:
category: dns
detection:
selection_tld:
query|endswith:
- '.top'
- '.xyz'
- '.club'
- '.work'
- '.click'
- '.surf'
- '.rest'
selection_pattern:
query|re: '^[a-z0-9]{16,}\.'
condition: selection_tld or selection_pattern
falsepositives:
- Legitimate websites on uncommon TLDs
- CDN subdomains with hash-based names
level: lowRule 5: Kerberoasting Detection
title: Kerberos Service Ticket Request with RC4 Encryption
id: ce9i7f6a-1b85-8d23-f567-890123efa456
status: stable
description: |
Detects Kerberos TGS requests using RC4 encryption, which may
indicate Kerberoasting activity targeting service account credentials.
author: Palavi Tech
date: 2026/03/28
tags:
- attack.credential_access
- attack.t1558.003
logsource:
product: windows
service: security
detection:
selection:
EventID: 4769
TicketEncryptionType: '0x17'
Status: '0x0'
filter_machine:
ServiceName|endswith: '$'
filter_krbtgt:
ServiceName: 'krbtgt'
condition: selection and not filter_machine and not filter_krbtgt
falsepositives:
- Legacy systems that only support RC4 encryption
- Environments that haven't migrated to AES
level: highConverting Sigma to Your SIEM
Sigma rules are SIEM-agnostic - you need a converter to transform them into your platform's query language.
Using sigma-cli
# Install
pip install sigma-cli pySigma-backend-splunk pySigma-pipelines-sysmon
# Convert to Splunk SPL
sigma convert -t splunk -p sysmon rule.yml
# Convert to Elastic/Lucene
sigma convert -t elasticsearch-lucene -p ecs_windows rule.yml
# Convert to Microsoft Sentinel KQL
sigma convert -t microsoft365defender rule.ymlExample Conversion
The LSASS access rule converted to Splunk:
index=sysmon EventCode=10
TargetImage="*\\lsass.exe"
(GrantedAccess="*0x1010*" OR GrantedAccess="*0x1410*"
OR GrantedAccess="*0x1438*" OR GrantedAccess="*0x143a*")
NOT (SourceImage="C:\\Windows\\System32\\*"
OR SourceImage="C:\\Program Files\\Windows Defender\\*")And the same rule in Elastic KQL:
event.code: "10" AND winlog.event_data.TargetImage: *\\lsass.exe
AND winlog.event_data.GrantedAccess: (*0x1010* OR *0x1410* OR *0x1438* OR *0x143a*)
AND NOT winlog.event_data.SourceImage: (C\:\\Windows\\System32\\* OR C\:\\Program\ Files\\Windows\ Defender\\*)Reducing False Positives
The difference between a rule that works and a rule that gets disabled is tuning. Here's a systematic approach:
Step 1: Deploy in Audit Mode
Run the rule for 1-2 weeks without triggering alerts. Log the matches and review them:
# Set level to informational during tuning
level: informational
status: experimentalStep 2: Analyze the Noise
For each false positive, ask:
- Is it a known-good process? Add it to the filter section
- Is it a known-good parent process? Filter by
ParentImage - Is it only from specific machines? Filter by
ComputerName(but document why) - Is the rule too broad? Tighten the selection modifiers
Step 3: Build Environment-Specific Filters
detection:
selection:
# ... attack detection logic ...
filter_sccm:
ParentImage|endswith: '\ccmexec.exe'
filter_monitoring:
SourceImage|contains:
- '\CrowdStrike\'
- '\SentinelOne\'
- '\Tanium\'
condition: selection and not 1 of filter_*Step 4: Promote to Production
Once the rule fires only on true positives (or near-true positives with known, documented FP scenarios), promote it:
status: stable
level: high # or whatever severity is appropriateTesting Your Rules
Before deploying to production, validate against known-bad activity:
Atomic Red Team
# Install
Install-Module -Name AtomicRedTeam
# Run the T1003.001 test (LSASS credential dumping)
Invoke-AtomicTest T1003.001 -TestNumbers 1
# Verify your LSASS access rule firesManual Validation
For each rule, create a test case document:
test:
rule: LSASS Memory Access via Process Handle
steps:
- Run: procdump.exe -ma lsass.exe lsass.dmp
- Expected: Alert fires within 60 seconds
- Fields to verify:
- SourceImage contains procdump
- TargetImage contains lsass
- GrantedAccess matches selection
cleanup:
- Delete lsass.dmp
- Confirm no residual artifactsOrganizing a Detection Rule Library
As your rule set grows, structure matters:
sigma-rules/
├── credential_access/
│ ├── lsass_memory_access.yml
│ ├── dcsync_detection.yml
│ └── kerberoasting_rc4.yml
├── persistence/
│ ├── scheduled_task_creation.yml
│ └── registry_run_key.yml
├── command_and_control/
│ ├── suspicious_dns_tld.yml
│ └── beaconing_pattern.yml
├── execution/
│ └── powershell_download_cradle.yml
└── README.mdTrack rules in version control. Every change should be a commit with context - what broke, what was tuned, what FP was eliminated.
Key Takeaways
Write rules for behaviors, not indicators. IOC-based rules go stale in days. Behavioral rules (process accessing LSASS, RC4 Kerberos tickets) catch variants for years.
The
falsepositivesfield is not optional. If you can't list known FPs, you haven't tested the rule. This field saves your SOC analysts hours of triage.Start with five high-fidelity rules, not fifty noisy ones. A SOC that trusts its alerts investigates faster than one drowning in noise.
Test every rule against Atomic Red Team before production. A rule that doesn't fire on known-bad is worse than no rule - it gives false confidence.
Sigma is a starting point, not an endpoint. Convert, test, tune for your environment, and document every filter. The generic rule is 60% of the work - the last 40% is what makes it production-ready.
Good detections are tuned, not just written. More hands-on security walkthroughs on the BytesCop blog.

