Back
Id8f3c1a4e-6b52-4d19-9c07-2a5e8d0f7b41
RulenameDatazag - impersonation domain resolved in DNS
DescriptionMatches active Datazag impersonation indicators against DNS activity normalized by the ASIM

Dns schema, so the rule works across any normalized DNS source without modification. A match

means a host inside the estate resolved a domain Datazag scored as brand impersonation,

platform impersonation or attacker infrastructure. Requires the ASIM DNS parsers.
SeverityHigh
TacticsInitialAccess
CommandAndControl
TechniquesT1566
T1071
Required data connectorsThreatIntelligenceTaxii
KindScheduled
Query frequency1h
Query period14d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Datazag/Analytic%20Rules/DatazagDomainIndicatorMatch_DNS.yaml
Version1.0.0
Arm template8f3c1a4e-6b52-4d19-9c07-2a5e8d0f7b41.json
Deploy To Azure
let datazag_identity = "identity--55a5a448-c6f1-5128-bc71-4d85b719131e";
let ioc_lookback = 14d;
let dns_lookback = 1h;
let confidence_floor = 85;
let DatazagDomains =
    ThreatIntelIndicators
    | where TimeGenerated >= ago(ioc_lookback)
    | where tostring(Data.created_by_ref) == datazag_identity
    | where ObservableKey == "domain-name:value"
    | where isnotempty(ObservableValue)
    | summarize arg_max(TimeGenerated, *) by Id
    | where IsDeleted == false
    | where tostring(Data.revoked) != "true"
    | where isempty(ValidUntil) or ValidUntil > now()
    | where Confidence >= confidence_floor
    | extend IndicatorDomain = tolower(trim_end(@"\.", ObservableValue))
    | project
        IndicatorDomain,
        IndicatorStixId     = tostring(Data.id),
        IndicatorRecordId   = Id,
        DatazagAlertRef     = tostring(Data.external_references[0].external_id),
        Confidence,
        IndicatorEvidence   = tostring(Data.labels),
        IndicatorValidUntil = ValidUntil;
let DnsActivity =
    _Im_Dns
    | where TimeGenerated >= ago(dns_lookback)
    | where isnotempty(DnsQuery)
    | extend IndicatorDomain = tolower(trim_end(@"\.", DnsQuery))
    | project
        DnsTime         = TimeGenerated,
        IndicatorDomain,
        DnsQuery,
        SrcIpAddr       = column_ifexists("SrcIpAddr", ""),
        SrcHostname     = column_ifexists("SrcHostname", ""),
        SrcUsername     = column_ifexists("SrcUsername", ""),
        SrcUsernameType = column_ifexists("SrcUsernameType", ""),
        EventVendor     = column_ifexists("EventVendor", ""),
        EventProduct    = column_ifexists("EventProduct", "");
DatazagDomains
| join kind=innerunique DnsActivity on IndicatorDomain
| summarize
    FirstSeen   = min(DnsTime),
    LastSeen    = max(DnsTime),
    QueryCount  = count(),
    SourceIps   = make_set(SrcIpAddr, 50),
    SourceHosts = make_set(SrcHostname, 50),
    Upns        = make_set_if(SrcUsername, SrcUsernameType == "UPN", 50),
    SeenBy      = make_set(strcat(EventVendor, " ", EventProduct), 10)
    by
    IndicatorDomain, IndicatorStixId, IndicatorRecordId, DatazagAlertRef,
    Confidence, IndicatorEvidence, IndicatorValidUntil
| extend
    SourceIp   = tostring(SourceIps[0]),
    SourceHost = tostring(SourceHosts[0]),
    AccountUpn = tostring(Upns[0])
| order by LastSeen desc
incidentConfiguration:
  groupingConfiguration:
    lookbackDuration: 1d
    enabled: true
    reopenClosedIncident: false
    matchingMethod: Selected
    groupByEntities:
    - DNS
  createIncident: true
