Detection rules › Kusto
Unusual Anomaly
'Anomaly Rules generate events in the Anomalies table. This scheduled rule tries to detect Anomalies that are not usual, they could be a type of Anomaly that has recently been activated, or an infrequent type. The detected Anomaly should be reviewed, if it is relevant enough, eventually a separate scheduled Analytics Rule could be created specifically for that Anomaly Type, so an alert and/or incident is generated everytime that type of Anomaly happens.'
Rule body kusto
id: d0255b5f-2a3c-4112-8744-e6757af3283a
name: Unusual Anomaly
description: |
'Anomaly Rules generate events in the Anomalies table. This scheduled rule tries to detect Anomalies that are not usual, they could be a type of Anomaly that has recently been activated, or an infrequent type. The detected Anomaly should be reviewed, if it is relevant enough, eventually a separate scheduled Analytics Rule could be created specifically for that Anomaly Type, so an alert and/or incident is generated everytime that type of Anomaly happens.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 1h
queryPeriod: 4d
triggerOperator: gt
triggerThreshold: 0
tactics: []
techniques: []
query: |
// You can leave out Anomalies that are already monitored through other Analytics Rules
//let _MonitoredRules = dynamic(["TestAlertName"]);
let query_frequency = 1h;
let query_lookback = 3d;
Anomalies
| where TimeGenerated > ago(query_frequency)
//| where not(RuleName has_any (_MonitoredRules))
| join kind = leftanti (
Anomalies
| where TimeGenerated between (ago(query_frequency + query_lookback)..ago(query_frequency))
| distinct RuleName
) on RuleName
| extend Name = tostring(split(UserPrincipalName, "@")[0]), UPNSuffix = tostring(split(UserPrincipalName, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserPrincipalName
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
eventGroupingSettings:
aggregationKind: AlertPerResult
alertDetailsOverride:
alertDisplayNameFormat: Unusual Anomaly - {{RuleName}}
alertTacticsColumnName: Tactics
alertDynamicProperties:
- alertProperty: Techniques
value: Techniques
version: 1.0.3
kind: Scheduled
Stages and Predicates
Parameters
let query_frequency = 1h;
let query_lookback = 3d;
Stage 1: source
Anomalies
Stage 2: where
| where TimeGenerated > ago(query_frequency)
Stage 3: join (negated)
| join kind = leftanti (
Anomalies
| where TimeGenerated between (ago(query_frequency + query_lookback)..ago(query_frequency))
| distinct RuleName
) on RuleName
Stage 4: extend
| extend Name = tostring(split(UserPrincipalName, "@")[0]), UPNSuffix = tostring(split(UserPrincipalName, "@")[1])
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
Name | extend |
UPNSuffix | extend |