Dashboards & Alerts
Ready-to-paste SPL queries for detection, dashboards, and live alerts.
Curated alert and dashboard queries for Linux clients, Windows clients, and server services. Click any item to expand its SPL query · copy it into Splunk and save as alert or dashboard panel.
Linux Clients · Alerts
Detects IPs that fail to log in via SSH more than 10 times within 5 minutes.
index=main sourcetype=linux_secure "Failed password" | bucket _time span=5m | stats count by _time, src_ip, user | where count > 10
Alert type: Scheduled (every 5 min) · Condition: Number of Results > 0
Same IP has failed attempts first, then a successful login · classic credential stuffing.
index=main sourcetype=linux_secure ("Failed password" OR "Accepted password" OR "Accepted publickey") | eval outcome=if(match(_raw,"Failed"),"fail","success") | stats count(eval(outcome="fail")) as fails, count(eval(outcome="success")) as success by src_ip, user | where fails > 3 AND success > 0
Detects when a user is added to the sudo group or /etc/sudoers.
index=main sourcetype=linux_secure ("usermod" OR "adduser") "sudo" | table _time, host, user, _raw
Shows all successful logins from IPs that haven't appeared in the last 30 days.
index=main sourcetype=linux_secure "Accepted" earliest=-1h | stats count by src_ip, user, host | search [search index=main sourcetype=linux_secure "Accepted" earliest=-30d latest=-1h | stats count by src_ip | eval src_ip=src_ip | table src_ip] # invert to see only NEW IPs: | where NOT src_ip IN (known_ips)
Tip: easier to maintain via a Splunk lookup table with known IPs.
Changes to /etc/cron* or crontab can be persistence mechanisms.
index=main sourcetype=syslog ("CRON" OR "crontab") ("REPLACE" OR "new" OR "BEGIN EDIT") | table _time, host, user, _raw
index=main sourcetype=linux_secure ("new user" OR "useradd" OR "adduser") | table _time, host, _raw
Linux Clients · Dashboard Panels
index=main sourcetype=linux_secure "Accepted" earliest=-24h | stats count by src_ip | sort -count | head 10
Visualization: Bar Chart · X-axis: src_ip · Y-axis: count
index=main sourcetype=linux_secure ("Failed password" OR "Accepted password" OR "Accepted publickey") earliest=-24h | eval status=if(match(_raw,"Failed"),"Failed","Success") | timechart count by status span=1h
Visualization: Line Chart · Split by status
index=main sourcetype=linux_secure "sudo" earliest=-24h | rex field=_raw "sudo:\s+(?<sudo_user>\w+)\s*:.*COMMAND=(?<cmd>.+)" | stats count by sudo_user, cmd, host | sort -count
index=main sourcetype=linux_secure earliest=-1h | eval session=if(match(_raw,"session opened"),1, if(match(_raw,"session closed"),-1,0)) | stats sum(session) as active_sessions
Visualization: Single Value
Windows Clients · Alerts
index=wineventlog EventCode=4625 | bucket _time span=5m | stats count by _time, src_ip, Account_Name, ComputerName | where count > 15
User created (4720) and added directly to the Administrators group (4732).
index=wineventlog (EventCode=4720 OR EventCode=4732) | stats values(EventCode) as events, count by Account_Name, ComputerName | where mvcount(events) > 1
An unknown service installed outside of patch windows is suspicious.
index=wineventlog EventCode=7045 | table _time, ComputerName, ServiceName, ServiceFileName, ServiceType, ServiceStartType
-EncodedCommand / -enc is a typical attack vector for obfuscated code.
index=wineventlog EventCode=4688 New_Process_Name="*powershell*" Process_Command_Line="*-enc*" | table _time, ComputerName, Creator_Process_Name, New_Process_Name, Process_Command_Line
Requires: Process Creation Auditing enabled (GPO).
Logins between 22:00 and 06:00 · adjust depending on environment.
index=wineventlog EventCode=4624 Logon_Type=10 | eval hour=strftime(_time, "%H") | where hour >= 22 OR hour < 6 | table _time, Account_Name, src_ip, ComputerName, hour
Logon_Type 10 = Remote Interactive (RDP)
index=wineventlog EventCode=4740 | stats count by Account_Name, Caller_Computer_Name, ComputerName | sort -count
Windows Clients · Dashboard Panels
index=wineventlog (EventCode=4624 OR EventCode=4625) earliest=-24h | eval status=if(EventCode=4624,"Success","Failure") | timechart count by status span=1h
Visualization: Line Chart
index=wineventlog EventCode=4740 earliest=-7d | stats count by Account_Name | sort -count | head 10
index=wineventlog EventCode=4624 Logon_Type=10 earliest=-24h | stats count by ComputerName, Account_Name, src_ip | sort -count
index=wineventlog EventCode=4688 earliest=-1h | stats count by New_Process_Name, ComputerName | sort -count | head 10
Server Services · Alerts
A high server-error rate can indicate an attack or outage.
index=web (sourcetype=apache_combined OR sourcetype=nginx_access) status>=500 earliest=-5m | stats count by host, status, clientip | where count > 50
An IP producing many 404 errors is probably scanning for endpoints.
index=web status=404 earliest=-10m | stats count by clientip, host | where count > 100 | sort -count
index=main sourcetype=syslog ("failed" OR "stopped" OR "killed") "systemd" | rex field=_raw "systemd\[1\]: (?<service>[^:]+).*(?:failed|stopped|killed)" | stats count by host, service | sort -count
index=db sourcetype=mysql:error earliest=-5m ("ERROR" OR "Warning") | stats count by host | where count > 20
If a host has stopped sending logs, it's either down or the forwarder has a problem.
# Hosts that sent logs in the last hour index=* earliest=-1h | stats latest(_time) as last_seen by host | eval minutes_silent=round((now()-last_seen)/60,1) | where minutes_silent > 30 | table host, last_seen, minutes_silent | sort -minutes_silent
index=web method=POST earliest=-1h | eval bytes_mb=round(bytes/1048576,2) | where bytes_mb > 10 | table _time, clientip, uri, bytes_mb, host | sort -bytes_mb
Server Services · Dashboard Panels
index=web earliest=-1h | eval status_group=case( status>=500, "5xx Server Error", status>=400, "4xx Client Error", status>=300, "3xx Redirect", status>=200, "2xx OK", 1=1, "Other") | stats count by status_group | sort -count
Visualization: Pie Chart
index=web earliest=-24h | timechart count by host span=15m
Visualization: Area Chart
index=web earliest=-1h | stats count by clientip | sort -count | head 10
index=* earliest=-24h | stats count by host, sourcetype | sort -count
Visualization: Bar Chart or Statistics Table
index=* earliest=-15m | stats latest(_time) as last_seen, count by host | eval last_seen=strftime(last_seen,"%H:%M:%S") | eval status=if(now()-strptime(last_seen,"%H:%M:%S")>300, " Silent", " Active") | table host, status, last_seen, count | sort status
Create an Alert & Dashboard in Splunk
Create an alert
- Enter and test the query in Search & Reporting
- Save As → Alert
- Set title, choose Alert type: Scheduled (e.g. every 5 min)
- Under Trigger Conditions: Number of Results > 0
- Under Trigger Actions: e.g. email or Slack webhook
- Save
Create a dashboard
- Run the query → Save As → Dashboard Panel
- Create a New Dashboard or add to an existing one
- Pick a panel type (Line Chart, Bar Chart, Single Value, Table)
- Add more panels via Edit → Add Panel
- Adjust the time range filter at the top right of the dashboard