Detection Engineering Hub
5-module detection platform — cross-platform SIEM query translation matrix, production hunt queries for critical scenarios (ransomware, lateral movement, cloud exfil), and 14 interactive hunt tools. All queries are production-ready with tuning notes.
Sigma Translation Matrix
Sigma rule templates with operational equivalents in Splunk SPL, Cortex XQL, Microsoft KQL, and Elastic Lucene across 12 critical techniques.
Ransomware Pre-Encryption
Shadow copy erasure detection, mass directory enumeration patterns, backup service tampering, and credential dumping before encryption.
Advanced Lateral Movement
DCOM/WMI remote execution artifacts, WinRM abuse logs, abnormal off-hours bulk data staging, and Kerberoasting hunt queries.
Cloud Exfiltration
Anomalous CloudTrail API calls, bulk S3/SageMaker data queries, unauthorized external DNS modifications, and IAM privilege escalation signals.
Interactive Hunt Tools
Hunt Plan Builder, Sigma Converter, SPL/KQL Libraries, Beacon Detection, LOLBin Cluster Hunt, Kerberos Suite, Lateral Movement Pack, Insider Threat.
Cross-Platform SIEM Query Translation Matrix
Sigma rule templates with their direct operational equivalents across Splunk SPL, Cortex XQL, Microsoft Sentinel/Defender KQL, and Elastic Lucene. Every entry includes the Sigma source, all four translations, and tuning guidance.
title: Encoded PowerShell Execution
status: stable
logsource:
category: process_creation
product: windows
detection:
selection:
Image|endswith: '\powershell.exe'
CommandLine|contains:
- '-enc '
- '-EncodedCommand '
- ' -e '
filter_legitimate:
ParentImage|endswith:
- '\msiexec.exe'
- '\setup.exe'
condition: selection and not filter_legitimate
falsepositives:
- Software deployment tools using encoded commands
level: high
index=wineventlog EventCode=4688 Image="*\\powershell.exe" (CommandLine="*-enc *" OR CommandLine="*-EncodedCommand *" OR CommandLine="* -e *") NOT (ParentProcessName="*msiexec.exe" OR ParentProcessName="*setup.exe") | eval decoded=urldecode(CommandLine) | table _time, ComputerName, User, CommandLine, ParentProcessName | sort -_time
dataset = xdr_data
| filter event_type = ENUM.PROCESS
and action_process_image_name = "powershell.exe"
and (
action_process_image_command_line ~= "(?i)-enc\s"
or action_process_image_command_line ~= "(?i)-EncodedCommand\s"
or action_process_image_command_line ~= "(?i)\s-e\s"
)
and actor_process_image_name not in ("msiexec.exe", "setup.exe")
| fields actor_process_image_name, action_process_image_command_line,
causality_actor_username, event_timestamp
| sort desc event_timestamp
causality_actor_username to filter service accounts. Add action_process_os_pid for process chain correlation in Cortex XSIAM timeline.DeviceProcessEvents
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has_any ("-enc ", "-EncodedCommand ", " -e ")
| where not (InitiatingProcessFileName has_any ("msiexec.exe", "setup.exe"))
| extend EncodedPart = extract(@"(?i)(?:-enc|-EncodedCommand|-e)\s+(\S+)",
1, ProcessCommandLine)
| extend Decoded = base64_decode_tostring(EncodedPart)
| project Timestamp, DeviceName, AccountName, ProcessCommandLine,
Decoded, InitiatingProcessFileName
| sort by Timestamp desc
base64_decode_tostring() lets you inspect the decoded payload in-query. Filter noise: add | where strlen(EncodedPart) > 50. Connect to AlertEvidence table for full process tree./* Lucene KQL for Elastic SIEM */
process where
process.name : "powershell.exe" and
process.command_line : ("*-enc *", "*-EncodedCommand *", "* -e *") and
not process.parent.name : ("msiexec.exe", "setup.exe")
/* EQL for Detection Rules */
process where
process.name == "powershell.exe" and
process.args : ("-enc", "-EncodedCommand", "-e") and
not process.parent.name in ("msiexec.exe", "setup.exe")
process.pe.original_file_name : "PowerShell.EXE" to catch renamed PS executables.title: LSASS Memory Access by Non-System Process
status: stable
logsource:
category: process_access
product: windows
detection:
selection:
TargetImage|endswith: '\lsass.exe'
GrantedAccess|contains:
- '0x1010'
- '0x1410'
- '0x1fffff'
filter_av:
SourceImage|endswith:
- '\MsMpEng.exe'
- '\SentinelAgent.exe'
- '\CrowdStrikeAgent.exe'
- '\csfalconservice.exe'
filter_system:
SourceImage|startswith: 'C:\Windows\System32\'
condition: selection and not (filter_av or filter_system)
falsepositives:
- EDR/AV vendors — enumerate and add to filter_av
level: critical
index=sysmon EventCode=10
TargetImage="*\\lsass.exe"
(GrantedAccess="0x1010" OR GrantedAccess="0x1410" OR GrantedAccess="0x1fffff")
NOT SourceImage IN ("*\\MsMpEng.exe","*\\SentinelAgent.exe",
"*\\csfalconservice.exe","C:\\Windows\\System32\\*")
| eval risk=case(GrantedAccess="0x1fffff","CRITICAL",
GrantedAccess="0x1410","HIGH","MEDIUM")
| table _time, ComputerName, SourceImage, GrantedAccess, risk
| sort -_time
| eventstats count by SourceImage to identify frequent false-positive accessors over 30 days before alerting.dataset = xdr_data
| filter event_type = ENUM.PROCESS_INJECTION
and action_process_image_name = "lsass.exe"
and actor_process_image_name not in (
"MsMpEng.exe", "SentinelAgent.exe", "csfalconservice.exe"
)
and actor_process_image_path not contains "C:\Windows\System32"
| fields actor_process_image_name, actor_process_image_path,
action_process_access_mask, causality_actor_username, event_timestamp
| sort desc event_timestamp
causality_actor_process_image_name for full attack chain attribution.DeviceEvents
| where ActionType == "OpenProcessApiCall"
| where FileName =~ "lsass.exe"
| where ProcessCommandLine has_any ("0x1010", "0x1410", "0x1fffff")
or InitiatingProcessFileName !in~ (
"MsMpEng.exe", "SentinelAgent.exe", "csfalconservice.exe"
)
| where not InitiatingProcessFolderPath startswith @"C:\Windows\System32"
| project Timestamp, DeviceName, InitiatingProcessFileName,
InitiatingProcessCommandLine, ReportId
| sort by Timestamp desc
process where
process.name : "lsass.exe" and
event.type : "access" and
winlog.event_data.GrantedAccess : ("0x1010", "0x1410", "0x1fffff") and
not process.parent.name : (
"MsMpEng.exe", "SentinelAgent.exe", "csfalconservice.exe"
) and
not process.parent.executable : "C:\\Windows\\System32\\*"
host.risk.calculated_score to prioritise high-risk endpoints. Correlate with network where destination.ip != null within 120s to catch immediate credential use.title: Kerberoasting — RC4 TGS Requests
status: stable
logsource:
product: windows
service: security
detection:
selection:
EventID: 4769
TicketEncryptionType: '0x17'
filter_computers:
ServiceName|endswith: '$'
filter_krbtgt:
ServiceName: 'krbtgt'
condition: selection and not (filter_computers or filter_krbtgt)
aggregate:
count: 5
timeframe: 60s
group_by: SourceAddress
falsepositives:
- Legacy applications using RC4 encryption
level: high
index=wineventlog EventCode=4769
TicketEncryptionType=0x17
NOT ServiceName="*$"
NOT ServiceName="krbtgt"
| bucket _time span=60s
| stats count as RequestCount, values(ServiceName) as Services
by _time, IpAddress
| where RequestCount >= 5
| eval Severity=case(RequestCount>=20,"CRITICAL",
RequestCount>=10,"HIGH","MEDIUM")
| table _time, IpAddress, RequestCount, Services, Severity
| sort -RequestCount
SecurityEvent
| where EventID == 4769
| where TicketEncryptionType == "0x17"
| where not ServiceName endswith "$"
| where ServiceName != "krbtgt"
| summarize RequestCount=count(), Services=make_set(ServiceName)
by bin(TimeGenerated, 1m), IpAddress
| where RequestCount >= 5
| extend Severity = case(RequestCount >= 20, "CRITICAL",
RequestCount >= 10, "HIGH", "MEDIUM")
| project TimeGenerated, IpAddress, RequestCount, Services, Severity
| sort by RequestCount desc
dataset = xdr_data
| filter event_type = ENUM.NETWORK
and network_protocol = "KERBEROS"
and network_description contains "TGS-REQ"
and network_description contains "RC4"
and network_description not contains "$@"
| bin event_timestamp span = 60s
| agg count() as req_count, array_agg(network_description) as services
by event_timestamp, actor_primary_username, src_ip
| filter req_count >= 5
| fields event_timestamp, src_ip, actor_primary_username, req_count, services
| sort desc req_count
/* EQL sequence for Kerberoasting + immediate hash cracking attempt */
sequence by source.ip with maxspan=5m
[authentication where event.code == "4769"
and winlog.event_data.TicketEncryptionType == "0x17"
and not winlog.event_data.ServiceName endswith "$"] with runs=5
[network where destination.port == 80 or destination.port == 443
and network.direction == "outbound"]
maxspan — 5 minutes is tight but high-confidence. For broader coverage remove the sequence and alert on 5 EID 4769 events alone.title: DCSync Attack from Non-DC
status: stable
logsource:
product: windows
service: security
detection:
selection:
EventID: 4662
ObjectType: '%{19195a5b-6da0-11d0-afd3-00c04fd930c9}'
Properties|contains:
- '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2' # DS-Replication-Get-Changes
- '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2' # DS-Replication-Get-Changes-All
filter_dc:
SubjectUserName|endswith: '$' # Computer accounts (DCs)
condition: selection and not filter_dc
level: critical
index=wineventlog EventCode=4662
ObjectType="%{19195a5b-6da0-11d0-afd3-00c04fd930c9}"
(Properties="*1131f6aa*" OR Properties="*1131f6ad*")
NOT SubjectUserName="*$"
| eval alert="DCSync from non-DC account: "+SubjectUserName+" on "+ComputerName
| table _time, ComputerName, SubjectUserName, SubjectDomainName, alert
| sort -_time
SecurityEvent
| where EventID == 4662
| where ObjectType has "19195a5b-6da0-11d0-afd3-00c04fd930c9"
| where Properties has_any (
"1131f6aa-9c07-11d1-f79f-00c04fc2dcd2",
"1131f6ad-9c07-11d1-f79f-00c04fc2dcd2"
)
| where not SubjectUserName endswith "$"
| where not SubjectUserName startswith "MSOL_"
| where not SubjectUserName startswith "AAD_"
| project TimeGenerated, Computer, SubjectUserName,
SubjectDomainName, SubjectLogonId
| sort by TimeGenerated desc
| join kind=leftouter (IdentityLogonEvents | project AccountName, DeviceName) to map the user to their originating device. Cross-reference with unusual logon times./* Lucene KQL */ event.code: "4662" AND winlog.event_data.ObjectType: "*19195a5b*" AND (winlog.event_data.Properties: "*1131f6aa*" OR winlog.event_data.Properties: "*1131f6ad*") AND NOT winlog.event_data.SubjectUserName: *$
title: Shadow Copy and Backup Deletion
status: stable
logsource:
category: process_creation
product: windows
detection:
vssadmin:
Image|endswith: '\vssadmin.exe'
CommandLine|contains|all:
- 'delete'
- 'shadows'
wmic_vss:
Image|endswith: '\wmic.exe'
CommandLine|contains|all:
- 'shadowcopy'
- 'delete'
bcdedit:
Image|endswith: '\bcdedit.exe'
CommandLine|contains|all:
- 'recoveryenabled'
- 'no'
wbadmin:
Image|endswith: '\wbadmin.exe'
CommandLine|contains: 'delete catalog'
condition: vssadmin or wmic_vss or bcdedit or wbadmin
level: critical
index=wineventlog EventCode=4688
((Image="*\\vssadmin.exe" CommandLine="*delete*shadows*")
OR (Image="*\\wmic.exe" CommandLine="*shadowcopy*delete*")
OR (Image="*\\bcdedit.exe" CommandLine="*recoveryenabled*no*")
OR (Image="*\\wbadmin.exe" CommandLine="*delete*catalog*"))
| eval signal=case(
match(CommandLine,"vssadmin.*delete"),"VSS Deletion",
match(CommandLine,"wmic.*shadowcopy"),"WMIC Shadow Delete",
match(CommandLine,"bcdedit.*recoveryenabled"),"Boot Recovery Disabled",
match(CommandLine,"wbadmin.*delete"),"Backup Catalog Deleted",
true(),"Unknown Backup Tamper")
| table _time, ComputerName, User, Image, CommandLine, signal
| sort -_time
DeviceProcessEvents
| where (FileName =~ "vssadmin.exe"
and ProcessCommandLine has_all ("delete", "shadows"))
or (FileName =~ "wmic.exe"
and ProcessCommandLine has_all ("shadowcopy", "delete"))
or (FileName =~ "bcdedit.exe"
and ProcessCommandLine has_all ("recoveryenabled", "no"))
or (FileName =~ "wbadmin.exe"
and ProcessCommandLine has "delete catalog")
| project Timestamp, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessFileName
| sort by Timestamp desc
DeviceFileEvents | where ActionType == "FileModified" and FolderPath !contains "AppData" to catch mass file modification starting within 5 minutes of backup deletion — ransomware encryption in progress.dataset = xdr_data
| filter event_type = ENUM.PROCESS
and (
(action_process_image_name = "vssadmin.exe"
and action_process_image_command_line ~= "(?i)delete.*shadows")
or (action_process_image_name = "wmic.exe"
and action_process_image_command_line ~= "(?i)shadowcopy.*delete")
or (action_process_image_name = "bcdedit.exe"
and action_process_image_command_line ~= "(?i)recoveryenabled.*no")
or (action_process_image_name = "wbadmin.exe"
and action_process_image_command_line ~= "(?i)delete.*catalog")
)
| fields event_timestamp, endpoint_id, causality_actor_username,
action_process_image_name, action_process_image_command_line
| sort desc event_timestamp
ENUM.FILE | filter file_extension in ("docx","xlsx","pdf","sql","bak") modified count > 500 within 10 minutes for high-confidence ransomware detection.title: WMI Remote Process Creation
status: stable
logsource:
category: process_creation
product: windows
detection:
selection:
ParentImage|endswith: '\WmiPrvSE.exe'
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\wscript.exe'
- '\cscript.exe'
filter_sccm:
ParentCommandLine|contains: 'SCCM'
condition: selection and not filter_sccm
level: high
DeviceProcessEvents
| where InitiatingProcessFileName =~ "WmiPrvSE.exe"
| where FileName in~ ("cmd.exe","powershell.exe","wscript.exe","cscript.exe")
| where not InitiatingProcessCommandLine has "SCCM"
| project Timestamp, DeviceName, AccountName, FileName,
ProcessCommandLine, RemoteIP=InitiatingProcessRemoteIP
| sort by Timestamp desc
index=sysmon EventCode=1 ParentImage="*\\WmiPrvSE.exe" (Image="*\\cmd.exe" OR Image="*\\powershell.exe" OR Image="*\\wscript.exe" OR Image="*\\cscript.exe") NOT ParentCommandLine="*SCCM*" | stats count by ComputerName, Image, CommandLine, ParentCommandLine | sort -count
process where
process.parent.name : "WmiPrvSE.exe" and
process.name : ("cmd.exe","powershell.exe","wscript.exe","cscript.exe") and
not process.parent.command_line : ("*SCCM*", "*ConfigMgr*")
[network where destination.port == 135] to confirm the RPC/DCOM channel was opened before WMI execution — eliminates local WMI calls from scope.Paste any Sigma rule (YAML) and generate SPL, KQL, XQL, and Elastic equivalents. Client-side parsing — no data leaves your browser.
Ransomware Pre-Encryption Hunt Queries
Catch ransomware before encryption begins — shadow copy erasure detection, mass directory enumeration patterns, credential dumping signals, and backup service tampering. All queries include tuning notes for noise reduction.
index=wineventlog EventCode=4688
((Image="*\\vssadmin.exe" AND CommandLine="*delete*shadows*")
OR (Image="*\\wmic.exe" AND CommandLine="*shadowcopy*delete*")
OR (Image="*\\bcdedit.exe" AND (CommandLine="*recoveryenabled*no*" OR CommandLine="*bootstatuspolicy*ignoreallfailures*"))
OR (Image="*\\wbadmin.exe" AND CommandLine="*delete*catalog*")
OR (Image="*\\diskshadow.exe" AND CommandLine="*delete*shadows*"))
| eval technique=case(
match(Image,"vssadmin"),"T1490 — vssadmin delete shadows",
match(Image,"wmic"),"T1490 — WMIC shadowcopy delete",
match(Image,"bcdedit"),"T1490 — Boot Recovery Disabled",
match(Image,"wbadmin"),"T1490 — Backup Catalog Deleted",
match(Image,"diskshadow"),"T1490 — Diskshadow Delete",
true(),"Unknown")
| table _time, ComputerName, User, technique, CommandLine
| sort -_time
// Detect ransomware staging: shadow deletion + mass file modification within 10 minutes
let ShadowDeletion = DeviceProcessEvents
| where (FileName =~ "vssadmin.exe" and ProcessCommandLine has_all ("delete","shadows"))
or (FileName =~ "wmic.exe" and ProcessCommandLine has_all ("shadowcopy","delete"))
or (FileName =~ "bcdedit.exe" and ProcessCommandLine has_all ("recoveryenabled","no"))
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine;
let MassFileModify = DeviceFileEvents
| where ActionType in ("FileCreated","FileModified","FileRenamed")
| where not FolderPath has_any (@"C:\Windows\", @"C:\Program Files")
| summarize ModifiedCount=count() by bin(Timestamp, 1m), DeviceName
| where ModifiedCount > 100;
ShadowDeletion
| join kind=inner MassFileModify on DeviceName
| where abs(datetime_diff('minute', Timestamp, Timestamp1)) <= 10
| project Timestamp, DeviceName, AccountName, FileName,
ProcessCommandLine, ModifiedCount
| sort by Timestamp desc
ModifiedCount threshold from 100 if you want earlier detection. Adjust timeframe window for your environment's encryption speed profile.index=sysmon EventCode=1
(Image="*\\cmd.exe" OR Image="*\\powershell.exe")
(CommandLine="*dir *" OR CommandLine="*tree *" OR CommandLine="*Get-ChildItem*" OR CommandLine="*gci *")
NOT (User="*svc*" OR User="*admin*" OR ParentImage="*explorer.exe")
| bucket _time span=60s
| stats count as DirCommands, dc(CommandLine) as UniqueCommands
by _time, ComputerName, User
| where DirCommands >= 15
| sort -DirCommands
// Network share enumeration pattern — ransomware mapping attack surface
DeviceProcessEvents
| where FileName in~ ("net.exe","net1.exe")
| where ProcessCommandLine has_any ("view", "share", "use")
| summarize ShareEnumCount=count(), Commands=make_set(ProcessCommandLine)
by bin(Timestamp, 5m), DeviceName, AccountName
| where ShareEnumCount >= 5
| join kind=leftouter (
DeviceProcessEvents
| where FileName =~ "vssadmin.exe"
| project DeviceName, VSSTime=Timestamp
) on DeviceName
| where isnotnull(VSSTime) or ShareEnumCount >= 10
| sort by Timestamp desc
// Full ransomware kill chain: cred dump → lateral movement → shadow deletion
let CredDump = DeviceProcessEvents
| where FileName in~ ("procdump.exe","procdump64.exe","lsass.exe")
or (FileName =~ "reg.exe" and ProcessCommandLine has_all ("save","SAM"))
or (ProcessCommandLine has "sekurlsa" and ProcessCommandLine has "logonpasswords")
| project Timestamp, DeviceName, CredDumpTime=Timestamp, AccountName;
let LatMove = DeviceLogonEvents
| where LogonType in ("3","10")
| where not ActionType =~ "LogonFailed"
| project Timestamp, DeviceName=RemoteDeviceName, LatMoveTime=Timestamp,
SourceDevice=DeviceName, LogonType, AccountName;
let VSSDelete = DeviceProcessEvents
| where FileName =~ "vssadmin.exe" and ProcessCommandLine has_all ("delete","shadows")
| project Timestamp, DeviceName, VSSTime=Timestamp;
CredDump
| join kind=inner LatMove on AccountName
| join kind=inner VSSDelete on DeviceName
| where CredDumpTime < LatMoveTime and LatMoveTime < VSSTime
| where datetime_diff('hour', VSSTime, CredDumpTime) <= 24
| project CredDumpTime, LatMoveTime, VSSTime, AccountName, CredDumpDevice=DeviceName
| sort by CredDumpTime desc
index=wineventlog EventCode=4688
Image="*\\net.exe" OR Image="*\\net1.exe" OR Image="*\\sc.exe"
(CommandLine="*stop*" OR CommandLine="*delete*" OR CommandLine="*config*")
(CommandLine IN ("*vss*","*backup*","*shadow*","*wbengine*","*MSSQLSvc*",
"*MSSQL*","*SQLWriter*","*MsDtsServer*","*mepocs*",
"*memtas*","*veeam*","*Veeam*","*sophos*","*Malwarebytes*"))
| eval service=mvindex(split(CommandLine," "),2)
| table _time, ComputerName, User, CommandLine, service
| sort -_time
dataset = xdr_data
| filter event_type = ENUM.PROCESS
and action_process_image_name in ("net.exe","net1.exe","sc.exe","taskkill.exe")
and (
action_process_image_command_line ~= "(?i)(stop|delete).*(backup|vss|veeam|shadow|MSSQL|sophos)"
or action_process_image_command_line ~= "(?i)/im.*(backup|antivirus|defender)"
)
| fields event_timestamp, endpoint_id, causality_actor_username,
action_process_image_name, action_process_image_command_line
| sort desc event_timestamp
Advanced Lateral Movement Hunt Queries
Production hunt queries for DCOM/WMI remote execution artifacts, WinRM abuse logs, and off-hours bulk data staging — the key techniques used in advanced persistent threat lateral movement.
// DCOM lateral movement: mmc.exe spawning child processes
DeviceProcessEvents
| where InitiatingProcessFileName =~ "mmc.exe"
| where FileName in~ ("cmd.exe","powershell.exe","rundll32.exe",
"wscript.exe","cscript.exe","certutil.exe")
| extend IsOffHours = iff(hourofday(Timestamp) !between (8 .. 18), true, false)
| project Timestamp, DeviceName, AccountName, FileName,
ProcessCommandLine, InitiatingProcessRemoteIP, IsOffHours
| sort by Timestamp desc
InitiatingProcessRemoteIP being populated confirms remote origin. Alert with no threshold for off-hours events; apply 2-event threshold for business hours.index=sysmon EventCode=1
ParentImage="*\\WmiPrvSE.exe"
(Image="*\\cmd.exe" OR Image="*\\powershell.exe" OR Image="*\\wscript.exe")
| eval is_offhours=if(strftime("%H:%M",_time)>="22:00" OR strftime("%H:%M",_time)<="06:00","YES","no")
| stats count by ComputerName, User, Image, CommandLine, ParentCommandLine, is_offhours
| where count >= 1 AND is_offhours="YES"
OR count >= 3
| sort -count
dataset = xdr_data
| filter event_type = ENUM.PROCESS
and actor_process_image_name in ("WmiPrvSE.exe","mmc.exe","svchost.exe")
and action_process_image_name in ("cmd.exe","powershell.exe","rundll32.exe")
and actor_process_is_remote_session = true
| fields event_timestamp, endpoint_id, causality_actor_username,
actor_process_image_name, action_process_image_name,
action_process_image_command_line, actor_primary_ip
| sort desc event_timestamp
actor_process_is_remote_session = true filters to remote WMI/DCOM sessions only, eliminating local WMI instrumentation noise. This is the primary filter that makes this query production-ready without a threshold.// WinRM session: wsmprovhost.exe spawns execution on target host
DeviceProcessEvents
| where InitiatingProcessFileName =~ "wsmprovhost.exe"
| where FileName in~ ("cmd.exe","powershell.exe","net.exe","whoami.exe",
"ipconfig.exe","systeminfo.exe","wmic.exe")
// Enrich with off-hours flag
| extend HourUTC = hourofday(Timestamp)
| extend IsOffHours = iff(HourUTC < 8 or HourUTC > 18, true, false)
// Correlate with baseline: was this source host seen before?
| join kind=leftouter (
DeviceLogonEvents
| where LogonType == "3"
| summarize SeenBefore=dcount(Timestamp) by DeviceName
| where SeenBefore > 5
) on DeviceName
| project Timestamp, DeviceName, AccountName, FileName,
ProcessCommandLine, IsOffHours, SeenBefore
| sort by Timestamp desc
index=wineventlog EventCode=4624 LogonType=3
AuthenticationPackageName=Kerberos
| eval hour=strftime("%H",_time)
| where (hour>="22" OR hour<="06")
| stats count as OffHoursLogons, dc(WorkstationName) as UniqueSourceHosts,
values(WorkstationName) as SourceHosts
by TargetUserName, IpAddress
| where OffHoursLogons >= 5 OR UniqueSourceHosts >= 3
| table _time, IpAddress, TargetUserName, OffHoursLogons, UniqueSourceHosts, SourceHosts
| sort -OffHoursLogons
// Abnormal off-hours bulk data staging to temp/staging directories
DeviceFileEvents
| where ActionType in ("FileCreated","FileCopied")
| where FolderPath has_any (@"C:\Temp", @"C:\Windows\Temp", @"C:\ProgramData",
@"\AppData\Local\Temp")
| where FileExtension in ("zip","7z","rar","tar","gz","sql","bak","mdb",
"csv","xlsx","pst","ost","kdbx")
| extend HourUTC = hourofday(Timestamp)
| where HourUTC < 7 or HourUTC > 20 // Off-hours window
| summarize StagedFileCount=count(), TotalSizeMB=sum(FileSize)/1048576,
FileTypes=make_set(FileExtension), FolderPaths=make_set(FolderPath)
by bin(Timestamp, 30m), DeviceName, AccountName
| where StagedFileCount >= 20 or TotalSizeMB >= 100
| sort by TotalSizeMB desc
index=sysmon EventCode=11
(TargetFilename="*.zip" OR TargetFilename="*.7z" OR TargetFilename="*.rar")
(TargetFilename="*\\Temp\\*" OR TargetFilename="*\\ProgramData\\*")
| eval hour=strftime("%H",_time)
| where hour>="20" OR hour<="07"
| stats count as ArchiveCount, dc(TargetFilename) as UniqueArchives,
values(TargetFilename) as Archives
by ComputerName, User, hour
| where ArchiveCount >= 5
| sort -ArchiveCount
// Pass-the-Ticket: Type-3 network logon without preceding TGT request
let TGTRequests = SecurityEvent
| where EventID == 4768
| project TGTTime=TimeGenerated, TGTSource=IpAddress, UserName=TargetUserName;
let NetworkLogons = SecurityEvent
| where EventID == 4624
| where LogonType == "3"
| project LogonTime=TimeGenerated, LogonSource=IpAddress, UserName=TargetUserName,
WorkstationName, ComputerName;
NetworkLogons
| join kind=leftanti TGTRequests on UserName,
$left.LogonSource == $right.TGTSource
| where not UserName endswith "$"
| where abs(datetime_diff('minute', LogonTime, now())) < 60
| project LogonTime, ComputerName, WorkstationName, UserName, LogonSource
| sort by LogonTime desc
leftanti join surfaces logon Type-3 events that have no corresponding TGT request from the same source — consistent with injected tickets. High false-positive potential from cached tickets and Kerberos pre-auth. Run as a hunting query, not a real-time alert. Correlate with BloodHound to check if the user has a known reason to be on the target host.Cloud Exfiltration Hunt Queries
Anomalous CloudTrail API call patterns, bulk S3 and SageMaker data queries, unauthorized external DNS modifications, and IAM privilege escalation detection — across AWS, with notes for Azure and GCP equivalents.
index=aws_cloudtrail
eventName IN ("GetSecretValue","DescribeSecret","ListSecrets",
"GetParameter","GetParameters","DescribeParameters",
"CreateAccessKey","AttachUserPolicy","CreatePolicyVersion",
"AssumeRole","GetCallerIdentity","DescribeInstances",
"ListBuckets","ListObjects","GetObject")
errorCode=* OR errorCode!="AccessDenied"
| eval risk_tier=case(
eventName IN ("CreateAccessKey","AttachUserPolicy","CreatePolicyVersion"),"CRITICAL",
eventName IN ("GetSecretValue","GetParameter","GetParameters"),"HIGH",
eventName IN ("AssumeRole","GetCallerIdentity"),"MEDIUM",
true(),"LOW")
| where risk_tier IN ("CRITICAL","HIGH")
| stats count as EventCount, values(eventName) as Events,
values(sourceIPAddress) as SourceIPs
by userIdentity.arn, risk_tier
| where EventCount >= 3 OR risk_tier="CRITICAL"
| sort -EventCount
CreateAccessKey outside of approved IAM provisioning workflows is immediately suspicious. Filter known automation roles (e.g., terraform execution roles) using a lookup table of approved ARNs. Alert on: any human-user ARN calling CreateAccessKey on a different user.// Azure Activity Log equivalent for CloudTrail anomaly hunting
AuditLogs
| where OperationName has_any (
"Add member to role", "Update user", "Reset user password",
"Add service principal credentials", "Add application",
"Delete application"
)
| where Result =~ "success"
| extend InitiatedBy = tostring(InitiatedBy.user.userPrincipalName)
| where not InitiatedBy has "#EXT#" // Filter guest accounts
| project TimeGenerated, OperationName, InitiatedBy,
TargetResources, AADTenantId, CorrelationId
| sort by TimeGenerated desc
SigninLogs | where RiskLevelDuringSignIn != "none" to identify risky sign-ins preceding privileged operations. Add | where Category == "RoleManagement" to focus on privileged role assignments.index=aws_cloudtrail eventName=GetObject
NOT errorCode=AccessDenied
| eval size_mb=requestParameters.contentLength/1048576
| bucket _time span=10m
| stats sum(size_mb) as TotalMB, count as ObjectCount,
dc(requestParameters.bucketName) as BucketCount,
values(requestParameters.key) as ObjectKeys
by _time, userIdentity.arn, sourceIPAddress
| where TotalMB >= 1000 OR ObjectCount >= 500
| eval alert_reason=case(
TotalMB>=10000,"Mass exfil: "+tostring(round(TotalMB/1024,1))+"GB in 10min",
TotalMB>=1000,"Large exfil: "+tostring(round(TotalMB,0))+"MB in 10min",
ObjectCount>=1000,"High object count: "+tostring(ObjectCount),
true(),"Volume anomaly")
| table _time, userIdentity.arn, sourceIPAddress, TotalMB, ObjectCount, alert_reason
| sort -TotalMB
// SageMaker anomalous data access — T1530 cloud ML data exfil
AWSCloudTrail
| where EventName has_any ("CreatePresignedDomainUrl","CreatePresignedNotebookInstanceUrl",
"DescribeFeatureGroup","GetRecord","BatchGetRecord")
| where UserIdentityType != "AWSService"
| summarize ApiCallCount=count(), UniqueOps=dcount(EventName),
DataApis=make_set(EventName)
by bin(TimeGenerated, 1h), UserIdentityArn, SourceIpAddress
| where ApiCallCount >= 50 or UniqueOps >= 4
| project TimeGenerated, UserIdentityArn, SourceIpAddress,
ApiCallCount, UniqueOps, DataApis
| sort by ApiCallCount desc
CreatePresignedDomainUrl (shares Studio access) as a high-value alert on its own.index=aws_cloudtrail
eventName IN ("CreatePolicyVersion","AttachUserPolicy","AttachRolePolicy",
"AttachGroupPolicy","PutUserPolicy","PutRolePolicy",
"CreateAccessKey","AddUserToGroup","UpdateAssumeRolePolicy",
"PassRole")
NOT errorCode=AccessDenied
| bucket _time span=30m
| stats count as PrivEscOps, values(eventName) as Operations,
values(requestParameters.policyArn) as Policies
by _time, userIdentity.arn, sourceIPAddress
| where PrivEscOps >= 2
| eval risk=case(
mvfind(Operations,"CreatePolicyVersion")>=0 AND mvfind(Operations,"SetDefaultPolicyVersion")>=0,
"CRITICAL — Policy version swap detected",
mvfind(Operations,"AttachUserPolicy")>=0 AND mvfind(Operations,"CreateAccessKey")>=0,
"CRITICAL — Policy attachment + new key in 30min",
mvfind(Operations,"PassRole")>=0 AND mvfind(Operations,"CreateFunction")>=0,
"HIGH — PassRole + Lambda priv-esc path",
true(),"HIGH — Multiple IAM modification in 30min")
| table _time, userIdentity.arn, sourceIPAddress, PrivEscOps, risk, Operations
| sort -PrivEscOps
AWSCloudTrail
| where EventName in ("CreatePolicyVersion","AttachUserPolicy","CreateAccessKey",
"AddUserToGroup","UpdateAssumeRolePolicy")
| where tostring(ErrorCode) == "" // Only successful operations
| summarize OpsCount=count(), Ops=make_set(EventName)
by bin(TimeGenerated, 30m), UserIdentityArn, SourceIpAddress
| where OpsCount >= 2
| extend IsHuman = not (UserIdentityArn has ":assumed-role/AWSServiceRole"
or UserIdentityArn has ":assumed-role/lambda")
| where IsHuman == true
| project TimeGenerated, UserIdentityArn, SourceIpAddress, OpsCount, Ops, IsHuman
| sort by OpsCount desc
index=aws_cloudtrail eventSource=route53.amazonaws.com
eventName IN ("ChangeResourceRecordSets","CreateHostedZone","DeleteHostedZone",
"CreateHealthCheck","UpdateHealthCheck","AssociateVPCWithHostedZone")
| eval change_detail=mvjoin(
'requestParameters.changeBatch.changes{}.resourceRecordSet.name',", ")
| eval record_type=mvjoin(
'requestParameters.changeBatch.changes{}.resourceRecordSet.type',", ")
| stats count as Changes, values(eventName) as Operations,
values(change_detail) as RecordsModified
by userIdentity.arn, sourceIPAddress
| where Changes >= 1
| table _time, userIdentity.arn, sourceIPAddress, Operations, RecordsModified, Changes
| sort -Changes
dataset = xdr_data
| filter event_type = ENUM.NETWORK and network_protocol = "DNS"
| filter dns_query_name ~= "(?:[a-zA-Z0-9]{20,}\.)+" // Long subdomain labels
and dns_query_name not contains ".microsoft.com"
and dns_query_name not contains ".akamai.com"
and dns_query_name not contains ".cloudfront.net"
| bin event_timestamp span = 10m
| agg count() as dns_count, array_agg(dns_query_name) as queries
by event_timestamp, endpoint_id, actor_primary_ip
| filter dns_count >= 20
| sort desc dns_count
(?:[a-zA-Z0-9]{20,}\.)+ catches labels over 20 chars — most legitimate DNS has human-readable subdomains. Whitelist known CDN/telemetry domains. Alert on 20+ queries in 10 minutes to the same base domain from one host — classic C2 beaconing or DNS exfil pattern.Interactive Hunt Tool Suite — 14 Tools
Complete interactive threat hunting toolkit — hunt plan builder, hypothesis library, Sigma converter, SPL/KQL query libraries, beacon detection, LOLBin cluster hunt, Kerberos suite, lateral movement pack, and insider threat detection.
Hunt Plan Builder
Build a complete structured hunt plan from a hypothesis — data sources, indicators, escalation path.
Hunt Hypothesis Library
Structured hunt hypotheses by MITRE tactic with rationale, log sources, and ready queries.
Sigma Rule Converter
Paste any Sigma rule and convert to SPL, KQL, or EQL instantly. Runs client-side.
SPL Hunt Query Library
Production-ready Splunk SPL queries organised by MITRE technique with tuning guidance.
KQL Hunt Query Library
Microsoft Sentinel and Defender KQL queries for Windows, Azure AD, and O365.
IOC to Hunt Query Converter
Paste IOCs from any threat report — get SPL and KQL for all event types instantly.
Beacon Detection Calculator
Understand C2 beacon timing patterns and generate SPL/KQL detection queries.
Long Tail Frequency Analyser
Find rare process executions or DNS queries appearing on only 1–2 hosts.
LOLBin Cluster Hunt
3+ LOLBins from same process in 15 minutes — near-uniquely malicious cluster detection.
Kerberos Attack Hunt Suite
Kerberoasting, AS-REP Roasting, Pass-the-Ticket, Golden/Silver Ticket — SPL and KQL.
SMB Lateral Movement Hunt
Distinguish malicious SMB lateral movement from legitimate file sharing.
Lateral Movement Hunt Pack
WMI, DCOM, WinRM, RDP, token impersonation — every lateral movement technique.
Insider Threat Hunt Pack
Off-hours activity, abnormal data access, bulk downloads, email forwarding rules.
Data Staging & Exfil Hunt
Hunt pre-exfiltration staging — large file copies, ZIP creation, cloud uploads.
Ransomware Pre-Encryption Hunt
Shadow copy enumeration, credential dumping — catch ransomware before encryption.