↳ GitHub sourceAnalytics ruleMedium

TI map Domain entity to SecurityAlert

Description

'Identifies a match in SecurityAlert table from any Domain IOC from TI'
Rule type
Scheduled
Version
1.4.4
Query frequency
1h
Query period
14d
Trigger
gt 0

Declared MITRE coverage

Declared sources

Metadata from the source file. No dependencies inferred from KQL.

Connectors

Data types

KQL query

Original query, unchanged.

let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let SecurityAlerts = SecurityAlert
| where TimeGenerated > ago(dt_lookBack)
| where AlertName != "TI map Domain entity to SecurityAlert"
| extend domain = todynamic(dynamic_to_json(extract_all(@"(((xn--)?[a-z0-9\-]+\.)+([a-z]+|(xn--[a-z0-9]+)))", dynamic([1]), tolower(Entities))))
| where isnotempty(domain)
| mv-expand domain
| extend domain = tostring(domain)
| extend EntitiesDynamicArray = parse_json(Entities)
| mv-apply EntitiesDynamicArray on
    (summarize
        HostName = take_anyif(tostring(EntitiesDynamicArray.HostName), EntitiesDynamicArray.Type == "host"),
        IP_addr = take_anyif(tostring(EntitiesDynamicArray.Address), EntitiesDynamicArray.Type == "ip")
    )
| extend Alert_TimeGenerated = TimeGenerated
| extend Alert_Description = Description;
let AlertDomains = SecurityAlerts
| distinct domain
| summarize make_list(domain);
let Domain_Indicators = materialize(ThreatIntelligenceIndicator
| where isnotempty(DomainName)
| where TimeGenerated >= ago(ioc_lookBack)
| extend TI_DomainEntity = tolower(DomainName)
| where TI_DomainEntity in (AlertDomains)
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| where Active == true and ExpirationDateTime > now()
| where Description !contains_cs "State: inactive;" and Description !contains_cs "State: falsepos;");
Domain_Indicators
// Using innerunique to keep performance fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated
| join kind=innerunique (SecurityAlerts) on $left.TI_DomainEntity == $right.domain
| where Alert_TimeGenerated < ExpirationDateTime
| summarize Alert_TimeGenerated = arg_max(Alert_TimeGenerated, *) by IndicatorId, AlertName
| project Alert_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, ExpirationDateTime, ConfidenceScore, DomainName, AlertName, Alert_Description, ProviderName, AlertSeverity, ConfidenceLevel, HostName, IP_addr, Url, Entities, Type, TI_DomainEntity
| extend timestamp = Alert_TimeGenerated

Declared entities

HostIPURL

Related content

Links established from declared identifiers and solution manifests.

Source provenance

GitHub

Displayed values come from files in Azure/Azure-Sentinel. They describe the published template, not your workspace configuration.

Source identifier
87890d78-3e05-43ec-9ab9-ba32f4e01250
Additional source files 3Solutions/Threat Intelligence/Analytic Rules/DomainEntity_SecurityAlert.yamlsource ↗Detections/ThreatIntelligenceIndicator/DomainEntity_SecurityAlert.yamlmigration-note ↗Solutions/Threat Intelligence/Data/Solution_ThreatIntelligenceTemplateSpec.jsonsolution-membership ↗
GSTEP / CATALOG TRACKING

Added to catalog : 16 Sept 2026 · 05:49 UTC
Last change observed : 16 Sept 2026 · 05:49 UTC

GSTEP sync dates, separate from the source content’s publication dates.