Detection rules › Kusto
Detect excessive NXDOMAIN DNS queries - Static threshold based (ASIM DNS Solution)
This rule generates an alert when the configured threshold for DNS queries to non-existent domains is breached. This helps in identifying possible C2 communications. It utilizes ASIM normalization and is applied to any source that supports the ASIM DNS schema.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Command & Control | T1008 Fallback Channels, T1568 Dynamic Resolution |
Event coverage
| Provider | Event | Title |
|---|---|---|
| Sysmon | Event ID 22 | DNSEvent (DNS query) |
Rule body kusto
id: 4ab8b09e-3c23-4974-afbe-7e653779eb2b
name: Detect excessive NXDOMAIN DNS queries - Static threshold based (ASIM DNS Solution)
description: |
'This rule generates an alert when the configured threshold for DNS queries to non-existent domains is breached. 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.'
severity: Medium
status: Available
tags:
- Schema: ASimDns
SchemaVersion: 0.1.6
requiredDataConnectors: []
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1568
- T1008
query: |
let lookback = 1h;
let threshold = 200;
_Im_Dns(starttime=ago(lookback), responsecodename='NXDOMAIN')
| summarize NXDOMAINCount=count() by SrcIpAddr, bin(TimeGenerated, 15m)
| where NXDOMAINCount > threshold
| join kind=inner (_Im_Dns(starttime=ago(lookback), responsecodename='NXDOMAIN')
| summarize DNSQueries = makeset(DnsQuery) by SrcIpAddr)
on SrcIpAddr
| extend NXDOMAINthreshold=threshold
| project-away SrcIpAddr1
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
DNSQueries: DNSQueries
NXDOMAINthreshold: NXDOMAINthreshold
NXDOMAINCount: NXDOMAINCount
alertDetailsOverride:
alertDisplayNameFormat: "[Static threshold] Excessive NXDOMAIN DNS Queries has been detected from client IP: '{{SrcIpAddr}}'"
alertDescriptionFormat: "Client is generating excessive amount of DNS queries for non-existent domains. This can be an indication of possible C2 communications. \n\n'NXDOMAIN' error count threshold: '{{NXDOMAINthreshold}}'\n\nCurrent 'NXDOMAIN' error count from this client: '{{NXDOMAINCount}}'\n\nDNS queries requested by the client include:\n\n'{{DNSQueries}}'"
version: 1.0.2
kind: Scheduled
Stages and Predicates
Parameters
let lookback = 1h;
let threshold = 200;
Stage 1: source
_Im_Dns(starttime=ago(lookback), responsecodename='NXDOMAIN')
Stage 2: summarize
| summarize NXDOMAINCount=count() by SrcIpAddr, bin(TimeGenerated, 15m)
Stage 3: where
| where NXDOMAINCount > threshold
Stage 4: join
| join kind=inner (_Im_Dns(starttime=ago(lookback), responsecodename='NXDOMAIN')
| summarize DNSQueries = makeset(DnsQuery) by SrcIpAddr)
on SrcIpAddr
Stage 5: extend
| extend NXDOMAINthreshold=threshold
Stage 6: project-away
| project-away SrcIpAddr1
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.
| Field | Kind | Values |
|---|---|---|
NXDOMAINCount | gt |
|
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.
| Field | Source |
|---|---|
NXDOMAINCount | summarize |
SrcIpAddr | summarize |
NXDOMAINthreshold | extend |