Detection rules › Kusto

UniFi Site Manager: Multiple Devices Offline

Status
available
Severity
high
Time window
30m
Group by
Id
Source
github.com/Azure/Azure-Sentinel

Identifies when multiple UniFi devices go offline simultaneously, typically signaling a power outage, upstream connectivity failure, or infrastructure issue requiring investigation.

MITRE ATT&CK coverage

Rule body

id: 9283b576-5350-fca1-3979-dacb6acd1d16
name: "UniFi Site Manager: Multiple Devices Offline"
description: |
  Identifies when multiple UniFi devices go offline simultaneously, typically signaling a power outage, upstream connectivity failure, or infrastructure issue requiring investigation.
severity: High
status: Available
requiredDataConnectors:
  - connectorId: UniFiSiteManagerConnectorDefinition
    dataTypes:
      - Unifi_SiteManager_Devices_CL
queryFrequency: 15m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Impact
relevantTechniques:
  - T1489
  - T1499
subTechniques:
  - T1499.002
query: |
  let prev_offline_ids = Unifi_SiteManager_Devices_CL
      | where TimeGenerated between (ago(45m) .. ago(15m))
      | summarize arg_max(TimeGenerated, *) by Id
      | where Status == "offline"
      | distinct Id;
  Unifi_SiteManager_Devices_CL
  | where TimeGenerated > ago(15m)
  | summarize arg_max(TimeGenerated, *) by Id
  | where Status == "offline"
  | extend IsNew = Id !in (prev_offline_ids)
  | summarize
      OfflineDeviceCount = count(),
      NewlyOfflineCount = countif(IsNew),
      OfflineDevices = make_list(coalesce(Name, Id)),
      NewlyOfflineDevices = make_list_if(coalesce(Name, Id), IsNew),
      ProductLines = make_set(ProductLine)
  | where OfflineDeviceCount >= 3
  | where NewlyOfflineCount > 0
  | extend
      TimeGenerated = now(),
      OfflineDeviceList = strcat_array(OfflineDevices, ", "),
      NewlyOfflineList = strcat_array(NewlyOfflineDevices, ", "),
      AffectedProductLines = strcat_array(ProductLines, ", ")
  | extend Activity = strcat(NewlyOfflineCount, ' device(s) newly offline (', OfflineDeviceCount, ' total offline): ', NewlyOfflineList)
  | project
      TimeGenerated,
      OfflineDeviceCount,
      NewlyOfflineCount,
      OfflineDeviceList,
      NewlyOfflineList,
      AffectedProductLines,
      Activity
entityMappings:
  - entityType: CloudApplication
    fieldMappings:
      - identifier: Name
        columnName: AffectedProductLines
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: true
    lookbackDuration: PT4H
    matchingMethod: AllEntities
kind: Scheduled
version: 1.0.3

Stages and Predicates

Let binding: prev_offline_ids used in Stage 5

let prev_offline_ids = Unifi_SiteManager_Devices_CL
    | where TimeGenerated between (ago(45m) .. ago(15m))
    | summarize arg_max(TimeGenerated, *) by Id
    | where Status == "offline"
    | distinct Id;

Stage 1: source

Unifi_SiteManager_Devices_CL

Stage 2: where

| where TimeGenerated > ago(15m)

Stage 3: summarize

| summarize arg_max(TimeGenerated, *) by Id

Stage 4: where

| where Status == "offline"

Stage 5: extend

| extend IsNew = Id !in (prev_offline_ids)

Stage 6: summarize

| summarize
    OfflineDeviceCount = count(),
    NewlyOfflineCount = countif(IsNew),
    OfflineDevices = make_list(coalesce(Name, Id)),
    NewlyOfflineDevices = make_list_if(coalesce(Name, Id), IsNew),
    ProductLines = make_set(ProductLine)

Stage 7: where

| where OfflineDeviceCount >= 3

Stage 8: where

| where NewlyOfflineCount > 0

Stage 9: extend

| extend
    TimeGenerated = now(),
    OfflineDeviceList = strcat_array(OfflineDevices, ", "),
    NewlyOfflineList = strcat_array(NewlyOfflineDevices, ", "),
    AffectedProductLines = strcat_array(ProductLines, ", ")

Stage 10: extend

| extend Activity = strcat(NewlyOfflineCount, ' device(s) newly offline (', OfflineDeviceCount, ' total offline): ', NewlyOfflineList)

Stage 11: project

| project
    TimeGenerated,
    OfflineDeviceCount,
    NewlyOfflineCount,
    OfflineDeviceList,
    NewlyOfflineList,
    AffectedProductLines,
    Activity

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
Activityproject
AffectedProductLinesproject
NewlyOfflineCountproject
NewlyOfflineListproject
OfflineDeviceCountproject
OfflineDeviceListproject
TimeGeneratedproject