Detection rules › Kusto

UniFi Site Manager: ISP High Latency

Status
available
Severity
medium
Time window
30m
Group by
SiteId, ispAsn, ispName, metricTime
Source
github.com/Azure/Azure-Sentinel

Identifies when ISP latency exceeds acceptable thresholds, impacting VoIP quality, video conferencing, and overall application performance.

MITRE ATT&CK coverage

Rule body

id: 77d8f6d0-b45c-ea6e-7c58-daac194a095f
name: "UniFi Site Manager: ISP High Latency"
description: |
  Identifies when ISP latency exceeds acceptable thresholds, impacting VoIP quality, video conferencing, and overall application performance.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: UniFiSiteManagerConnectorDefinition
    dataTypes:
      - Unifi_SiteManager_ISPMetrics_CL
queryFrequency: 15m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Impact
relevantTechniques:
  - T1498
  - T1499
subTechniques:
  - T1498.001
  - T1499.002
query: |
  // UniFi ISP High Latency Detection
  let AvgLatencyThreshold = 200;
  let MaxLatencyThreshold = 1000;
  let SustainedPeriodCount = 2;
  Unifi_SiteManager_ISPMetrics_CL
  | where TimeGenerated > ago(30m)
  | mv-expand period = Periods
  | extend
      metricTime = todatetime(period.metricTime),
      avgLatency = toint(period.data.wan.avgLatency),
      maxLatency = toint(period.data.wan.maxLatency),
      ispName = tostring(period.data.wan.ispName),
      ispAsn = tostring(period.data.wan.ispAsn)
  // De-duplicate Periods: each poll returns the same hour buckets, so collapse to latest value per metricTime
  | summarize arg_max(TimeGenerated, avgLatency, maxLatency, ispAsn) by tostring(SiteId), ispName, metricTime
  | where metricTime > ago(30m)
  | where avgLatency > AvgLatencyThreshold or maxLatency > MaxLatencyThreshold
  | summarize
      EventCount = count(),
      AvgLatency = avg(avgLatency),
      MaxLatency = max(maxLatency),
      FirstSeen = min(metricTime),
      LastSeen = max(metricTime)
      by SiteId, ispName, ispAsn
  | where EventCount >= SustainedPeriodCount
  | extend 
      TimeGenerated = now(),
      AvgLatencyRounded = round(AvgLatency, 1)
  | project
      TimeGenerated,
      SiteId = SiteId,
      ISPName = ispName,
      ISPAsn = ispAsn,
      AvgLatencyMs = AvgLatencyRounded,
      MaxLatencyMs = MaxLatency,
      EventCount,
      FirstSeen,
      LastSeen
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: SiteId
  - entityType: CloudApplication
    fieldMappings:
      - identifier: Name
        columnName: ISPName
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: PT4H
    matchingMethod: AllEntities
kind: Scheduled
version: 1.0.1

Stages and Predicates

Parameters

let AvgLatencyThreshold = 200;
let MaxLatencyThreshold = 1000;
let SustainedPeriodCount = 2;

Stage 1: source

Unifi_SiteManager_ISPMetrics_CL

Stage 2: where

| where TimeGenerated > ago(30m)

Stage 3: mv-expand

| mv-expand period = Periods

Stage 4: extend

| extend
    metricTime = todatetime(period.metricTime),
    avgLatency = toint(period.data.wan.avgLatency),
    maxLatency = toint(period.data.wan.maxLatency),
    ispName = tostring(period.data.wan.ispName),
    ispAsn = tostring(period.data.wan.ispAsn)

Stage 5: summarize

| summarize arg_max(TimeGenerated, avgLatency, maxLatency, ispAsn) by tostring(SiteId), ispName, metricTime

Stage 6: where

| where metricTime > ago(30m)

Stage 7: where

| where avgLatency > AvgLatencyThreshold or maxLatency > MaxLatencyThreshold

Stage 8: summarize

| summarize
    EventCount = count(),
    AvgLatency = avg(avgLatency),
    MaxLatency = max(maxLatency),
    FirstSeen = min(metricTime),
    LastSeen = max(metricTime)
    by SiteId, ispName, ispAsn

Stage 9: where

| where EventCount >= SustainedPeriodCount

Stage 10: extend

| extend 
    TimeGenerated = now(),
    AvgLatencyRounded = round(AvgLatency, 1)

Stage 11: project

| project
    TimeGenerated,
    SiteId = SiteId,
    ISPName = ispName,
    ISPAsn = ispAsn,
    AvgLatencyMs = AvgLatencyRounded,
    MaxLatencyMs = MaxLatency,
    EventCount,
    FirstSeen,
    LastSeen

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
AvgLatencyMsproject
EventCountproject
FirstSeenproject
ISPAsnproject
ISPNameproject
LastSeenproject
MaxLatencyMsproject
SiteIdproject
TimeGeneratedproject