name: Datazag - impersonation domain resolved in DNS
suppressionDuration: 1h
suppressionEnabled: false
triggerOperator: gt
query: |
  let datazag_identity = "identity--55a5a448-c6f1-5128-bc71-4d85b719131e";
  let ioc_lookback = 14d;
  let dns_lookback = 1h;
  let confidence_floor = 85;
  let DatazagDomains =
      ThreatIntelIndicators
      | where TimeGenerated >= ago(ioc_lookback)
      | where tostring(Data.created_by_ref) == datazag_identity
      | where ObservableKey == "domain-name:value"
      | where isnotempty(ObservableValue)
      | summarize arg_max(TimeGenerated, *) by Id
      | where IsDeleted == false
      | where tostring(Data.revoked) != "true"
      | where isempty(ValidUntil) or ValidUntil > now()
      | where Confidence >= confidence_floor
      | extend IndicatorDomain = tolower(trim_end(@"\.", ObservableValue))
      | project
          IndicatorDomain,
          IndicatorStixId     = tostring(Data.id),
          IndicatorRecordId   = Id,
          DatazagAlertRef     = tostring(Data.external_references[0].external_id),
          Confidence,
          IndicatorEvidence   = tostring(Data.labels),
          IndicatorValidUntil = ValidUntil;
  let DnsActivity =
      _Im_Dns
      | where TimeGenerated >= ago(dns_lookback)
      | where isnotempty(DnsQuery)
      | extend IndicatorDomain = tolower(trim_end(@"\.", DnsQuery))
      | project
          DnsTime         = TimeGenerated,
          IndicatorDomain,
          DnsQuery,
          SrcIpAddr       = column_ifexists("SrcIpAddr", ""),
          SrcHostname     = column_ifexists("SrcHostname", ""),
          SrcUsername     = column_ifexists("SrcUsername", ""),
          SrcUsernameType = column_ifexists("SrcUsernameType", ""),
          EventVendor     = column_ifexists("EventVendor", ""),
          EventProduct    = column_ifexists("EventProduct", "");
  DatazagDomains
  | join kind=innerunique DnsActivity on IndicatorDomain
  | summarize
      FirstSeen   = min(DnsTime),
      LastSeen    = max(DnsTime),
      QueryCount  = count(),
      SourceIps   = make_set(SrcIpAddr, 50),
      SourceHosts = make_set(SrcHostname, 50),
      Upns        = make_set_if(SrcUsername, SrcUsernameType == "UPN", 50),
      SeenBy      = make_set(strcat(EventVendor, " ", EventProduct), 10)
      by
      IndicatorDomain, IndicatorStixId, IndicatorRecordId, DatazagAlertRef,
      Confidence, IndicatorEvidence, IndicatorValidUntil
  | extend
      SourceIp   = tostring(SourceIps[0]),
      SourceHost = tostring(SourceHosts[0]),
      AccountUpn = tostring(Upns[0])
  | order by LastSeen desc
queryFrequency: 1h
description: |
  Matches active Datazag impersonation indicators against DNS activity normalized by the ASIM
  Dns schema, so the rule works across any normalized DNS source without modification. A match
  means a host inside the estate resolved a domain Datazag scored as brand impersonation,
  platform impersonation or attacker infrastructure. Requires the ASIM DNS parsers.
id: 8f3c1a4e-6b52-4d19-9c07-2a5e8d0f7b41
triggerThreshold: 0
version: 1.0.0
queryPeriod: 14d
status: Available
kind: Scheduled
customDetails:
  ObservedBy: SeenBy
  DatazagIndicatorRef: IndicatorStixId
  ResolutionCount: QueryCount
  DatazagEvidence: IndicatorEvidence
  IndicatorExpiry: IndicatorValidUntil
  DatazagConfidence: Confidence
  DatazagAlertRef: DatazagAlertRef
relevantTechniques:
- T1566
- T1071
eventGroupingSettings:
  aggregationKind: AlertPerResult
severity: High
requiredDataConnectors:
- connectorId: ThreatIntelligenceTaxii
  dataTypes:
  - ThreatIntelIndicators
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Datazag/Analytic%20Rules/DatazagDomainIndicatorMatch_DNS.yaml
alertDetailsOverride:
  alertDescriptionFormat: |
    {{IndicatorDomain}} was resolved from inside the estate. Datazag scored this indicator
    at confidence {{Confidence}}. Supporting evidence: {{IndicatorEvidence}}
  alertDisplayNameFormat: 'Datazag: {{IndicatorDomain}} resolved from inside the estate'
tactics:
- InitialAccess
- CommandAndControl
entityMappings:
- fieldMappings:
  - identifier: DomainName
    columnName: IndicatorDomain
  entityType: DNS
- fieldMappings:
  - identifier: Address
    columnName: SourceIp
  entityType: IP
- fieldMappings:
  - identifier: HostName
    columnName: SourceHost
  entityType: Host
