Splunk Rule Conversion
Overview
Convert Splunk SPL detection rules to Microsoft Sentinel KQL, Google SecOps YARA-L 2.0, and CrowdStrike CQL. Includes field mappings, syntax patterns, and detection quality improvements.
Quick Reference
| Source | Target | Key Differences |
|---|---|---|
| Splunk SPL | Microsoft KQL | Pipe vs chained operators, different aggregation syntax |
| Splunk SPL | Google YARA-L | Declarative rules vs procedural queries, UDM schema |
| Splunk SPL | CrowdStrike CQL | Similar pipe syntax, different field names |
SPL to Microsoft Sentinel KQL
Syntax Mapping
| SPL | KQL |
|---|---|
index=windows | SecurityEvent table |
sourcetype=WinEventLog:Security | SecurityEvent |
search field=value | where field == "value" |
stats count by user | summarize count() by user |
eval field=value | extend field = value |
table field1, field2 | project field1, field2 |
rename old AS new | project-rename new = old |
dedup field | summarize take_any(*) by field |
sort -count | order by count desc |
rex field=x "(?<name>pattern)" | parse x with * "pattern" name or extract() |
mvexpand field | mv-expand field |
earliest=-24h | TimeGenerated > ago(24h) |
| where count > 5 | | where count_ > 5 |
transaction | summarize makeset() + correlation logic |
Data Table Mapping
| Splunk Source | Sentinel Table |
|---|---|
| Windows Security Events | SecurityEvent |
| Syslog | Syslog |
| Network/Firewall | CommonSecurityLog |
| DNS | DnsEvents |
| Azure AD Sign-ins | SigninLogs |
| Azure AD Audit | AuditLogs |
| M365 Activity | OfficeActivity |
| Defender for Endpoint | DeviceEvents, DeviceProcessEvents |
| Azure Activity | AzureActivity |
Windows EventID Reference
| EventID | Description | KQL Filter |
|---|---|---|
| 4624 | Successful logon | EventID == 4624 |
| 4625 | Failed logon | EventID == 4625 |
| 4648 | Explicit credential logon | EventID == 4648 |
| 4672 | Special privileges assigned | EventID == 4672 |
| 4688 | Process creation | EventID == 4688 |
| 4698 | Scheduled task created | EventID == 4698 |
| 4720 | User account created | EventID == 4720 |
| 4732 | Member added to local group | EventID == 4732 |
KQL Detection Quality Guidelines
When converting, enhance detections with:
- •
Avoid Low-and-Slow Blindness
kql// Create complementary rules with different thresholds // High threshold for immediate alert // Low threshold for hunting/investigation
- •
Address Distributed Attacks
kql// Aggregate by user across ALL devices, not per-device SecurityEvent | where EventID == 4625 | summarize FailedLogons = count() by TargetUserName, bin(TimeGenerated, 1h) | where FailedLogons > 10
- •
Correlate Failures with Success
kql// Failed attempts followed by success = potential compromise let failures = SecurityEvent | where EventID == 4625; let successes = SecurityEvent | where EventID == 4624; failures | join kind=inner (successes) on TargetUserName | where TimeGenerated1 between (TimeGenerated .. TimeGenerated + 1h)
- •
Cover Cloud Identity
kql// Include non-interactive sign-ins (often missed) union SigninLogs, AADNonInteractiveUserSignInLogs | where ResultType != 0
- •
Device Management Context
kql// CRITICAL: Use LEFT OUTER JOIN for device tables (not all devices managed) SecurityEvent | join kind=leftouter (DeviceInfo) on DeviceId
- •
Geographic Anomaly Detection
kqlSigninLogs | extend Country = tostring(LocationDetails.countryOrRegion) | summarize Countries = make_set(Country) by UserPrincipalName, bin(TimeGenerated, 1h) | where array_length(Countries) > 1
Example Conversion: Brute Force Detection
Original SPL:
index=windows sourcetype=WinEventLog:Security EventCode=4625 | stats count as failed_attempts by Account_Name, src_ip | where failed_attempts > 5
Converted KQL:
let timeframe = 1h; let threshold = 5; SecurityEvent | where TimeGenerated > ago(timeframe) | where EventID == 4625 | extend AccountName = TargetUserName | extend SourceIP = IpAddress | summarize FailedAttempts = count() by AccountName, SourceIP, bin(TimeGenerated, 5m) | where FailedAttempts > threshold | project TimeGenerated, AccountName, SourceIP, FailedAttempts
SPL to Google SecOps YARA-L 2.0
YARA-L 2.0 Rule Structure
rule rule_name {
meta:
author = "Security Team"
description = "Rule description"
severity = "HIGH" // INFO, LOW, MEDIUM, HIGH, CRITICAL
mitre_attack_tactic = "Tactic Name"
mitre_attack_technique = "TXXXX"
events:
// Event matching conditions
$event.metadata.event_type = "PROCESS_LAUNCH"
$event.principal.process.file.full_path = /pattern/i
match:
// Grouping for aggregation (optional)
$event.principal.user.userid over 5m
outcome:
// Calculated fields (optional)
$count = count($event)
condition:
// Rule trigger conditions
$event and $count > 5
}
CRITICAL YARA-L Requirements
- •
Risk Score MUST be static integer
yaral// CORRECT risk_score = 85 // WRONG - will fail risk_score = $severity * 10
- •
No if() in aggregation functions
yaral// WRONG $count = count_distinct(if($e.severity > 5, $e.user)) // CORRECT - use separate rules or filter in events section
- •
Match section indentation: exactly 2 spaces
yaralmatch: $user over 5m // 2 spaces, not tab
- •
Placeholder variables use $ prefix
yaral$e.metadata.event_type // event variable $user over 5m // match variable
UDM Field Mapping
| Splunk Field | UDM Path |
|---|---|
| user / Account | principal.user.userid |
| src_ip | principal.ip |
| dest_ip | target.ip |
| src_port | principal.port |
| dest_port | target.port |
| process | principal.process.file.full_path |
| command_line | principal.process.command_line |
| parent_process | principal.process.parent_process.file.full_path |
| host / hostname | principal.hostname |
| EventCode | metadata.product_event_type |
| action | security_result.action |
| severity | security_result.severity |
| file_hash | target.file.sha256 |
| url | target.url |
| domain | network.dns.questions.name |
UDM Event Types
| Type | Description |
|---|---|
PROCESS_LAUNCH | Process execution |
PROCESS_TERMINATE | Process termination |
NETWORK_CONNECTION | Network connection |
NETWORK_DNS | DNS query |
FILE_CREATION | File created |
FILE_MODIFICATION | File modified |
FILE_DELETION | File deleted |
USER_LOGIN | Authentication |
USER_LOGOUT | Session end |
REGISTRY_CREATION | Registry key created |
REGISTRY_MODIFICATION | Registry value changed |
Example Conversion: Suspicious PowerShell
Original SPL:
index=windows sourcetype=WinEventLog:Security EventCode=4688 | search New_Process_Name="*powershell.exe" | search (Process_Command_Line="*-enc*" OR Process_Command_Line="*-encodedcommand*") | stats count by Account_Name, Workstation_Name
Converted YARA-L:
rule suspicious_encoded_powershell {
meta:
author = "Security Team"
description = "Detects encoded PowerShell execution"
severity = "HIGH"
mitre_attack_tactic = "Execution"
mitre_attack_technique = "T1059.001"
events:
$process.metadata.event_type = "PROCESS_LAUNCH"
$process.metadata.product_event_type = "4688"
$process.principal.process.file.full_path = /powershell\.exe$/i
$process.principal.process.command_line = /\-[eE]nc|\-[eE]ncodedCommand/
$user = $process.principal.user.userid
$host = $process.principal.hostname
match:
$user, $host over 5m
outcome:
$execution_count = count($process)
$risk_score = 75
condition:
$process
}
SPL to CrowdStrike CQL
CQL Syntax Mapping
| SPL | CQL |
|---|---|
index=main | Select event source/repository |
sourcetype= | event_simpleName= |
search field=value | field=value |
stats count by field | | groupBy([field]) |
eval newfield=expr | | eval(newfield=expr) |
table fields | | select([fields]) |
sort -field | | sort(field, order=desc) |
dedup field | | groupBy([field]) | head(1) |
rex | | regex() |
where count > 5 | | test(count > 5) |
CrowdStrike Event Types
| event_simpleName | Description |
|---|---|
ProcessRollup2 | Process execution with full context |
SyntheticProcessRollup2 | Synthetic process events |
NetworkConnectIP4 | IPv4 network connection |
NetworkConnectIP6 | IPv6 network connection |
DnsRequest | DNS query |
FileWritten | File creation/modification |
UserLogon | Authentication event |
AsepValueUpdate | Persistence mechanism |
Platform Filtering
// Windows only event_platform=Win // macOS only event_platform=Mac // Linux only event_platform=Lin
CQL Field Reference
| Splunk Equivalent | CQL Field |
|---|---|
| hostname | ComputerName |
| user | UserName |
| process | FileName |
| command_line | CommandLine |
| parent_process | ParentBaseFileName |
| src_ip | LocalAddressIP4 |
| dest_ip | RemoteAddressIP4 |
| dest_port | RemotePort |
| file_hash | SHA256HashData |
| pid | TargetProcessId |
| parent_pid | ParentProcessId |
Example Conversion: Network Beaconing
Original SPL:
index=firewall sourcetype=pan:traffic | stats count by src_ip, dest_ip, dest_port | where count > 100 | sort -count
Converted CQL:
event_simpleName=NetworkConnectIP4 | groupBy([LocalAddressIP4, RemoteAddressIP4, RemotePort]) | count(aid, as=connection_count) | test(connection_count > 100) | sort(connection_count, order=desc) | select([LocalAddressIP4, RemoteAddressIP4, RemotePort, connection_count])
Conversion Workflow
Step 1: Analyze Source Rule
- •Identify data sources (index, sourcetype)
- •Map fields to target schema
- •Understand aggregation logic
- •Note time windows and thresholds
Step 2: Translate Core Logic
- •Convert search conditions
- •Map aggregation functions
- •Adapt field names
- •Adjust time syntax
Step 3: Enhance Detection Quality
- •Add complementary low-threshold variants
- •Include distributed attack patterns
- •Add success correlation for auth failures
- •Cover cloud identity sources
- •Add geographic anomaly detection
Step 4: Validate and Test
- •Syntax validation
- •Test with sample data
- •Tune thresholds
- •Document false positive patterns
MITRE ATT&CK Mapping Reference
Include MITRE mapping in converted rules:
| Tactic | Common Techniques |
|---|---|
| Initial Access | T1566 (Phishing), T1190 (Exploit Public-Facing) |
| Execution | T1059 (Command/Scripting), T1204 (User Execution) |
| Persistence | T1547 (Boot/Logon Autostart), T1053 (Scheduled Task) |
| Privilege Escalation | T1548 (Abuse Elevation), T1134 (Access Token) |
| Defense Evasion | T1070 (Indicator Removal), T1036 (Masquerading) |
| Credential Access | T1003 (OS Credential Dumping), T1110 (Brute Force) |
| Discovery | T1082 (System Info), T1083 (File/Directory Discovery) |
| Lateral Movement | T1021 (Remote Services), T1570 (Lateral Tool Transfer) |
| Collection | T1005 (Data from Local System), T1114 (Email Collection) |
| Exfiltration | T1041 (Exfil Over C2), T1048 (Exfil Over Alt Protocol) |
| Impact | T1486 (Data Encrypted), T1489 (Service Stop) |
Common Conversion Patterns
Authentication Monitoring
SPL:
index=windows EventCode=4625 | stats count by Account_Name | where count > 10
KQL:
SecurityEvent | where EventID == 4625 | summarize FailedCount = count() by TargetUserName | where FailedCount > 10
YARA-L:
rule brute_force_detection {
meta:
severity = "MEDIUM"
events:
$fail.metadata.event_type = "USER_LOGIN"
$fail.security_result.action = "BLOCK"
$user = $fail.target.user.userid
match:
$user over 10m
outcome:
$fail_count = count($fail)
condition:
$fail and $fail_count > 10
}
CQL:
event_simpleName=UserLogon LogonType=10 | groupBy([UserName]) | count(aid, as=logon_attempts) | test(logon_attempts > 10)
Confidence Scoring
When converting rules, assess confidence:
| Score | Meaning |
|---|---|
| 0.90-1.00 | Perfect conversion, all fields mapped |
| 0.75-0.89 | Good conversion, minor assumptions made |
| 0.60-0.74 | Moderate conversion, some logic simplified |
| 0.40-0.59 | Partial conversion, manual review needed |
| <0.40 | Significant gaps, major rework required |
Factors affecting confidence:
- •Field availability in target platform
- •Aggregation complexity
- •Multi-event correlation
- •Custom field extractions
- •Platform-specific features