Detection rules › Kusto

Rare client observed with high reverse DNS lookup count

Status
available
Severity
medium
Time window
8d
Group by
ClientIP
Source
github.com/Azure/Azure-Sentinel

'Identifies clients with a high reverse DNS counts that could be carrying out reconnaissance or discovery activity. Alerts are generated if the IP performing such reverse DNS lookups was not seen doing so in the preceding 7-day period.'

MITRE ATT&CK coverage

TacticTechniques
Discovery

Rule body

id: 15ae38a2-2e29-48f7-883f-863fb25a5a06
name: Rare client observed with high reverse DNS lookup count
description: |
  'Identifies clients with a high reverse DNS counts that could be carrying out reconnaissance or discovery activity.
  Alerts are generated if the IP performing such reverse DNS lookups was not seen doing so in the preceding 7-day period.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: DNS
    dataTypes:
      - DnsEvents
queryFrequency: 1d
queryPeriod: 8d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Discovery
relevantTechniques:
  - T1046
query: |
  let starttime = 8d;
  let endtime = 1d;
  let threshold = 10;
  DnsEvents
  | where TimeGenerated > ago(endtime)
  | where Name has "in-addr.arpa"
  | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), dcount(Name), ReverseDNSLookup_List = make_set(Name,100) by ClientIP
  | where dcount_Name > threshold
  | project StartTimeUtc, EndTimeUtc, ClientIP , dcount_Name, ReverseDNSLookup_List
  // Filter out previously seen IPs
  // Returns all the records from the left side that don't have matches from the right
  | join kind=leftanti (DnsEvents
      | where TimeGenerated between(ago(starttime)..ago(endtime))
      | where Name has "in-addr.arpa"
      | summarize dcount(Name) by ClientIP, bin(TimeGenerated, 1d)
      | where dcount_Name > threshold
      | project ClientIP , dcount_Name
  ) on ClientIP
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: ClientIP
version: 1.0.2
kind: Scheduled

Stages and Predicates

Parameters

let starttime = 8d;
let endtime = 1d;
let threshold = 10;

Stage 1: source

DnsEvents

Stage 2: where

| where TimeGenerated > ago(endtime)

Stage 3: where

| where Name has "in-addr.arpa"

Stage 4: summarize

| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), dcount(Name), ReverseDNSLookup_List = make_set(Name,100) by ClientIP

Stage 5: where

| where dcount_Name > threshold

Stage 6: project

| project StartTimeUtc, EndTimeUtc, ClientIP , dcount_Name, ReverseDNSLookup_List

Stage 7: join (negated)

| join kind=leftanti (DnsEvents
    | where TimeGenerated between(ago(starttime)..ago(endtime))
    | where Name has "in-addr.arpa"
    | summarize dcount(Name) by ClientIP, bin(TimeGenerated, 1d)
    | where dcount_Name > threshold
    | project ClientIP , dcount_Name
) on ClientIP

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
Namematchin-addr.arpaexcludes:Name field:"Name" value:"in-addr.arpa"
dcount_Namegt10excludes:dcount_Name field:"dcount_Name" value:"10"

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
ClientIPproject
EndTimeUtcproject
ReverseDNSLookup_Listproject
StartTimeUtcproject
dcount_Nameproject