Back
Id8972b513-12a2-4b46-8263-3f091d88a8bc
RulenameRed Sift - Email with URL to previously unseen domain
DescriptionDetects email forensics events containing one or more URLs whose domain has not been seen in the previous 14 days, which may indicate newly observed phishing infrastructure or suspicious delivery patterns.
SeverityMedium
TacticsInitialAccess
TechniquesT1566
Required data connectorsRedSiftPush
KindScheduled
Query frequency1h
Query period14d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Red%20Sift/Analytic%20Rules/RedSiftEmailUrlWithNewDomain.yaml
Version1.0.0
Arm template8972b513-12a2-4b46-8263-3f091d88a8bc.json
Deploy To Azure
let lookback = 14d;
let recentWindow = 1h;
let historicalDomains = RedSiftEmailForensics_CL
| extend EmailUrls = todynamic(EmailUrls)
| where TimeGenerated between (ago(lookback) .. ago(recentWindow))
| where isnotempty(EmailUrls) and array_length(EmailUrls) > 0
| mv-expand Url = EmailUrls
| extend UrlString = tostring(Url.url_string)
| where isnotempty(UrlString)
| extend UrlDomain = tostring(parse_url(UrlString).Host)
| where isnotempty(UrlDomain)
| summarize by UrlDomain;
RedSiftEmailForensics_CL
| extend
    EmailFrom = tostring(column_ifexists("EmailFrom", "")),
    EmailSubject = tostring(column_ifexists("EmailSubject", "")),
    EmailReturnPath = tostring(column_ifexists("EmailReturnPath", "")),
    EmailMessageUid = tostring(column_ifexists("EmailMessageUid", "")),
    SrcIp = tostring(column_ifexists("SrcIp", "")),
    DstHostname = tostring(column_ifexists("DstHostname", "")),
    Severity = tostring(column_ifexists("Severity", "")),
    Message = tostring(column_ifexists("Message", "")),
    CorrelationUid = tostring(column_ifexists("CorrelationUid", "")),
    EmailUrls = todynamic(EmailUrls)
| where TimeGenerated >= ago(recentWindow)
| where isnotempty(EmailUrls) and array_length(EmailUrls) > 0
| mv-expand Url = EmailUrls
| extend UrlString = tostring(Url.url_string)
| where isnotempty(UrlString)
| extend UrlDomain = tostring(parse_url(UrlString).Host)
| where isnotempty(UrlDomain)
| join kind=leftanti (historicalDomains) on UrlDomain
| summarize
    NewUrlDomains = make_set(UrlDomain, 50),
    NewUrls = make_set(UrlString, 50),
    NewDomainCount = dcount(UrlDomain),
    UrlCount = dcount(UrlString),
    RepresentativeUrlDomain = take_any(UrlDomain)
    by TimeGenerated,
    EmailFrom,
    EmailSubject,
    EmailReturnPath,
    EmailMessageUid,
    SrcIp,
    DstHostname,
    Severity,
    Message,
    CorrelationUid
| extend
    NewUrlDomainList = strcat_array(NewUrlDomains, ", "),
    NewUrlList = strcat_array(NewUrls, ", ")
| project
    TimeGenerated,
    EmailFrom,
    EmailSubject,
    EmailReturnPath,
    EmailMessageUid,
    SrcIp,
    DstHostname,
    RepresentativeUrlDomain,
    NewDomainCount,
    UrlCount,
    NewUrlDomainList,
    NewUrlList,
    Severity,
    Message,
    CorrelationUid
incidentConfiguration:
  groupingConfiguration:
    groupByCustomDetails:
    - EmailSubject
    lookbackDuration: P1D
    enabled: true
    reopenClosedIncident: false
    matchingMethod: Selected
    groupByEntities:
    - Account
    - DNS
  createIncident: true
