↳ GitHub sourceAnalytics ruleMedium

Detect excessive NXDOMAIN DNS queries - Anomaly based (ASIM DNS Solution)

Description

'This rule makes use of the series decompose anomaly method to generate an alert when client requests excessive amount of DNS queries to non-existent domains. This helps in identifying possible C2 communications. It utilizes [ASIM](https://aka.ms/AboutASIM) normalization and is applied to any source that supports the ASIM DNS schema. The rule also depends on the "**DNSEssentialsCustomParser**" Parser, so please make sure it is installed and configured before you use this Rule.'
Rule type
Scheduled
Version
1.0.3
Declared status
Available
Query frequency
1d
Query period
14d
Trigger
gt 0

Declared MITRE coverage

KQL query

Original query, unchanged.

let threshold = 2.5;
let min_t = ago(14d);
let max_t = now();
let dt = 1d;
let summarizationexist = (
  union isfuzzy=true 
      (
      DNSEssentialsCustomParser
      | where Type in ("DNS_Summarized_Logs_ip_CL", "DNS_Summarized_Logs_ipV1_CL")
      | where EventTime_t > ago(1d) 
      | project v = int(2)
      ),
      (
      print int(1) 
      | project v = print_0
      )
  | summarize maxv = max(v)
  | extend sumexist = (maxv > 1)
  );
let allData = union isfuzzy=true
      (
      (datatable(exists: int, sumexist: bool)[1, false]
      | join (summarizationexist) on sumexist)
      | join (
          _Im_Dns(responsecodename='NXDOMAIN', starttime=todatetime(min_t), endtime=max_t)
          | summarize Count=count() by SrcIpAddr, bin(TimeGenerated, 1h)
          | extend EventTime = TimeGenerated, Count = toint(Count), exists=int(1)
          )
          on exists
      | project-away exists, maxv, sum*
      ),
      (
      DNSEssentialsCustomParser
      | where Type in ("DNS_Summarized_Logs_ip_CL", "DNS_Summarized_Logs_ipV1_CL")
      | where EventTime_t > min_t and EventResultDetails_s == 'NXDOMAIN'
      | summarize Count=toint(sum(count__d)) by SrcIpAddr=SrcIpAddr_s, bin(EventTime=EventTime_t, 1h)
      );
allData
| make-series EventCount=sum(Count) on EventTime from min_t to max_t step dt by SrcIpAddr
| extend (anomalies, score, baseline) = series_decompose_anomalies(EventCount, threshold, -1, 'linefit')
| mv-expand anomalies, score, baseline, EventTime, EventCount
| extend
  anomalies = toint(anomalies),
  score = toint(score),
  baseline = toint(baseline),
  EventTime = todatetime(EventTime),
  Total = tolong(EventCount)
| where EventTime >= ago(dt)
| where score >= threshold * 2
| join kind=inner(_Im_Dns(responsecodename='NXDOMAIN', starttime=ago(dt), endtime=max_t)
  | summarize DNSQueries = make_set(DnsQuery) by SrcIpAddr)
  on SrcIpAddr
| project-away SrcIpAddr1

Declared entities

IP

Related content

Links established from declared identifiers and solution manifests.

Source provenance

GitHub

Displayed values come from files in Azure/Azure-Sentinel. They describe the published template, not your workspace configuration.

Source identifier
02f23312-1a33-4390-8b80-f7cd4df4dea0
Additional source files 2Solutions/DNS Essentials/Analytic Rules/ExcessiveNXDOMAINDNSQueriesAnomalyBased.yamlsource ↗Solutions/DNS Essentials/Data/Solution_DNS.jsonsolution-membership ↗
GSTEP / CATALOG TRACKING

Added to catalog : 16 Sept 2026 · 05:49 UTC
Last change observed : 16 Sept 2026 · 05:49 UTC

GSTEP sync dates, separate from the source content’s publication dates.