// Community Prompt
// About this prompt
Windows AD environment with 3 suspicious lateral movement hops originating from a compromised workstation, pivoting through servers using PTH, PsExec, WMI, and SMB admin shares over 72 hours.
// Prompt
You are a Splunk threat hunter in a Windows AD environment.
Write production-ready SPL to detect lateral movement using:
- Pass-the-hash (Event ID 4624 Type 3, NTLM auth, anomalous source)
- PsExec / remote service creation (Event ID 7045)
- WMI remote execution (wmiprvse.exe spawning child processes)
- SMB admin share access (Event ID 5140, share name ADMIN$ or C$)
Requirements:
- Baseline against known admin hosts: {{admin_hosts}}
- Flag first-seen src/dst pairs in the last 30 days
- Use stats and streamstats to surface sequential hop patterns
- Risk-score each finding: direct admin-to-server = low, workstation-to-workstation = high
Output: src_host, dst_host, technique, first_seen, hop_count, risk_score
// Evaluation scores
// MITRE ATT&CK
// AI evaluation output
**Scenario:** Domain: CORP.LOCAL. Suspicious activity originates from WS-FINOPS-14 (10.10.5.14), pivoting to SRV-FILESTORE-02 (10.10.8.22), then SRV-SQLPROD-01 (10.10.8.45). Admin hosts baseline: DC-CORP-01, JUMP-ADMIN-03. Timeframe: 2024-11-18 02:11 UTC – 2024-11-20 14:33 UTC.
---
```spl
| union
[ search index=wineventlog (EventCode=4624 Logon_Type=3 Authentication_Package=NTLM)
| eval technique="Pass-the-Hash" ]
[ search index=wineventlog EventCode=7045 Service_File_Name="*\\psexesvc*"
| rename ComputerName AS dst_host, src_ip AS src_host
| eval technique="PsExec-RemoteService" ]
[ search index=wineventlog EventCode=5140 (Share_Name="\\\\*\\ADMIN$" OR Share_Name="\\\\*\\C$")
| eval technique="SMB-AdminShare" ]
[ search index=wineventlog ParentImage="*\\wmiprvse.exe"
| eval technique="WMI-RemoteExec", src_host=ParentComputerName, dst_host=ComputerName ]
| eval src_host=coalesce(src_host, IpAddress, "unknown"),
dst_host=coalesce(dst_host, ComputerName, "unknown")
| where src_host!="unknown" AND dst_host!="unknown"
| lookup admin_hosts_lookup hostname AS src_host OUTPUT is_admin_host AS src_is_admin
| lookup admin_hosts_lookup hostname AS dst_host OUTPUT is_admin_host AS dst_is_admin
| eval risk_score=case(
src_is_admin="true" AND dst_is_admin="true", 10,
src_is_admin="true" AND dst_is_admin!="true", 30,
src_is_admin!="true" AND dst_is_admin="true", 60,
src_is_admin!="true" AND dst_is_admin!="true", 90,
true(), 50)
| stats
min(_time) AS first_seen,
dc(technique) AS technique_count,
values(technique) AS technique,
max(risk_score) AS risk_score
by src_host, dst_host
| eval pair=src_host."-".dst_host
| sort 0 first_seen
| streamstats count AS hop_count by src_host
| eval first_seen_30d=if(first_seen >= relative_time(now(),"-30d@d"), "NEW", "KNOWN")
| where first_seen_30d="NEW"
| eval first_seen=strftime(first_seen,"%Y-%m-%dT%H:%M:%SZ")
| table src_host, dst_host, technique, first_seen, hop_count, risk_score
| sort - risk_score
```
**Results (fictional):**
| src_host | dst_host | technique | first_seen | hop_count | risk_score |
|---|---|---|---|---|---|
| WS-FINOPS-14 | SRV-FILESTORE-02 | Pass-the-Hash, SMB-AdminShare | 2024-11-18T02:11:00Z | 1 | 90 |
| SRV-FILESTORE-02 | SRV-SQLPROD-01 | PsExec-RemoteService, WMI-RemoteExec | 2024-11-18T03:44:22Z | 2 | 60 |
**Note:** Replace `admin_hosts_lookup` with your actual Splunk lookup table name resolving `{{admin_hosts}}`.