This covers the actual Splunk configuration needed to build a functional home SOC dashboard from scratch. The assumption is Splunk Enterprise (free trial or licensed) ingesting Windows Security events, Sysmon, and optionally Zeek.
Data ingestion setup
Install the required add-ons before building any searches. Without these, field extractions do not work and all searches run against raw event text:
# Download from Splunkbase: # - Splunk Add-on for Microsoft Windows (TA-windows) # - Splunk Add-on for Sysmon (TA-sysmon) # Install via CLI: $SPLUNK_HOME/bin/splunk install app TA-windows.tgz -auth admin:password $SPLUNK_HOME/bin/splunk install app TA-sysmon.tgz -auth admin:password $SPLUNK_HOME/bin/splunk restart
Configure a Universal Forwarder on each Windows target to send events to Splunk. The inputs.conf on each forwarder:
[WinEventLog://Security] disabled = false index = wineventlog [WinEventLog://Microsoft-Windows-Sysmon/Operational] disabled = false renderXml = true index = sysmon
Verifying field extractions
Before building dashboards, confirm fields are parsing correctly:
index=wineventlog EventCode=4624 | table _time, host, EventCode, Account_Name, Logon_Type, src_ip | head 10
If Account_Name is empty, the TA-windows add-on is either not installed or not applied to the correct index. Fix with:
# props.conf in TA-windows/default/ should contain: [WinEventLog:Security] TRANSFORMS-force_sourcetype = force_wineventlog_security_sourcetype
Dashboard panel 1 — Failed logon attempts
index=wineventlog EventCode=4625 earliest=-24h
| eval Logon_Type_Name=case(
Logon_Type=="2","Interactive",
Logon_Type=="3","Network",
Logon_Type=="10","RemoteInteractive",
true(),"Other")
| stats count AS Failures,
dc(src_ip) AS UniqueSourceIPs,
values(src_ip) AS SourceIPs
by Account_Name, Logon_Type_Name, ComputerName
| where Failures > 5
| sort -Failures
Threshold of 5 catches brute force without generating noise from single mistyped passwords.
Dashboard panel 2 — New local admin accounts
index=wineventlog (EventCode=4720 OR EventCode=4728 OR EventCode=4732)
| eval Action=case(
EventCode==4720, "Account Created",
EventCode==4728, "Added to Domain Admins",
EventCode==4732, "Added to Local Admins")
| table _time, host, Action, Account_Name, Subject_Account_Name
| sort -_time
Dashboard panel 3 — Suspicious process parent-child pairs
index=sysmon EventCode=1 earliest=-24h
| eval ParentName=mvindex(split(ParentImage,"\"),-1)
| eval ChildName=mvindex(split(Image,"\"),-1)
| eval Pair=ParentName." > ".ChildName
| stats count by Pair, ComputerName
| where count < 5 AND
(ChildName IN ("cmd.exe","powershell.exe","wscript.exe","mshta.exe","cscript.exe")
OR ParentName IN ("winword.exe","excel.exe","outlook.exe","msaccess.exe"))
| sort count
Office applications spawning cmd.exe or PowerShell is a macro execution indicator. The count < 5 filter prioritises rare combinations — high count pairs are likely legitimate admin activity.
Dashboard panel 4 — PowerShell with encoded commands
index=wineventlog EventCode=4688 earliest=-24h
(Process_Command_Line="*-EncodedCommand*"
OR Process_Command_Line="*-enc *"
OR Process_Command_Line="*-en *")
| rex field=Process_Command_Line "(?i)-e(?:nc|ncodedcommand)?\s+(?P[A-Za-z0-9+/=]{20,})"
| eval decoded=base64decode(b64)
| table _time, host, Account_Name, Process_Command_Line, decoded
| sort -_time
Dashboard panel 5 — New scheduled tasks from unusual locations
index=wineventlog EventCode=4698 earliest=-24h | rex field=_raw "Task Name:\s+(?P[^\r\n]+)" | rex field=_raw "Task Content:\s+(?P.+)" | rex field=task_xml "Command>(?P[^<]+)</Command" | where NOT match(command,"(?i)^(C:\\Windows\\|C:\\Program Files)") | table _time, host, task_name, command, Subject_Account_Name
Alert on high-priority detections
# Convert any of the above searches to an alert: # Search > Save As > Alert # Trigger: Scheduled - every 15 minutes # Condition: Number of results > 0 # Actions: Send email / Webhook to Slack/Teams