Analytic rule catalog
Red Sift - Email with URL to previously unseen domain
Back
| Id | 8972b513-12a2-4b46-8263-3f091d88a8bc |
| Rulename | Red Sift - Email with URL to previously unseen domain |
| 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. |
| Severity | Medium |
| Tactics | InitialAccess |
| Techniques | T1566 |
| Required data connectors | RedSiftPush |
| Kind | Scheduled |
| Query frequency | 1h |
| Query period | 14d |
| Trigger threshold | 0 |
| Trigger operator | gt |
| Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Red%20Sift/Analytic%20Rules/RedSiftEmailUrlWithNewDomain.yaml |
| Version | 1.0.0 |
| Arm template | 8972b513-12a2-4b46-8263-3f091d88a8bc.json |
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
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: EmailFrom
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIp
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: RepresentativeUrlDomain
name: Red Sift - Email with URL to previously unseen domain
kind: Scheduled
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Red%20Sift/Analytic%20Rules/RedSiftEmailUrlWithNewDomain.yaml
triggerOperator: gt
status: Available
suppressionDuration: PT1H
queryPeriod: 14d
requiredDataConnectors:
- connectorId: RedSiftPush
dataTypes:
- RedSiftEmailForensics_CL
tactics:
- InitialAccess
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
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.'
severity: Medium
incidentConfiguration:
groupingConfiguration:
lookbackDuration: P1D
groupByCustomDetails:
- EmailSubject
groupByEntities:
- Account
- DNS
enabled: true
matchingMethod: Selected
reopenClosedIncident: false
createIncident: true
id: 8972b513-12a2-4b46-8263-3f091d88a8bc
customDetails:
ReturnPath: EmailReturnPath
CorrelationUid: CorrelationUid
EmailSubject: EmailSubject
NewUrlDomainList: NewUrlDomainList
NewDomainCount: NewDomainCount
NewUrlList: NewUrlList
suppressionEnabled: false
triggerThreshold: 0
queryFrequency: 1h
eventGroupingSettings:
aggregationKind: AlertPerResult
alertDetailsOverride:
alertDescriptionFormat: 'Email from {{EmailFrom}} contains {{NewDomainCount}} previously unseen URL domain(s): {{NewUrlDomainList}}.'
alertDisplayNameFormat: RedSift - URL to new domain in email from {{EmailFrom}}
version: 1.0.0
relevantTechniques:
- T1566
{
"$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"
}
]
}