- fieldMappings:
  - identifier: FullName
    columnName: AccountUpn
  entityType: Account
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/8f3c1a4e-6b52-4d19-9c07-2a5e8d0f7b41')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/8f3c1a4e-6b52-4d19-9c07-2a5e8d0f7b41')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "{{IndicatorDomain}} was resolved from inside the estate. Datazag scored this indicator\nat confidence {{Confidence}}. Supporting evidence: {{IndicatorEvidence}}\n",
          "alertDisplayNameFormat": "Datazag: {{IndicatorDomain}} resolved from inside the estate"
        },
        "alertRuleTemplateName": "8f3c1a4e-6b52-4d19-9c07-2a5e8d0f7b41",
        "customDetails": {
          "DatazagAlertRef": "DatazagAlertRef",
          "DatazagConfidence": "Confidence",
          "DatazagEvidence": "IndicatorEvidence",
          "DatazagIndicatorRef": "IndicatorStixId",
          "IndicatorExpiry": "IndicatorValidUntil",
          "ObservedBy": "SeenBy",
          "ResolutionCount": "QueryCount"
        },
        "description": "Matches active Datazag impersonation indicators against DNS activity normalized by the ASIM\nDns schema, so the rule works across any normalized DNS source without modification. A match\nmeans a host inside the estate resolved a domain Datazag scored as brand impersonation,\nplatform impersonation or attacker infrastructure. Requires the ASIM DNS parsers.\n",
        "displayName": "Datazag - impersonation domain resolved in DNS",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "DNS",
            "fieldMappings": [
              {
                "columnName": "IndicatorDomain",
                "identifier": "DomainName"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SourceIp",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "Host",
            "fieldMappings": [
              {
                "columnName": "SourceHost",
                "identifier": "HostName"
              }
            ]
          },
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "AccountUpn",
                "identifier": "FullName"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "AlertPerResult"
        },
        "incidentConfiguration": {
          "createIncident": true,
          "groupingConfiguration": {
            "enabled": true,
            "groupByEntities": [
              "DNS"
            ],
            "lookbackDuration": "P1D",
            "matchingMethod": "Selected",
            "reopenClosedIncident": false
          }
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Datazag/Analytic%20Rules/DatazagDomainIndicatorMatch_DNS.yaml",
        "query": "let datazag_identity = \"identity--55a5a448-c6f1-5128-bc71-4d85b719131e\";\nlet ioc_lookback = 14d;\nlet dns_lookback = 1h;\nlet confidence_floor = 85;\nlet DatazagDomains =\n    ThreatIntelIndicators\n    | where TimeGenerated >= ago(ioc_lookback)\n    | where tostring(Data.created_by_ref) == datazag_identity\n    | where ObservableKey == \"domain-name:value\"\n    | where isnotempty(ObservableValue)\n    | summarize arg_max(TimeGenerated, *) by Id\n    | where IsDeleted == false\n    | where tostring(Data.revoked) != \"true\"\n    | where isempty(ValidUntil) or ValidUntil > now()\n    | where Confidence >= confidence_floor\n    | extend IndicatorDomain = tolower(trim_end(@\"\\.\", ObservableValue))\n    | project\n        IndicatorDomain,\n        IndicatorStixId     = tostring(Data.id),\n        IndicatorRecordId   = Id,\n        DatazagAlertRef     = tostring(Data.external_references[0].external_id),\n        Confidence,\n        IndicatorEvidence   = tostring(Data.labels),\n        IndicatorValidUntil = ValidUntil;\nlet DnsActivity =\n    _Im_Dns\n    | where TimeGenerated >= ago(dns_lookback)\n    | where isnotempty(DnsQuery)\n    | extend IndicatorDomain = tolower(trim_end(@\"\\.\", DnsQuery))\n    | project\n        DnsTime         = TimeGenerated,\n        IndicatorDomain,\n        DnsQuery,\n        SrcIpAddr       = column_ifexists(\"SrcIpAddr\", \"\"),\n        SrcHostname     = column_ifexists(\"SrcHostname\", \"\"),\n        SrcUsername     = column_ifexists(\"SrcUsername\", \"\"),\n        SrcUsernameType = column_ifexists(\"SrcUsernameType\", \"\"),\n        EventVendor     = column_ifexists(\"EventVendor\", \"\"),\n        EventProduct    = column_ifexists(\"EventProduct\", \"\");\nDatazagDomains\n| join kind=innerunique DnsActivity on IndicatorDomain\n| summarize\n    FirstSeen   = min(DnsTime),\n    LastSeen    = max(DnsTime),\n    QueryCount  = count(),\n    SourceIps   = make_set(SrcIpAddr, 50),\n    SourceHosts = make_set(SrcHostname, 50),\n    Upns        = make_set_if(SrcUsername, SrcUsernameType == \"UPN\", 50),\n    SeenBy      = make_set(strcat(EventVendor, \" \", EventProduct), 10)\n    by\n    IndicatorDomain, IndicatorStixId, IndicatorRecordId, DatazagAlertRef,\n    Confidence, IndicatorEvidence, IndicatorValidUntil\n| extend\n    SourceIp   = tostring(SourceIps[0]),\n    SourceHost = tostring(SourceHosts[0]),\n    AccountUpn = tostring(Upns[0])\n| order by LastSeen desc\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "High",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "CommandAndControl",
          "InitialAccess"
        ],
        "techniques": [
          "T1071",
          "T1566"
        ],
        "templateVersion": "1.0.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}