name: Red Sift - Email with URL to previously unseen domain
suppressionDuration: PT1H
suppressionEnabled: false
triggerOperator: gt
query: |
  let lookback = 14d;
  let recentWindow = 1h;
  let historicalDomains = RedSiftEmailForensics_CL
  | extend EmailUrls = todynamic(EmailUrls)
  | where TimeGenerated between (ago(lookback) .. ago(recentWindow))
  | where isnotempty(EmailUrls) and array_length(EmailUrls) > 0
  | mv-expand Url = EmailUrls
  | extend UrlString = tostring(Url.url_string)
  | where isnotempty(UrlString)
  | extend UrlDomain = tostring(parse_url(UrlString).Host)
  | where isnotempty(UrlDomain)
  | summarize by UrlDomain;
  RedSiftEmailForensics_CL
  | extend
      EmailFrom = tostring(column_ifexists("EmailFrom", "")),
      EmailSubject = tostring(column_ifexists("EmailSubject", "")),
      EmailReturnPath = tostring(column_ifexists("EmailReturnPath", "")),
      EmailMessageUid = tostring(column_ifexists("EmailMessageUid", "")),
      SrcIp = tostring(column_ifexists("SrcIp", "")),
      DstHostname = tostring(column_ifexists("DstHostname", "")),
      Severity = tostring(column_ifexists("Severity", "")),
      Message = tostring(column_ifexists("Message", "")),
      CorrelationUid = tostring(column_ifexists("CorrelationUid", "")),
      EmailUrls = todynamic(EmailUrls)
  | where TimeGenerated >= ago(recentWindow)
  | where isnotempty(EmailUrls) and array_length(EmailUrls) > 0
  | mv-expand Url = EmailUrls
  | extend UrlString = tostring(Url.url_string)
  | where isnotempty(UrlString)
  | extend UrlDomain = tostring(parse_url(UrlString).Host)
  | where isnotempty(UrlDomain)
  | join kind=leftanti (historicalDomains) on UrlDomain
  | summarize
      NewUrlDomains = make_set(UrlDomain, 50),
      NewUrls = make_set(UrlString, 50),
      NewDomainCount = dcount(UrlDomain),
      UrlCount = dcount(UrlString),
      RepresentativeUrlDomain = take_any(UrlDomain)
      by TimeGenerated,
      EmailFrom,
      EmailSubject,
      EmailReturnPath,
      EmailMessageUid,
      SrcIp,
      DstHostname,
      Severity,
      Message,
      CorrelationUid
  | extend
      NewUrlDomainList = strcat_array(NewUrlDomains, ", "),
      NewUrlList = strcat_array(NewUrls, ", ")
  | project
      TimeGenerated,
      EmailFrom,
      EmailSubject,
      EmailReturnPath,
      EmailMessageUid,
      SrcIp,
      DstHostname,
      RepresentativeUrlDomain,
      NewDomainCount,
      UrlCount,
      NewUrlDomainList,
      NewUrlList,
      Severity,
      Message,
      CorrelationUid
queryFrequency: 1h
description: |
  'Detects email forensics events containing one or more URLs whose domain has not been seen in the previous 14 days, which may indicate newly observed phishing infrastructure or suspicious delivery patterns.'
id: 8972b513-12a2-4b46-8263-3f091d88a8bc
triggerThreshold: 0
queryPeriod: 14d
version: 1.0.0
kind: Scheduled
customDetails:
  CorrelationUid: CorrelationUid
  ReturnPath: EmailReturnPath
  NewUrlDomainList: NewUrlDomainList
  NewUrlList: NewUrlList
  EmailSubject: EmailSubject
  NewDomainCount: NewDomainCount
status: Available
eventGroupingSettings:
  aggregationKind: AlertPerResult
severity: Medium
requiredDataConnectors:
- connectorId: RedSiftPush
  dataTypes:
  - RedSiftEmailForensics_CL
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Red%20Sift/Analytic%20Rules/RedSiftEmailUrlWithNewDomain.yaml
alertDetailsOverride:
  alertDescriptionFormat: 'Email from {{EmailFrom}} contains {{NewDomainCount}} previously unseen URL domain(s): {{NewUrlDomainList}}.'
  alertDisplayNameFormat: RedSift - URL to new domain in email from {{EmailFrom}}
relevantTechniques:
- T1566
tactics:
- InitialAccess
entityMappings:
- fieldMappings:
  - identifier: FullName
    columnName: EmailFrom
  entityType: Account
- fieldMappings:
  - identifier: Address
    columnName: SrcIp
  entityType: IP
