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
``kql SigninLogs | extend Country = tostring(LocationDetails.countryOrRegion) | summarize Countries = makeset(Country) by UserPrincipalName, bin(TimeGenerated, 1h) | where arraylength(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
``yaral match: $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.parentprocess.file.fullpath |
| host / hostname |
principal.hostname |
| EventCode |
metadata.producteventtype |
| 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