A threat actor may be using a Word document to host a malicious link that triggers a browser download, potentially leading to code execution or data exfiltration. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify and mitigate early-stage phishing or document-based attack campaigns.
KQL Query
let minTimeRange = ago(7d);
let wordLinks =
DeviceEvents
// Filter on click on links from WinWord
| where Timestamp > minTimeRange and ActionType == "BrowserLaunchedToOpenUrl" and isnotempty(RemoteUrl) and InitiatingProcessFileName =~ "winword.exe"
| project ClickTime=Timestamp, DeviceId, DeviceName, ClickUrl=RemoteUrl;
let docAttachments =
DeviceFileEvents
| where Timestamp > minTimeRange
// Query for common document file extensions
and (FileName endswith ".docx" or FileName endswith ".docm" or FileName endswith ".doc")
// Query for files saved from email clients such as the Office Outlook app or the Windows Mail app
and InitiatingProcessFileName in~ ("outlook.exe", "hxoutlook.exe")
| summarize AttachmentSaveTime=min(Timestamp) by AttachmentName=FileName, DeviceId;
let browserDownloads =
DeviceFileEvents
| where Timestamp > minTimeRange
// Query for files created by common browsers
and InitiatingProcessFileName in~ ("browser_broker.exe", "chrome.exe", "iexplore.exe", "firefox.exe")
// Exclude JS files that are used for loading sites (but still query for JS files that are known to be downloaded)
and not (FileName endswith ".js" and isempty(FileOriginUrl))
// Further filter to exclude file extensions that are less indicative of an attack (when there were already previously a doc attachment that included a link)
| where FileName !endswith ".partial" and FileName !endswith ".docx"
| summarize (Timestamp, SHA1) = argmax(Timestamp, SHA1) by FileName, DeviceId, FileOriginUrl;
// Perf tip: start the joins from the smallest table (put it on the left-most side of the joins)
wordLinks
| join kind= inner (docAttachments) on DeviceId | where ClickTime - AttachmentSaveTime between (0min..3min)
| join kind= inner (browserDownloads) on DeviceId | where Timestamp - ClickTime between (0min..3min)
// Aggregating multiple "attachments" together - because oftentimes the same file is stored multiple times under different names
| summarize Attachments=makeset(AttachmentName), AttachmentSaveTime=min(AttachmentSaveTime), ClickTime=min(ClickTime)
by // Downloaded file details
bin(Timestamp, 1tick), FileName, FileOriginUrl, ClickUrl, SHA1, DeviceName, DeviceId
id: cf259a7a-801a-435a-af3f-3ef998561145
name: Doc attachment with link to download
description: |
This query looks for a Word document attachment, from which a link was clicked, and after which there was a browser download.
This query is not noisy, but most of its results are clean.
It can also hserve as reference for other queries on email attachments, on browser downloads or for queries that join multiple events by time.
Tags: #EmailAttachment, #WordLink, #BrowserDownload, #Phishing, #DedupFileCreate.
Implementation comment #1: Matching events by time.
Matching the 3 different events (saving attachment, clicking on link, downloading file) is done purely by time difference - so could sometimes link together unrelated events.
Doing a more exact lookup would create a much more complex query due to.
Implementation comment #2: Deduping DeviceFileEvents.
Oftentimes there are multiple DeviceFileEvents for a single file - e.g. if the file keeps being appended into before being closed.
So, we query only for the last reported file state to ignore intermediate file states.
Explaining the underlying data:.
BrowserLaunchedToOpenUrl event:.
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
- DeviceFileEvents
query: |
let minTimeRange = ago(7d);
let wordLinks =
DeviceEvents
// Filter on click on links from WinWord
| where Timestamp > minTimeRange and ActionType == "BrowserLaunchedToOpenUrl" and isnotempty(RemoteUrl) and InitiatingProcessFileName =~ "winword.exe"
| project ClickTime=Timestamp, DeviceId, DeviceName, ClickUrl=RemoteUrl;
let docAttachments =
DeviceFileEvents
| where Timestamp > minTimeRange
// Query for common document file extensions
and (FileName endswith ".docx" or FileName endswith ".docm" or FileName endswith ".doc")
// Query for files saved from email clients such as the Office Outlook app or the Windows Mail app
and InitiatingProcessFileName in~ ("outlook.exe", "hxoutlook.exe")
| summarize AttachmentSaveTime=min(Timestamp) by AttachmentName=FileName, DeviceId;
let browserDownloads =
DeviceFileEvents
| where Timestamp > minTimeRange
// Query for files created by common browsers
and InitiatingProcessFileName in~ ("browser_broker.exe", "chrome.exe", "iexplore.exe", "firefox.exe")
// Exclude JS files that are used for loading sites (but still query for JS files that are known to be downloaded)
and not (FileName endswith ".js" and isempty(FileOriginUrl))
// Further filter to exclude file extensions that are less indicative of an attack (when there were already previously a doc attachment that included a link)
|
| Sentinel Table | Notes |
|---|---|
DeviceEvents | Ensure this data connector is enabled |
DeviceFileEvents | Ensure this data connector is enabled |
Scenario: Scheduled Report Generation with Embedded Links
Description: A scheduled job runs a script that generates a Word document containing a link to a downloadable file (e.g., a CSV or PDF), which is then automatically clicked and downloaded by a system user.
Filter/Exclusion: Exclude events where the link is part of a known scheduled report generation process (e.g., report_generator.exe or Power BI scheduled tasks) and the download occurs within a predefined time window (e.g., 8:00 AM - 9:00 AM).
Scenario: Admin Task to Download Configuration Files
Description: An administrator uses a tool like PowerShell or Ansible to download configuration files from a shared drive or internal server, which are then embedded in a Word document and clicked as part of a configuration update process.
Filter/Exclusion: Exclude events where the user is a domain admin or has a specific group membership (e.g., Domain Admins) and the download occurs from a known internal server or shared drive (e.g., \\fileserver\config).
Scenario: User-Generated Document with External Link
Description: A user creates a Word document (e.g., using Microsoft Word) that includes a link to an internal file share or a public website, which is clicked and downloaded as part of normal documentation.
Filter/Exclusion: Exclude events where the user is a regular employee and the link is to a known internal resource (e.g., \\internal-share\docs or https://intranet.example.com).
Scenario: Automated Testing with Document Attachments
Description: A test automation tool (e.g., Selenium, Postman, or Jenkins) generates a Word document with a link to a test file, clicks the link, and downloads the file