DEV Community

David Moya
David Moya

Posted on Originally published at malwareintel.es

Splunk SPL Queries for Threat Hunting: Copy-Paste Ready

SPL is the query language that makes Splunk useful for threat hunting. But writing good hunting queries from scratch takes time. Here are battle-tested SPL queries you can drop into your Splunk instance and start hunting today.

Fundamentals: How SPL Hunting Queries Work

Every SPL hunt follows this structure:

index= 
| stats/eval/where 
| sort/table 
Enter fullscreen mode Exit fullscreen mode

Start broad, filter aggressively, aggregate for patterns. The key commands:

  • stats: Aggregate and count. Your most-used command.
  • eventstats: Add statistics without removing original events.
  • transaction: Group related events into chains (e.g., a full attack sequence).
  • tstats: Like stats, but runs on accelerated data models. 10x faster for large datasets.

1. Process Creation Anomalies

Processes spawned from temp directories

index=sysmon EventCode=1
| where like(Image, "%\\Temp\\%") OR like(Image, "%\\tmp\\%")
| stats count by Image, ParentImage, User, ComputerName
| where count < 5
| sort -count
Enter fullscreen mode Exit fullscreen mode

Unusual parent-child relationships

index=sysmon EventCode=1
| stats count by ParentImage, Image
| where (like(ParentImage, "%\\winword.exe") OR like(ParentImage, "%\\excel.exe"))
  AND NOT like(Image, "%\\splwow64.exe")
| sort -count
Enter fullscreen mode Exit fullscreen mode

Word or Excel spawning anything other than splwow64.exe (print driver) is suspicious. This catches macro-based initial access.

LOLBins execution

index=sysmon EventCode=1
| search Image IN ("*\\certutil.exe","*\\mshta.exe","*\\regsvr32.exe",
    "*\\rundll32.exe","*\\wmic.exe","*\\msbuild.exe","*\\cscript.exe",
    "*\\wscript.exe","*\\bitsadmin.exe")
| stats count by Image, CommandLine, ParentImage, User
| sort -count
Enter fullscreen mode Exit fullscreen mode

2. Lateral Movement

PsExec-style activity

index=windows EventCode=7045
| where like(Service_File_Name, "%PSEXESVC%")
  OR like(Service_File_Name, "%\\ADMIN$\\%")
  OR like(Service_File_Name, "%cmd.exe /c%")
| stats count by ComputerName, Service_Name, Service_File_Name, Account_Name
| sort -count
Enter fullscreen mode Exit fullscreen mode

Remote service creation (generic)

index=windows EventCode=7045
| stats count by ComputerName, Service_Name, Service_File_Name
| where count=1
| sort -Service_Name
Enter fullscreen mode Exit fullscreen mode

One-off service installations across multiple hosts often indicate lateral movement tools.

SMB lateral movement

index=sysmon EventCode=3
| where DestinationPort=445
| stats dc(DestinationIp) as unique_targets, values(DestinationIp) as targets
    by SourceIp, Image
| where unique_targets > 5
| sort -unique_targets
Enter fullscreen mode Exit fullscreen mode

More than 5 unique SMB targets from one source in a short window is worth investigating.

3. C2 Beaconing Detection

Interval analysis (coefficient of variation)

index=proxy OR index=firewall
| sort 0 src_ip, dest_ip, _time
| streamstats current=f last(_time) as prev_time by src_ip, dest_ip
| eval interval=_time-prev_time
| stats count, avg(interval) as avg_int, stdev(interval) as std_int
    by src_ip, dest_ip
| eval cv=round(std_int/avg_int, 4)
| where cv < 0.1 AND count > 50
| sort cv
Enter fullscreen mode Exit fullscreen mode

A coefficient of variation (CV) below 0.1 means the connection intervals are highly regular. Humans are irregular. Beacons are regular. This is one of the most effective C2 detection techniques.

Beaconing with jitter tolerance

index=proxy OR index=firewall
| bin _time span=10m
| stats count by src_ip, dest_ip, dest_port, _time
| stats count as total_bins, avg(count) as avg_conn by src_ip, dest_ip, dest_port
| where total_bins > 20 AND avg_conn > 0.8 AND avg_conn < 1.5
| sort -total_bins
Enter fullscreen mode Exit fullscreen mode

4. DNS Tunneling

Abnormally long subdomains

index=dns
| eval subdomain_len=len(replace(query, "\.\w+\.\w+$", ""))
| where subdomain_len > 50
| stats count by query, src_ip
| sort -count
Enter fullscreen mode Exit fullscreen mode

DNS tunneling tools like dnscat2 and iodine encode data in subdomain labels. Legitimate subdomains rarely exceed 30 characters.

High query volume to single domain

index=dns
| rex field=query "\.(?[^\.]+\.[^\.]+)$"
| stats count, dc(query) as unique_queries by src_ip, root_domain
| where unique_queries > 100 AND count > 500
| sort -unique_queries
Enter fullscreen mode Exit fullscreen mode

5. Persistence Mechanisms

Scheduled task creation

index=sysmon EventCode=1
| where like(Image, "%\\schtasks.exe") AND like(CommandLine, "%/Create%")
| stats count by CommandLine, User, ComputerName, ParentImage
| sort -count
Enter fullscreen mode Exit fullscreen mode

Registry run keys modification

index=sysmon EventCode=13
| where like(TargetObject, "%\\CurrentVersion\\Run%")
  OR like(TargetObject, "%\\CurrentVersion\\RunOnce%")
| stats count by TargetObject, Details, Image, User
| sort -count
Enter fullscreen mode Exit fullscreen mode

WMI persistence

index=sysmon EventCode=1
| where like(Image, "%\\wmic.exe") AND like(CommandLine, "%process call create%")
| stats count by CommandLine, User, ComputerName
| sort -count
Enter fullscreen mode Exit fullscreen mode

Performance Tips

  1. Filter by index first. Always specify index= at the start.
  2. Use tstats when possible. It runs on accelerated data models and is dramatically faster.
  3. Avoid leading wildcards. *\\cmd.exe is slow. Use like(Image, "%\\cmd.exe") or better, a lookup table.
  4. Limit time ranges. Start with 24 hours, expand only if needed.
  5. Build macros. Wrap your best hunts in Splunk macros for reuse:
# Define macro: detect_lolbins(host)
# Usage:
| `detect_lolbins("workstation01")`
Enter fullscreen mode Exit fullscreen mode

From Hunt to Detection

When a hunt query finds real threats, convert it to a Correlation Search in Splunk Enterprise Security. Add Risk-Based Alerting to accumulate risk scores per entity instead of firing individual alerts, which dramatically reduces alert fatigue.

Successful hunt → Save as Report → Convert to Correlation Search
→ Assign risk score → Threshold triggers Notable Event
Enter fullscreen mode Exit fullscreen mode

Originally published at MalwareIntel. MalwareIntel is a free threat intelligence platform monitoring 13 public CTI sources.

Free resources:

Top comments (0)