SPL (Splunk Processing Language) is the query language for Splunk SIEM. It’s the most widely deployed SIEM query language in enterprise environments. The pipe model makes it readable but has some quirks — especially around performance.
The Core SPL Commands
search (the implicit first command)
index=windows EventCode=4625
Splunk’s search is implicit — the first pipe stage is always a search. Always start with:
- An index or source filter (
index=windows) - One or more field=value pairs that narrow the result set
index=windows EventCode=4688 NewProcessName="*powershell.exe"
This searches Windows events for 4688 (process creation) where NewProcessName ends in powershell.exe.
Performance rule: The more specific your initial search, the less data the subsequent commands process.
stats — aggregate everything
index=windows EventCode=4625
| stats count as FailCount, dc(WorkstationName) as UniqueHosts, values(LogonType) as LogonTypes
by TargetUserName
| where FailCount > 10
| sort -FailCount
Result: a table with one row per username showing their total failed logon count, how many distinct workstations they failed on, and which logon types were used.
Common stats functions:
| Function | What it does |
|---|---|
count | Total events |
dc(field) | Distinct count of field values |
values(field) | List of unique field values |
list(field) | List of all field values (may repeat) |
avg(field) | Numeric average |
sum(field) | Numeric sum |
earliest(field) | Earliest value |
latest(field) | Latest value |
first(field) | First occurrence in time |
eval — compute and transform
index=windows EventCode=4688
| eval IsElevated=if(IntegrityLevel="High" OR IntegrityLevel="System", "YES", "NO")
| eval ProcessBin=lower(mvindex(split(NewProcessName, "\\"), -1))
| where IsElevated="YES" AND ProcessBin IN ("powershell.exe", "cmd.exe", "wscript.exe")
| stats count by host, TargetUserName, ProcessBin
eval in detail:
if(condition, true_value, false_value)— conditionallower(str)— lowercasesplit(str, delim)— split string into multivalue fieldmvindex(mv_field, index)— get element from multivalue fieldcoalesce(field1, field2)— first non-null value
rex — field extraction from text
index=linux sourcetype=syslog
| rex field=_raw "sshd\[\d+\]: Accepted (?P<auth_method>\w+) for (?P<username>\S+) from (?P<src_ip>[\d\.]+)"
| stats count by src_ip, username, auth_method
| sort -count
rex uses named capture groups ((?P<fieldname>pattern)) to extract structured fields from raw text. Run this on only the filtered subset — rex is slow when applied to millions of events.
lookup — enrich with reference data
index=network sourcetype=firewall action=allowed
| stats sum(bytes_out) as TotalBytesOut by dest_ip
| lookup ip_reputation.csv ip AS dest_ip OUTPUT threat_score, category
| where threat_score > 70
| sort -TotalBytesOut
| table dest_ip, TotalBytesOut, threat_score, category
This query:
- Gets all allowed firewall traffic
- Sums outbound bytes per destination IP
- Enriches with threat intel (threat_score, category)
- Filters for high-threat destinations
- Shows IPs with the most data sent to high-threat destinations
This is data exfiltration detection via lookup enrichment.
Detection Patterns in SPL
Password spray detection
index=windows EventCode=4625 earliest=-1h
| stats count as Attempts, dc(TargetUserName) as UniqueAccounts
by IpAddress
| eval SprayScore=UniqueAccounts/Attempts
| where UniqueAccounts > 10 AND SprayScore > 0.5
| sort -UniqueAccounts
High UniqueAccounts and high SprayScore (each attempt hits a different account) = spray pattern. Low UniqueAccounts and high Attempts on one account = brute force.
Process tree with pipe
index=windows EventCode=4688 earliest=-24h
| eval ParentProcess=lower(mvindex(split(ParentProcessName,"\\"),-1))
| eval ChildProcess=lower(mvindex(split(NewProcessName,"\\"),-1))
| where ParentProcess IN ("word.exe","excel.exe","outlook.exe","powerpnt.exe")
AND ChildProcess IN ("cmd.exe","powershell.exe","wscript.exe","mshta.exe","cscript.exe")
| table _time, host, TargetUserName, ParentProcess, ChildProcess, CommandLine
| sort -_time
Office applications spawning shells = malicious macro execution or exploit.
Splunk Search Commands— Splunk Docs