Detection rules › Kusto

UniFi Site Manager: Controller Connection State Change

Status
available
Severity
medium
Time window
1h
Group by
Id, id_s
Source
github.com/Azure/Azure-Sentinel

Identifies when a UniFi controller (Cloud Key, Dream Machine, etc.) experiences a connection state change, which may indicate a network outage, power loss, or device failure.

MITRE ATT&CK coverage

TacticTechniques
Command & Control
Impact

Rule body

id: ac1efe0f-654e-264e-07be-c1b60e698343
name: "UniFi Site Manager: Controller Connection State Change"
description: |
  Identifies when a UniFi controller (Cloud Key, Dream Machine, etc.) experiences a connection state change, which may indicate a network outage, power loss, or device failure.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: UniFiSiteManagerConnectorDefinition
    dataTypes:
      - Unifi_SiteManager_Hosts_CL
queryFrequency: 15m
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Impact
  - CommandAndControl
relevantTechniques:
  - T1489
  - T1071
subTechniques:
  - T1071.001
query: |
  // UniFi Controller Connection State Change Detection
  // Only fire when LastConnectionStateChange has changed since the prior 15-min cycle
  // to avoid 4-5 alerts per actual state change (rule runs every 15m, change visible for 1h).
  let prev = Unifi_SiteManager_Hosts_CL
      | where TimeGenerated between (ago(30m) .. ago(15m))
      | summarize arg_max(TimeGenerated, *) by Id
      | project id_s = Id, prevChange = todatetime(LastConnectionStateChange);
  Unifi_SiteManager_Hosts_CL
  | where TimeGenerated > ago(15m)
  | where isnotempty(LastConnectionStateChange)
  | summarize arg_max(TimeGenerated, *) by Id
  | extend
      ConnectionChange = todatetime(LastConnectionStateChange),
      id_s = Id
  | join kind=leftouter prev on id_s
  | where ConnectionChange != prevChange or isnull(prevChange)
  | where ConnectionChange > ago(30m)
  | extend
      HostTypeDisplay = case(
          HostType == "ucore", "UniFi OS Console",
          HostType == "uck", "Cloud Key",
          HostType == "uckp", "Cloud Key+",
          HostType == "udm", "Dream Machine",
          HostType == "udmpro", "Dream Machine Pro",
          HostType == "udmse", "Dream Machine SE",
          HostType == "self-hosted", "Self-Hosted",
          HostType
      )
  | project
      TimeGenerated,
      ConnectionChangeTime = ConnectionChange,
      PreviousChangeTime = prevChange,
      HostId = Id,
      HostType = HostType,
      HostTypeDisplay,
      IPAddress = IpAddress,
      IsBlocked = IsBlocked,
      IsOwner = Owner
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPAddress
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: PT4H
    matchingMethod: AllEntities
kind: Scheduled
version: 1.0.1

Stages and Predicates

Stage 0: let

let prev = Unifi_SiteManager_Hosts_CL
    | where TimeGenerated between (ago(30m) .. ago(15m))
    | summarize arg_max(TimeGenerated, *) by Id
    | project id_s = Id, prevChange = todatetime(LastConnectionStateChange);

Stage 1: source

Unifi_SiteManager_Hosts_CL

Stage 2: where

| where TimeGenerated > ago(15m)

Stage 3: where

| where isnotempty(LastConnectionStateChange)

Stage 4: summarize

| summarize arg_max(TimeGenerated, *) by Id

Stage 5: extend

| extend
    ConnectionChange = todatetime(LastConnectionStateChange),
    id_s = Id

Stage 6: join

| join kind=leftouter prev on id_s

Stage 7: where

where (ConnectionChange != prevChange or isempty(prevChange))

Stage 8: where

where ConnectionChange > ago(1800s)

Stage 9: extend

extend HostTypeDisplay
HostTypeDisplay =
ifHostType == "ucore""UniFi OS Console"
elifHostType == "uck""Cloud Key"
elifHostType == "uckp""Cloud Key+"
elifHostType == "udm""Dream Machine"
elifHostType == "udmpro""Dream Machine Pro"
elifHostType == "udmse""Dream Machine SE"
elifHostType == "self-hosted""Self-Hosted"
elseHostType

Stage 10: project

project ConnectionChangeTime, HostId, HostType, HostTypeDisplay, IPAddress, IsBlocked, IsOwner, PreviousChangeTime, TimeGenerated

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
ConnectionChangeTimeproject
HostIdproject
HostTypeproject
HostTypeDisplayproject
IPAddressproject
IsBlockedproject
IsOwnerproject
PreviousChangeTimeproject
TimeGeneratedproject