Detection rules › Kusto

M2131_AssetStoppedLogging

Status
available
Severity
medium
Time window
14d
Group by
ResourceId
Source
github.com/Azure/Azure-Sentinel

'This alert is designed to monitor assets within the Maturity Model for Event Log Management (M-21-31) standard. The alert triggers when a monitored asset fails to provide a heartbeat within 24 hours.'

MITRE ATT&CK coverage

TacticTechniques
DiscoveryT1082 System Information Discovery

Rule body kusto

id: 4be5b645-1d08-49e4-b58d-07294ff19223
name: M2131_AssetStoppedLogging
description: |
  'This alert is designed to monitor assets within the Maturity Model for Event Log Management (M-21-31) standard. The alert triggers when a monitored asset fails to provide a heartbeat within 24 hours.'
severity: Medium
status: Available 
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Discovery
relevantTechniques:
  - T1082
query: |
  let LastHeartbeatTime = Heartbeat
  | summarize LastHeartbeat_Time = arg_max(TimeGenerated, *) by ResourceId;
  Heartbeat
  | where TimeGenerated > ago(14d)
  | summarize LastHeartbeat_Hours = datetime_diff("hour",now(), max(TimeGenerated)) by ResourceId
  | where ResourceId <> ""
  | where ResourceId <> "None"
  | join kind=inner (LastHeartbeatTime) on ResourceId
  | where LastHeartbeat_Hours > 24
  | project LastHeartbeat_Hours, LastHeartbeat_Time, Computer, ComputerIP, Category, OSType, OSName, ResourceId, SubscriptionId, ResourceGroup, RemoteIPCountry 
  | sort by LastHeartbeat_Hours desc
entityMappings:
  - entityType: AzureResource
    fieldMappings:
      - identifier: ResourceId
        columnName: ResourceId
version: 1.0.0
kind: Scheduled

Stages and Predicates

Let binding: LastHeartbeatTime

let LastHeartbeatTime = Heartbeat
| summarize LastHeartbeat_Time = arg_max(TimeGenerated, *) by ResourceId;

Stage 1: source

Heartbeat

Stage 2: where

| where TimeGenerated > ago(14d)

Stage 3: summarize

| summarize LastHeartbeat_Hours = datetime_diff("hour",now(), max(TimeGenerated)) by ResourceId

Stage 4: where

| where ResourceId <> ""

Stage 5: where

| where ResourceId <> "None"

Stage 6: join

| join kind=inner (LastHeartbeatTime) on ResourceId

Stage 7: where

| where LastHeartbeat_Hours > 24

Stage 8: project

| project LastHeartbeat_Hours, LastHeartbeat_Time, Computer, ComputerIP, Category, OSType, OSName, ResourceId, SubscriptionId, ResourceGroup, RemoteIPCountry

Stage 9: sort

| sort by LastHeartbeat_Hours desc

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
LastHeartbeat_Hoursgt
  • 24 transforms: cased
ResourceIdne
  • None transforms: cased

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.

FieldSource
Categoryproject
Computerproject
ComputerIPproject
LastHeartbeat_Hoursproject
LastHeartbeat_Timeproject
OSNameproject
OSTypeproject
RemoteIPCountryproject
ResourceGroupproject
ResourceIdproject
SubscriptionIdproject