Attackers may be attempting to exploit phishing links embedded in emails to deliver malicious payloads or exfiltrate data. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential phishing campaigns and mitigate lateral movement or data compromise risks.
KQL Query
// Query for links opened from mail apps - if a detection occurred right afterwards. - MTP Schema
// As there are many links opened from mails, to have a successful hunt we should have some filter or join with some other signal,
// such as suspicious processes, network connections, etc.
// Therefore, in this example, we query for alerts that might be related to links sent via email.
// This could be indicative of a phishing or spear-phishing attacks.
// Tags: #EmailLink, #Phishing, #GetNearbyAlerts
// Explaining the underlying data:
// This query uses the BrowserLaunchedToOpenUrl event, that includes clicks on http:// or https:// links (clicks outside of browsers), or on .lnk files
// For this event, RemoteUrl contains the opened URL.
let minTimeRange = ago(7d);
let outlookLinks =
DeviceEvents
// Filter on click on links from outlook
| where Timestamp > minTimeRange and ActionType == "BrowserLaunchedToOpenUrl" and isnotempty(RemoteUrl)
| where
// outlook.exe is the Office Outlook app
InitiatingProcessFileName =~ "outlook.exe"
// RuntimeBroker.exe opens links for all apps from the Windows store, including the Windows Mail app (HxOutlook.exe).
// However, it will also include some links opened from other apps.
or InitiatingProcessFileName =~ "runtimebroker.exe"
| project Timestamp, DeviceId, DeviceName, RemoteUrl, InitiatingProcessFileName, ParsedUrl=parse_url(RemoteUrl)
// When applicable, parse the link sent via email from the clicked O365 ATP SafeLink
| extend WasOutlookSafeLink=(tostring(ParsedUrl.Host) endswith "safelinks.protection.outlook.com")
| project Timestamp, DeviceId, DeviceName, WasOutlookSafeLink, InitiatingProcessFileName,
OpenedLink=iff(WasOutlookSafeLink, url_decode(tostring(ParsedUrl["Query Parameters"]["url"])), RemoteUrl);
let alerts =
AlertInfo | join AlertEvidence on AlertId
| summarize (FirstDetectedActivity, Title)=argmin(Timestamp, Title) by AlertId, DeviceId
// Filter alerts that include events from before the queried time period
| where FirstDetectedActivity > minTimeRange;
// Join the two together - looking for alerts that are right after an abnormal network logon
alerts | join kind=inner (outlookLinks) on DeviceId | where FirstDetectedActivity - Timestamp between (0min..3min)
// If there are multiple alerts close to a single click-on-link, aggregate them together to a single row
// Note: bin(Timestamp, 1tick) is used because when summarizing by a datetime field, the default "bin" used is 1-hour.
| summarize FirstDetectedActivity=min(FirstDetectedActivity), AlertTitles=makeset(Title) by OpenedLink, InitiatingProcessFileName, Timestamp=bin(Timestamp, 1tick), DeviceName, DeviceId, WasOutlookSafeLink
id: 67be3fdd-6942-45f8-8663-d825b61d1ab9
name: Open email link
description: |
Query for links opened from mail apps - if a detection occurred right afterwards.
As there are many links opened from mails, to have a successful hunt we should have some filter or join with some other signal,.
Such as suspicious processes, network connections, etc.
Therefore, in this example, we query for alerts that might be related to links sent via email.
This could be indicative of a phishing or spear-phishing attacks.
Tags: #EmailLink, #Phishing, #GetNearbyAlerts.
Explaining the underlying data:.
This query uses the BrowserLaunchedToOpenUrl event, that includes clicks on http:// or https:// links (clicks outside of browsers), or on .lnk files.
For this event, RemoteUrl contains the opened URL.
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceEvents
- AlertInfo
- AlertEvidence
query: |
// Query for links opened from mail apps - if a detection occurred right afterwards. - MTP Schema
// As there are many links opened from mails, to have a successful hunt we should have some filter or join with some other signal,
// such as suspicious processes, network connections, etc.
// Therefore, in this example, we query for alerts that might be related to links sent via email.
// This could be indicative of a phishing or spear-phishing attacks.
// Tags: #EmailLink, #Phishing, #GetNearbyAlerts
// Explaining the underlying data:
// This query uses the BrowserLaunchedToOpenUrl event, that includes clicks on http:// or https:// links (clicks outside of browsers), or on .lnk files
// For this event, RemoteUrl contains the opened URL.
let minTimeRange = ago(7d);
let outlookLinks =
DeviceEvents
// Filter on click on links from outlook
| where Timestamp > minTimeRange and ActionType == "BrowserLaunchedToOpenUrl" and isnotempty(RemoteUrl)
| where
// outlook.exe is the Office Outlook app
InitiatingProcessFileName =~ "outlook.exe"
// RuntimeBroker.exe opens links for all apps from the Windows store, including the Windows Mail app (HxOutlook.exe).
// However, it will also include some links opened from other apps.
or InitiatingProcessFileName =~ "runtimebroker.exe"
| project Timestamp, DeviceId, DeviceName, RemoteUrl, InitiatingProcessFileName, ParsedUrl=parse_url(RemoteUrl)
// When applicable, parse the link sent via email from the clicked O365 ATP SafeLink
| extend WasOutlookSafeLink=(tostring(ParsedUrl.Host) endswith "safelinks.protection.outlook.com")
| project Timestamp, DeviceId, DeviceName, WasOutlookSafeLink, InitiatingProcessFileName,
OpenedLink=iff(WasOutlookSafeLink, url_decode(tostring(ParsedUrl["Query Parameters"]["url"])), RemoteUrl);
let alerts =
AlertInfo | join AlertEvidence on AlertId
| summarize (FirstDetectedActivity, Title)=argmin(Timestamp, Title) by AlertId, DeviceId
| Sentinel Table | Notes |
|---|---|
AlertEvidence | Ensure this data connector is enabled |
DeviceEvents | Ensure this data connector is enabled |
Scenario: User clicks on a legitimate marketing link in an email
Description: A user receives a marketing email with a link to a product page or landing site and clicks on it.
Filter/Exclusion: Exclude links from known marketing domains (e.g., example.com, marketing-site.com) using a domain allowlist in the email security tool (e.g., Microsoft Defender for Office 365, Cisco Secure Email Gateway).
Scenario: Scheduled job or automation opens a link for data processing
Description: A scheduled task or automation script (e.g., a Power Automate flow or Python script) opens a link to fetch or process data from an external service.
Filter/Exclusion: Exclude links accessed by system accounts or service accounts (e.g., [email protected]) using user account filtering in the SIEM or endpoint detection tool.
Scenario: Admin opens a link for system maintenance or patching
Description: An admin opens a link to a patch download or configuration tool (e.g., from Microsoft Update, VMware vSphere Update Manager) as part of routine maintenance.
Filter/Exclusion: Exclude links from known admin or maintenance domains using a domain blocklist or IP allowlist in the email gateway or endpoint protection system.
Scenario: User opens a link from a shared calendar event
Description: A user opens a link to a shared calendar event (e.g., from Outlook or Google Calendar) that includes a link to a meeting or resource.
Filter/Exclusion: Exclude links originating from calendar applications using application context filtering in the email security tool (e.g., Microsoft 365 Defender, Google Workspace Security).
Scenario: Link opened during a phishing simulation exercise