Detection rules › Kusto

Potential DGA detected (ASIM DNS Schema)

Severity
medium
Time window
10d
Group by
SrcIpAddr, dcount_sld
Author
Yaron
Source
github.com/Azure/Azure-Sentinel

'Identifies clients with a high NXDomain count which could be indicative of a DGA (cycling through possible C2 domains where most C2s are not live). Alert is generated when a new IP address is seen (based on not being seen associated with NXDomain records in prior 10-day baseline period). This analytic rule uses ASIM and supports any built-in or custom source that supports the ASIM DNS schema'

MITRE ATT&CK coverage

TacticTechniques
Command & ControlT1008 Fallback Channels, T1568 Dynamic Resolution

Rule body kusto

id: 983a6922-894d-413c-9f04-d7add0ecc307
name: Potential DGA detected (ASIM DNS Schema)
description: |
  'Identifies clients with a high NXDomain count which could be indicative of a DGA (cycling through possible C2 domains where most C2s are not live). Alert is generated when a new IP address is seen (based on not being seen associated with 
  NXDomain records in prior 10-day baseline period).
  This analytic rule uses [ASIM](https://aka.ms/AboutASIM) and supports any built-in or custom source that supports the ASIM DNS schema'
severity: Medium
requiredDataConnectors:
  - connectorId: DNS
    dataTypes:
      - DnsEvents
  - connectorId: AzureFirewall
    dataTypes: 
      - AzureDiagnostics
  - connectorId: Zscaler
    dataTypes:
      - CommonSecurityLog
  - connectorId: InfobloxNIOS
    dataTypes: 
      - Syslog
  - connectorId: GCPDNSDataConnector
    dataTypes: 
      - GCP_DNS_CL
  - connectorId: NXLogDnsLogs
    dataTypes: 
      - NXLog_DNS_Server_CL
  - connectorId: CiscoUmbrellaDataConnector
    dataTypes: 
      - Cisco_Umbrella_dns_CL
  - connectorId: Corelight
    dataTypes: 
      - Corelight_CL

queryFrequency: 1d
queryPeriod: 10d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CommandAndControl
relevantTechniques:
  - T1568
  - T1008
tags:
  - ParentAlert: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/DnsEvents/DNS_HighNXDomainCount_detection.yaml
    version: 1.0.0
  - Schema: ASIMDns
    SchemaVersion: 0.1.1
query: |
  let referencestarttime = 10d;
  let referenceendtime = 1d;
  let threshold = 100;
  let nxDomainDnsEvents = (stime:datetime, etime:datetime) 
    {_Im_Dns(responsecodename='NXDOMAIN', starttime=stime, endtime=etime)
    | where DnsQueryTypeName in ("A", "AAAA")
    | where ipv4_is_match("127.0.0.1", SrcIpAddr) == False
    | where DnsQuery !contains "/" and  DnsQuery contains "."};
  nxDomainDnsEvents (stime=ago(referenceendtime) ,etime=now())
    | extend sld = tostring(split(DnsQuery, ".")[-2])
    | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), dcount(sld) by SrcIpAddr
    | where dcount_sld > threshold
    // Filter out previously seen IPs
    | join kind=leftanti (nxDomainDnsEvents (stime=ago(referencestarttime), etime=ago(referenceendtime))
      | extend sld = tostring(split(DnsQuery, ".")[-2])
      | summarize dcount(sld) by SrcIpAddr
      | where dcount_sld > threshold ) on SrcIpAddr
  // Pull out sample NXDomain responses for those remaining potentially infected IPs
  | join kind = inner (nxDomainDnsEvents (stime=ago(referencestarttime), etime=now()) | summarize by DnsQuery, SrcIpAddr) on SrcIpAddr
  | summarize StartTime = min(StartTime), EndTime = max(EndTime), sampleNXDomainList=make_list(DnsQuery, 100)  by SrcIpAddr, dcount_sld
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
version: 1.3.4
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Yaron
    support:
        tier: Community
    categories:
        domains: [ "Security - Network" ]

Stages and Predicates

Parameters

let referencestarttime = 10d;
let referenceendtime = 1d;
let threshold = 100;

The stages below define let nxDomainDnsEvents (the rule's main pipeline source).

Stage 1: source

_Im_Dns

Stage 2: where

where DnsQueryTypeName in~ ("A", "AAAA")

Stage 3: where

where not (ipv4_is_in_range(SrcIpAddr, "127.0.0.1"))

Stage 4: where

where not (DnsQuery contains "/") and DnsQuery contains "."

The stages below run on nxDomainDnsEvents (the outer pipeline).

Stage 5: extend

extend sld

Stage 6: summarize

summarize EndTime, StartTime by SrcIpAddr

Stage 7: where

where dcount_sld > 100

Stage 8: join (negated)

join kind=leftanti (...)

Stage 9: join

join kind=inner (...)

Stage 10: summarize

summarize EndTime, StartTime, sampleNXDomainList by SrcIpAddr, dcount_sld

Exclusions

Top-level NOT(...) conjuncts: predicates this rule actively suppresses.

FieldKindExcluded values
SrcIpAddrcidr_match127.0.0.1
DnsQuerycontains/
dcount_sldgt100

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.

FieldKindValues
DnsQuerycontains
  • .
DnsQueryTypeNamein
  • A transforms: cased
  • AAAA transforms: cased
dcount_sldgt
  • 100 transforms: cased

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.

FieldSource
EndTimesummarize
SrcIpAddrsummarize
StartTimesummarize
dcount_sldsummarize
sampleNXDomainListsummarize