SIEM Detection Rules That Actually Work: Splunk, Elastic, and Wazuh Guide

A SIEM with no rules is just an expensive log storage system. The real value comes from detection logic that catches real attacks with minimal false positives. This guide teaches you to write, tune, and deploy detection rules in the three most popular open-source SIEM platforms.

Critical Log Sources to Collect

# Windows: Enable these Event IDs via Group Policy
# 4624/4625 - Logon success/failure
# 4648 - Explicit credential use (runas)
# 4720/4722-4726 - Account creation/modification/deletion
# 4728/4729/4732/4733 - Group membership changes
# 4768/4769/4771 - Kerberos TGT/TGS/pre-auth failure
# 5140/5145 - Network share access
# 7045 - New service installed (common persistence)

# Install Sysmon for rich telemetry (process, network, file)
Invoke-WebRequest https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml -OutFile sysmonconfig.xml
sysmon64.exe -accepteula -i sysmonconfig.xml

# Sysmon Event IDs:
# 1  = Process creation
# 3  = Network connection
# 7  = Image loaded (DLL)
# 8  = CreateRemoteThread (injection indicator)
# 10 = Process access (LSASS dumping)
# 11 = File created
# 12/13 = Registry object created/modified
# 22 = DNS query

Wazuh Custom Detection Rules

# File: /var/ossec/etc/rules/local_rules.xml

<!-- New Windows service installed (persistence technique T1543.003) -->
<rule id="100100" level="12">
  <if_sid>7045</if_sid>
  <description>New Windows service installed: $(win.eventdata.serviceName)</description>
  <mitre><id>T1543.003</id></mitre>
  <group>windows,persistence,</group>
</rule>

<!-- Domain Admin group membership change -->
<rule id="100101" level="14">
  <if_sid>4728</if_sid>
  <field name="win.eventdata.targetUserName">^Domain Admins$</field>
  <description>User added to Domain Admins: $(win.eventdata.memberName)</description>
  <mitre><id>T1098</id></mitre>
  <group>windows,privilege_escalation,</group>
</rule>

<!-- Mass file modification (ransomware indicator) -->
<rule id="100102" level="15" timeframe="60" frequency="100">
  <if_matched_sid>554</if_matched_sid>
  <same_field>agent.id</same_field>
  <description>Possible ransomware: Mass file modification on $(agent.name)</description>
</rule>

Splunk Detection Queries

# Brute force: 10+ failed logins in 5 minutes
index=windows EventCode=4625
| bucket _time span=5m
| stats count by src_ip dest_host _time
| where count >= 10

# Ransomware: mass file extension changes
index=windows EventCode=4663
| rex field=ObjectName ".(?P<extension>[^.]+)$"
| where NOT extension IN ("docx","xlsx","pdf","jpg","png","txt","log")
| stats count by host extension
| where count > 100

# PowerShell suspicious download cradles
index=windows EventCode=4104
| search ScriptBlockText="*Invoke-WebRequest*" OR ScriptBlockText="*DownloadString*" OR ScriptBlockText="*WebClient*"
| table _time, host, user, ScriptBlockText

# Golden Ticket detection: TGS tickets with unusual encryption
index=windows EventCode=4769
| where TicketEncryptionType="0x17" AND ServiceName!="krbtgt"
| stats count by user ServiceName ClientAddress

Elastic/KQL Detection Rules

# LSASS process access (credential dumping T1003.001)
event.code: 10 AND
winlog.event_data.TargetImage: *lsass.exe AND
NOT winlog.event_data.SourceImage: (C:\Windows\System32\* OR C:\Windows\SysWOW64\*)

# WMI persistence (T1546.003)
event.code: (19 OR 20 OR 21)

# Suspicious scheduled task creation (T1053.005)
event.code: 4698 AND
NOT winlog.event_data.SubjectUserName: SYSTEM AND
winlog.event_data.TaskName: (*update* OR *backup* OR *sync*)

# Kerberos pre-auth failure (AS-REP Roasting T1558.004)
event.code: 4768 AND winlog.event_data.Status: "0x18"

Sigma Rules: Write Once, Deploy Anywhere

# Install sigma-cli
pip3 install sigma-cli sigma-backend-splunk sigma-backend-elasticsearch

# Example Sigma rule: PowerShell download cradle
title: PowerShell Download Cradle
status: stable
logsource:
  category: process_creation
  product: windows
detection:
  selection:
    CommandLine|contains:
      - Invoke-WebRequest
      - DownloadString
      - DownloadFile
      - Net.WebClient
  condition: selection
falsepositives:
  - Legitimate admin scripts
level: high
tags:
  - attack.execution
  - attack.t1059.001

# Convert to Splunk
sigma convert -t splunk powershell_download.yml

# Convert to Elastic EQL
sigma convert -t eql powershell_download.yml

# Browse 3000+ community rules
git clone https://github.com/SigmaHQ/sigma.git
ls sigma/rules/windows/

Alert Tuning: Eliminating False Positives

# Step 1: Measure false positive rate
# FP rate = alerts with no action taken / total alerts
# Target: less than 20% FP rate on high-severity alerts

# Step 2: Add smart exclusions
# BAD exclusion: exclude all certutil events (hides real attacks)
# GOOD exclusion: exclude certutil from SCCM service account on patch Tuesday
index=windows CommandLine="*certutil*"
| where NOT (ParentImage="*ccmexec.exe" AND user="svc_sccm")

# Step 3: Require corroboration for high-noise rules
# Brute force + impossible travel = much higher confidence
index=windows EventCode=4625
| lookup user_baseline user OUTPUT normal_country
| iplocation src_ip
| where Country != normal_country AND count > 5

# Step 4: Alert enrichment (makes alerts actionable)
| lookup asset_inventory dest_ip OUTPUT asset_tier owner criticality
| where asset_tier="Tier 0"  # Only alert on critical assets
SIEMBest ForFree TierDifficulty
WazuhComplete platform + agentsUnlimitedMedium
Elastic SIEMLarge environmentsUnlimited (self-hosted)High
SplunkEnterprise SOC500MB/dayHigh
GraylogLog management basics5GB/dayLow

Start with Wazuh for your first SIEM deployment. Deploy agents on all endpoints, enable Sysmon, and work through the default rule set before writing custom rules. Once you understand what good alerts look like, the transition to Splunk or Elastic becomes much more productive.