- fieldMappings:
  - identifier: DomainName
    columnName: RepresentativeUrlDomain
  entityType: DNS
{
  "$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/8972b513-12a2-4b46-8263-3f091d88a8bc')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/8972b513-12a2-4b46-8263-3f091d88a8bc')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "Email from {{EmailFrom}} contains {{NewDomainCount}} previously unseen URL domain(s): {{NewUrlDomainList}}.",
          "alertDisplayNameFormat": "RedSift - URL to new domain in email from {{EmailFrom}}"
        },
        "alertRuleTemplateName": "8972b513-12a2-4b46-8263-3f091d88a8bc",
        "customDetails": {
          "CorrelationUid": "CorrelationUid",
          "EmailSubject": "EmailSubject",
          "NewDomainCount": "NewDomainCount",
          "NewUrlDomainList": "NewUrlDomainList",
          "NewUrlList": "NewUrlList",
          "ReturnPath": "EmailReturnPath"
        },
        "description": "'Detects email forensics events containing one or more URLs whose domain has not been seen in the previous 14 days, which may indicate newly observed phishing infrastructure or suspicious delivery patterns.'\n",
        "displayName": "Red Sift - Email with URL to previously unseen domain",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "EmailFrom",
                "identifier": "FullName"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "SrcIp",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "DNS",
            "fieldMappings": [
              {
                "columnName": "RepresentativeUrlDomain",
                "identifier": "DomainName"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "AlertPerResult"
        },
        "incidentConfiguration": {
          "createIncident": true,
          "groupingConfiguration": {
            "enabled": true,
            "groupByCustomDetails": [
              "EmailSubject"
            ],
            "groupByEntities": [
              "Account",
              "DNS"
            ],
            "lookbackDuration": "P1D",
            "matchingMethod": "Selected",
            "reopenClosedIncident": false
          }
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Red%20Sift/Analytic%20Rules/RedSiftEmailUrlWithNewDomain.yaml",
        "query": "let lookback = 14d;\nlet recentWindow = 1h;\nlet historicalDomains = RedSiftEmailForensics_CL\n| extend EmailUrls = todynamic(EmailUrls)\n| where TimeGenerated between (ago(lookback) .. ago(recentWindow))\n| where isnotempty(EmailUrls) and array_length(EmailUrls) > 0\n| mv-expand Url = EmailUrls\n| extend UrlString = tostring(Url.url_string)\n| where isnotempty(UrlString)\n| extend UrlDomain = tostring(parse_url(UrlString).Host)\n| where isnotempty(UrlDomain)\n| summarize by UrlDomain;\nRedSiftEmailForensics_CL\n| extend\n    EmailFrom = tostring(column_ifexists(\"EmailFrom\", \"\")),\n    EmailSubject = tostring(column_ifexists(\"EmailSubject\", \"\")),\n    EmailReturnPath = tostring(column_ifexists(\"EmailReturnPath\", \"\")),\n    EmailMessageUid = tostring(column_ifexists(\"EmailMessageUid\", \"\")),\n    SrcIp = tostring(column_ifexists(\"SrcIp\", \"\")),\n    DstHostname = tostring(column_ifexists(\"DstHostname\", \"\")),\n    Severity = tostring(column_ifexists(\"Severity\", \"\")),\n    Message = tostring(column_ifexists(\"Message\", \"\")),\n    CorrelationUid = tostring(column_ifexists(\"CorrelationUid\", \"\")),\n    EmailUrls = todynamic(EmailUrls)\n| where TimeGenerated >= ago(recentWindow)\n| where isnotempty(EmailUrls) and array_length(EmailUrls) > 0\n| mv-expand Url = EmailUrls\n| extend UrlString = tostring(Url.url_string)\n| where isnotempty(UrlString)\n| extend UrlDomain = tostring(parse_url(UrlString).Host)\n| where isnotempty(UrlDomain)\n| join kind=leftanti (historicalDomains) on UrlDomain\n| summarize\n    NewUrlDomains = make_set(UrlDomain, 50),\n    NewUrls = make_set(UrlString, 50),\n    NewDomainCount = dcount(UrlDomain),\n    UrlCount = dcount(UrlString),\n    RepresentativeUrlDomain = take_any(UrlDomain)\n    by TimeGenerated,\n    EmailFrom,\n    EmailSubject,\n    EmailReturnPath,\n    EmailMessageUid,\n    SrcIp,\n    DstHostname,\n    Severity,\n    Message,\n    CorrelationUid\n| extend\n    NewUrlDomainList = strcat_array(NewUrlDomains, \", \"),\n    NewUrlList = strcat_array(NewUrls, \", \")\n| project\n    TimeGenerated,\n    EmailFrom,\n    EmailSubject,\n    EmailReturnPath,\n    EmailMessageUid,\n    SrcIp,\n    DstHostname,\n    RepresentativeUrlDomain,\n    NewDomainCount,\n    UrlCount,\n    NewUrlDomainList,\n    NewUrlList,\n    Severity,\n    Message,\n    CorrelationUid\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "Medium",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "InitialAccess"
        ],
        "techniques": [
          "T1566"
        ],
        "templateVersion": "1.0.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}