Query Details

Multiple Excessive NXDOMAIN DNS Queries

Query

let query_frequency = 1d;
let query_period = 2d;
let distinct_domain_threshold = 10;
let _ExcludedIPAddresses = toscalar(
    _GetWatchlist('Service-PrivateCorporateServices')
    | where Notes has "[NXDOMAINDnsQuery]"
    | summarize make_list(IPAddress)
);
let _DomainRegex = toscalar(
    _GetWatchlist('RegEx-SingleRegularExpressions')
    | where UseCase == "Threat Intelligence Indicator Domain"
    | project RegEx
);
let _BenignDomainRegex = toscalar(
    (union isfuzzy=true
        _GetWatchlist("Domain-RareBenignDomains"),
        _GetWatchlist("Domain-PrivDomains")
    )
    | summarize RegEx = make_set(regex_quote(Domain))
);
let _PastWindowsDNSEvents =
    DnsEvents
    | where TimeGenerated between (ago(query_period)..ago(query_frequency))
    | where ResultCode == 3 and not(QueryType in ("DNAME", "33", "64", "65", "249")) and not(ClientIP in (_ExcludedIPAddresses))
    | where not(Name matches regex strcat(@'(?i)(', strcat_array(_BenignDomainRegex, '|'), @')(?-i)$'))
    | where Name matches regex strcat(_DomainRegex, @"$")
    | distinct
        SrcIpAddr = ClientIP,
        DnsQueryTypeName = QueryType,
        SLD = tolower(strcat_array(array_slice(split(Name, "."), -2, -1), "."))
;
let _PastUmbrellaDNSEvents =
    Cisco_Umbrella_dns_CL
    | where TimeGenerated between (ago(query_period)..ago(query_frequency))
    | where ResponseCode_s == "NXDOMAIN" and not(QueryType_s has_any ("PTR", "SRV", "SOA")) //and not(InternalIp_s == ExternalIp_s)
    | where not(Domain_s matches regex strcat(@'(?i)(', strcat_array(_BenignDomainRegex, '|'), @')(?-i)\.$'))
    | where Domain_s matches regex strcat(_DomainRegex, @"\.$")
    | distinct
        SrcIpAddr = InternalIp_s,
        QueryType_s,
        SLD = strcat_array(array_slice(split(Domain_s, "."), -3, -2), ".")
    | parse QueryType_s with DnsQueryType:int " (" DnsQueryTypeName:string ")"
    | project
        SrcIpAddr,
        DnsQueryTypeName,
        SLD
;
let _CurrentWindowsDNSEvents =
    DnsEvents
    | where TimeGenerated between (ago(query_frequency)..now())
    | where ResultCode == 3 and not(QueryType in ("DNAME", "33", "64", "65", "249")) and not(ClientIP in (_ExcludedIPAddresses))
    | where not(Name matches regex strcat(@'(?i)(', strcat_array(_BenignDomainRegex, '|'), @')(?-i)$'))
    | where Name matches regex strcat(_DomainRegex, @"$")
    | project
        TimeGenerated,
        SrcIpAddr = ClientIP,
        DnsQueryTypeName = QueryType,
        DnsQuery = Name,
        SLD = tolower(strcat_array(array_slice(split(Name, "."), -2, -1), "."))
;
let _CurrentUmbrellaDNSEvents =
    Cisco_Umbrella_dns_CL
    | where TimeGenerated between (ago(query_frequency)..now())
    | where ResponseCode_s == "NXDOMAIN" and not(QueryType_s has_any ("PTR", "SRV", "SOA")) //and not(InternalIp_s == ExternalIp_s)
    | where not(Domain_s matches regex strcat(@'(?i)(', strcat_array(_BenignDomainRegex, '|'), @')(?-i)\.$'))
    | where Domain_s matches regex strcat(_DomainRegex, @"\.$")
    | parse QueryType_s with DnsQueryType:int " (" DnsQueryTypeName:string ")"
    | mv-apply Identities_s_aux = todynamic(Identities_s) to typeof(string), Identity_Types_s_aux = todynamic(Identity_Types_s) to typeof(string) on ( 
        summarize Identities = make_bag(bag_pack(Identity_Types_s_aux, Identities_s_aux))
        )
    | project
        TimeGenerated = todatetime(column_ifexists('Timestamp_t', column_ifexists('Timestamp_s',''))),
        Identities,
        SrcIpAddr = column_ifexists('InternalIp_s', ''),
        SrcNatIpAddr = column_ifexists('ExternalIp_s', ''),
        DnsQueryTypeName,
        DnsQuery = trim_end(@'\.', column_ifexists('Domain_s', '')),
        SLD = strcat_array(array_slice(split(Domain_s, "."), -3, -2), ".")
;
union _CurrentWindowsDNSEvents, _CurrentUmbrellaDNSEvents
| join kind=leftanti
    (union _PastWindowsDNSEvents, _PastUmbrellaDNSEvents)
    on SrcIpAddr, DnsQueryTypeName, SLD
| summarize
    StartTime = min(TimeGenerated),
    EndTime = max(TimeGenerated),
    Identities = make_set(Identities, 5),
    take_any(SrcNatIpAddr),
    DnsQueryTypeNames = array_sort_asc(make_set(DnsQueryTypeName)),
    SLDSample = make_set(SLD, 100),
    SLDDistinctCount = dcount(SLD),
    DnsQuerySample = make_set(DnsQuery, 150),
    DnsQueryDistinctCount = dcount(DnsQuery)
    by SrcIpAddr
| where DnsQueryDistinctCount > distinct_domain_threshold or SLDDistinctCount > distinct_domain_threshold
| project
    StartTime,
    EndTime,
    Identities,
    SrcIpAddr,
    SrcNatIpAddr,
    DnsQueryTypeNames,
    SLDDistinctCount,
    SLDSample,
    DnsQueryDistinctCount,
    DnsQuerySample

Explanation

The query is retrieving DNS events from both Windows and Cisco Umbrella logs. It filters the events based on certain criteria such as time range, result code, query type, and excluded IP addresses. It also uses watchlists to filter out benign domains and extract regular expressions for domain matching. The query then joins the current and past DNS events and summarizes the results by grouping them based on source IP address. It calculates various metrics such as the start and end time of the events, the identities associated with the IP address, the source NAT IP address, the DNS query type names, the distinct count and samples of second-level domains (SLD), and the distinct count and samples of DNS queries. Finally, it filters the summarized results based on a threshold for distinct domain counts and returns the relevant information.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: March 23, 2023

Tables

_DnsEventsCisco_Umbrella_dns_CL

Keywords

Devices,Intune,User

Operators

|=lettoscalar|wherehassummarizemake_listprojectunionisfuzzymake_setregex_quotesummarizeDnsEventsbetweenagoandnotinmatches regexdistinctSrcIpAddrDnsQueryTypeNameSLDCisco_Umbrella_dns_CLResponseCode_shas_anyparsewithmv-applytodynamictypeofonsummarizemake_bagbag_packcolumn_ifexiststodatetimetrim_endjoinkind=leftantiStartTimeEndTimeIdentitiestake_anyarray_sort_ascSLDSampleSLDDistinctCountDnsQuerySampleDnsQueryDistinctCountbywhereproject

Actions