SOP-94: Malicious Office Macro / Document Execution Response | CyberHawk Threat Intel

·

Malicious Office documents remain one of the most common initial-access vectors a SOC will ever triage. A user opens a Word, Excel, PowerPoint or Outlook attachment, is social-engineered into clicking Enable Content or Enable Editing, and an embedded VBA macro, XLM (Excel 4.0) macro, DDE field or exploit payload spawns a scripting interpreter to download and run the next stage. The single most reliable signal of this attack is a parent-child process anomaly: an Office application (WINWORD.EXE, EXCEL.EXE, POWERPNT.EXE, OUTLOOK.EXE, MSPUB.EXE, MSACCESS.EXE) launching a child process it has no legitimate reason to launch — cmd.exe, powershell.exe, mshta.exe, wscript.exe, cscript.exe, rundll32.exe, regsvr32.exe, certutil.exe or bitsadmin.exe.

Because Microsoft now blocks VBA macros from internet-sourced files by default, adversaries have shifted delivery to container formats that strip the Mark-of-the-Web (ISO, IMG, ZIP, 7z), OneNote embedded scripts, LNK droppers and HTML smuggling — but the on-endpoint execution footprint is identical: Office (or its handler) spawns a script host, writes a payload to disk, and beacons out. This SOP treats any confirmed Office-spawns-script-host chain with a network callout as a SEV1 active-intrusion event — it is the loader stage for infostealers, Cobalt Strike, QakBot-class banking trojans and ransomware precursors.

Key data sources: DeviceProcessEvents (Office parent → script-host child), DeviceFileEvents (payload written to %Temp%, %AppData%, Startup, ProgramData), DeviceNetworkEvents (macro/child C2 callout), DeviceRegistryEvents (Office template / add-in persistence), and EmailEvents / EmailAttachmentInfo (delivery correlation).

☰ Table of Contents

01 Background 02 Identification 03 Containment 04 Eradication 05 Escalation
🛠

01 — BACKGROUND

TECHNIQUE OVERVIEW
01
Technique Overview — Malicious Document Execution
MITRE T1204.002

Weaponised documents deliver code execution by riding a trusted, whitelisted application. The user is the exploit trigger: they open the attachment, the lure convinces them to enable active content, and the document's macro/script/exploit reaches out to a scripting interpreter. That interpreter downloads a second-stage loader, which stages the real payload — an infostealer, a remote access trojan, or a ransomware affiliate's beacon. The document itself is almost always disposable; its only job is to run one command line. That command line, and the process that spawned it, are what the SOC hunts.

FieldValue
MITRE TechniquesT1566.001 — Phishing: Spearphishing Attachment
T1204.002 — User Execution: Malicious File
T1059 — Command & Scripting Interpreter (.001 PowerShell, .003 cmd, .005 VBScript, .007 JavaScript)
T1137 — Office Application Startup (.001 template, .006 add-ins)
T1218.005 mshta / T1218.010 regsvr32 / T1218.011 rundll32 — System Binary Proxy Execution
T1027.006 — HTML Smuggling · T1553.005 — Mark-of-the-Web Bypass
Kill-chain PhaseInitial Access → Execution → Defense Evasion → Command & Control
Primary Log SourceDeviceProcessEvents (parent-child), DeviceFileEvents (drop), DeviceNetworkEvents (C2)
Secondary Log SourcesDeviceRegistryEvents (template/add-in persistence), EmailEvents / EmailAttachmentInfo (delivery), SecurityEvent 4688 (process create w/ command line), Sysmon Event 1/11/22
Common Child Processespowershell.exe, cmd.exe, mshta.exe, wscript.exe, cscript.exe, rundll32.exe, regsvr32.exe, certutil.exe, bitsadmin.exe, curl.exe, msiexec.exe, cmstp.exe
Default SeveritySEV1 if Office spawns a script host and a network callout / drop follows; SEV2 if spawn only, no callout confirmed
Detection WindowQuery last 1 hour on alert; extend to 7 days for retro-hunting a new IOC

An Office application launching PowerShell, mshta, wscript or cmd is NEVER normal user behaviour. Office never needs a shell to open a document. Treat every unticket Office-spawns-interpreter event as hands-on-keyboard until proven otherwise — this is the loader stage, and the real payload lands seconds later.

02
Attack Paths, Business Impact & Severity Model
CONTEXT

A confirmed malicious-document execution is a live foothold on a corporate endpoint. Depending on the payload it becomes credential theft (browser cookie/token stealers — pivot SOP-83), a Cobalt Strike / loader beacon (pivot SOP-09 C2 beaconing), lateral movement (pivot SOP-06), or the opening move of a ransomware affiliate intrusion (pivot SOP-70). The five attack paths a SOC actually sees:

  • A1VBA / XLM macro loader. User enables content in a .docm/.xlsm/.xls; the macro shells out to PowerShell or mshta to pull stage 2. Classic QakBot / Emotet-style delivery.
  • A2Container-delivered (MotW bypass). The document arrives inside an ISO/IMG/ZIP/7z or a OneNote (.one) file so it never gets Mark-of-the-Web, defeating the default macro block. Payload is a LNK, HTA, VBS or JS that Office/Explorer executes.
  • A3DDE / field-code execution. No VBA at all — a DDEAUTO field or embedded OLE object launches cmd/PowerShell when the doc updates fields.
  • A4Document-based exploit. A crafted RTF/Office file triggers a memory-corruption or template-injection flaw (e.g. remote-template fetch over HTTP) to run code without user macro consent.
  • A5Office persistence. Post-exec the actor writes a malicious Normal.dotm / XLSTART template, a WLL/XLL add-in, or an Outlook VbaProject.OTM so the payload re-runs on every Office launch (T1137).
SeveritySignal
SEV1 / CRITICALOffice spawns script host AND (outbound C2 callout OR payload dropped & executed OR the same chain seen on multiple endpoints OR a privileged/VIP user)
SEV2 / HIGHOffice spawns script host, command line shows download/encoded intent, but callout not yet confirmed (query still running / blocked at proxy)
SEV3 / MEDIUMSuspicious macro-enabled attachment delivered & opened, but no child-process spawn observed (macro blocked / user did not enable content)
INFO / FPEnterprise-signed macro from a trusted publisher, or Office add-in from a documented business application, matching a change/allow-list entry

Speed matters more here than in almost any other alert. The gap between "macro spawned PowerShell" and "beacon established + credentials stolen" is often under 60 seconds. If the process-tree is confirmed, isolate first and finish the forensics after — do not sit on it to reach 100% certainty.

🔍

02 — IDENTIFICATION

6 INDICATORS + TRIAGE
▶ Investigation Workflow
T0
Alert Triage Checklist
FIRST 5 MINUTES
WHY CHECK

Five yes/no questions decide whether this jumps the queue. Any single YES on Q1–Q4 means confirmed execution — do not queue it, work it live.

  • 1Is the parent process an Office binary (WINWORD/EXCEL/POWERPNT/OUTLOOK/MSPUB/MSACCESS) and the child a script host / LOLBin? (YES → confirmed spawn, continue at I1)
  • 2Does the child command line show download, -enc/-EncodedCommand, IEX, DownloadString, -w hidden, bypass, or a URL? (YES → weaponised intent)
  • 3Was a file dropped to %Temp%, %AppData%, ProgramData or a Startup folder by that chain? (YES → stage 2 on disk, go to I2)
  • 4Is there an outbound network connection from the Office process or its child to an external IP/domain? (YES → live C2, go to I3, isolate)
  • 5Is the affected user a privileged / VIP / finance account, or is the same chain seen on more than one endpoint? (YES → raise severity, page L2)

If Q1 is YES, the clock has already started. Begin isolation preparation in parallel with the remaining queries — do not run all six indicators to completion before acting. Confirmed process-tree beats query completeness.

I1
Office Application Spawns a Script Host
MANUAL + KQL
WHY CHECK

This is the single defining signal. A Word/Excel/PowerPoint/Outlook process has no legitimate reason to launch a command interpreter or a system-binary proxy. Any such parent-child edge, absent a signed enterprise macro, is macro/document code execution in progress.

📍 Portal Navigation — Microsoft Defender XDR
security.microsoft.com› Hunting› Advanced Hunting
  • 1Open Hunting → Advanced Hunting and paste the KQL below. Set Time range to Last 1 hour (extend to 7 days when sweeping a known IOC).
  • 2Click Run query. For any hit, click the row → open the DeviceName link → Device timeline to see the full process tree and everything that ran after.
  • 3Read the full ProcessCommandLine — decode any -EncodedCommand Base64 to reveal the true download URL and next stage.
  • 4Note the InitiatingProcessFileName (the Office binary), the acting AccountName, and the DeviceId — you need all three for containment.
  • 5Under Incidents & alerts → Alerts, check for a co-incident "Suspicious Office child process" or "Initial access" alert and link them into one incident.
Child Process / Command FragmentMeaningSeverity
powershell.exe -enc / -e / FromBase64StringEncoded PowerShell — hides the real command from casual reviewCRITICAL
powershell -w hidden / -windowstyle hiddenHidden window — no UI, classic loader stealthCRITICAL
IEX / Invoke-Expression / DownloadString / iwr / curlIn-memory download-and-run of stage 2CRITICAL
mshta.exe http... / mshta vbscript:HTA proxy execution of remote/inline scriptCRITICAL
wscript.exe / cscript.exe *.vbs / *.jsDropped VBScript/JScript loader executed by WSHCRITICAL
regsvr32 /s /n /u /i:http... scrobj.dllSquiblydoo — regsvr32 running remote scriptletCRITICAL
rundll32.exe *.dll,Entry / javascript:DLL proxy execution of dropped payloadCRITICAL
certutil -urlcache -f / -decodeLOLBin download or Base64 decode of payloadHIGH
cmd.exe /c ... & / bitsadmin /transferShell chaining or BITS download of next stageHIGH
DETECTS: Any Office application launching a scripting interpreter or system-binary-proxy LOLBin — the core malicious-document execution edge
KQL — Microsoft Sentinel / Defender XDR Advanced Hunting
// Office app spawning a script host / LOLBin child (last 1h) let officeParents = dynamic(["winword.exe","excel.exe","powerpnt.exe","outlook.exe","mspub.exe","msaccess.exe","onenote.exe"]); let suspChildren = dynamic(["powershell.exe","powershell_ise.exe","pwsh.exe","cmd.exe","mshta.exe","wscript.exe","cscript.exe","rundll32.exe","regsvr32.exe","certutil.exe","bitsadmin.exe","curl.exe","msiexec.exe","cmstp.exe","installutil.exe"]); DeviceProcessEvents | where Timestamp > ago(1h) | where InitiatingProcessFileName in~ (officeParents) | where FileName in~ (suspChildren) | extend Suspicious = ProcessCommandLine has_any ("-enc","-e ","EncodedCommand","FromBase64String","IEX","Invoke-Expression","DownloadString","DownloadFile","iwr","Invoke-WebRequest","-w hidden","-windowstyle hidden","bypass","http://","https://","scrobj.dll","urlcache") | project Timestamp, DeviceName, DeviceId, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine, InitiatingProcessCommandLine, InitiatingProcessParentFileName, Suspicious, SHA256 | order by Suspicious desc, Timestamp desc
DETECTS: Same coverage in Splunk — Office parent process launching a script-host / LOLBin child (Sysmon EID 1 or WinEvent 4688)
SPL — Splunk
index=* (sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1) OR (sourcetype=WinEventLog:Security EventCode=4688) | eval pproc=lower(coalesce(ParentImage,ParentProcessName)) | eval cproc=lower(coalesce(Image,NewProcessName)) | where (like(pproc,"%winword.exe") OR like(pproc,"%excel.exe") OR like(pproc,"%powerpnt.exe") OR like(pproc,"%outlook.exe") OR like(pproc,"%mspub.exe") OR like(pproc,"%msaccess.exe") OR like(pproc,"%onenote.exe")) | where (like(cproc,"%powershell.exe") OR like(cproc,"%pwsh.exe") OR like(cproc,"%cmd.exe") OR like(cproc,"%mshta.exe") OR like(cproc,"%wscript.exe") OR like(cproc,"%cscript.exe") OR like(cproc,"%rundll32.exe") OR like(cproc,"%regsvr32.exe") OR like(cproc,"%certutil.exe") OR like(cproc,"%bitsadmin.exe") OR like(cproc,"%msiexec.exe")) | eval cmd=coalesce(CommandLine,Process_Command_Line) | table _time, host, Account_Name, pproc, cproc, cmd | sort - _time

OUTLOOK.EXE spawning a script host is especially high-fidelity — it usually means a macro fired straight from the reading pane or a malicious attachment opened in place, before the file even hit disk. Prioritise Outlook-parent hits.

I2
Payload Dropped to Disk by the Office Chain
MANUAL + KQL
WHY CHECK

The macro's job is to stage a second-stage binary. Office (or the script host it spawned) writing an executable, DLL, HTA, script or LNK into a user-writable path is the drop event. It confirms the loader ran and gives you the payload hash to sweep the fleet.

📍 Portal Navigation — Microsoft Defender XDR
security.microsoft.com› Hunting› Advanced Hunting
  • 1Run the DeviceFileEvents KQL below, scoped to the affected DeviceId from I1, to list files written by the Office process or its children.
  • 2For each dropped file, copy the SHA256 and pivot to security.microsoft.com → Threat Intelligence → File page to check the verdict and prevalence across the tenant.
  • 3Note the FolderPath — payloads in %TEMP%, %APPDATA%\Roaming, %PROGRAMDATA% or a Startup folder are the norm; anything in a Startup path is also persistence (cross to I4).
  • 4Check whether the dropped file was subsequently executed — join back to DeviceProcessEvents on the SHA256 / FileName.
Drop Location / TypeMeaningSeverity
%TEMP% or %APPDATA%\Roaming *.exe/.dllSecond-stage binary staged for executionCRITICAL
*.hta / *.vbs / *.js / *.ps1 / *.wsfScript loader dropped to be run by WSH / mshtaCRITICAL
...\Start Menu\Programs\Startup\*.lnkStartup persistence — payload re-runs at every logonCRITICAL
%APPDATA%\Microsoft\Templates\Normal.dotmWord global template weaponised (see I4)CRITICAL
Downloaded .iso/.img/.zip then mounted contentContainer delivery to strip Mark-of-the-WebHIGH
DETECTS: Executable / script / LNK payload written to a user-writable path by an Office process or the script host it spawned
KQL — Microsoft Sentinel / Defender XDR Advanced Hunting
// Files dropped by Office or its script-host children (last 1h) let officeChain = dynamic(["winword.exe","excel.exe","powerpnt.exe","outlook.exe","onenote.exe","mspub.exe","msaccess.exe","powershell.exe","pwsh.exe","cmd.exe","mshta.exe","wscript.exe","cscript.exe","rundll32.exe","regsvr32.exe","certutil.exe","bitsadmin.exe"]); DeviceFileEvents | where Timestamp > ago(1h) | where ActionType in ("FileCreated","FileRenamed","FileModified") | where InitiatingProcessFileName in~ (officeChain) | where FolderPath has_any (@"\Temp\", @"\AppData\Roaming", @"\AppData\Local", @"\ProgramData", @"\Startup", @"\Templates", @"\Public\") | where FileName endswith ".exe" or FileName endswith ".dll" or FileName endswith ".hta" or FileName endswith ".vbs" or FileName endswith ".js" or FileName endswith ".ps1" or FileName endswith ".wsf" or FileName endswith ".lnk" or FileName endswith ".scr" or FileName endswith ".bat" or FileName endswith ".cmd" or FileName endswith ".dotm" or FileName endswith ".xlam" or FileName endswith ".xll" | project Timestamp, DeviceName, DeviceId, AccountName, InitiatingProcessFileName, FileName, FolderPath, SHA256, InitiatingProcessCommandLine | order by Timestamp desc
DETECTS: Same coverage in Splunk — Sysmon FileCreate (EID 11) where the writing process is an Office binary or a script host and the target is an executable/script/LNK in a writable path
SPL — Splunk
index=* sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=11 | eval img=lower(Image) | where (like(img,"%winword.exe") OR like(img,"%excel.exe") OR like(img,"%powerpnt.exe") OR like(img,"%outlook.exe") OR like(img,"%onenote.exe") OR like(img,"%powershell.exe") OR like(img,"%cmd.exe") OR like(img,"%mshta.exe") OR like(img,"%wscript.exe") OR like(img,"%cscript.exe") OR like(img,"%rundll32.exe") OR like(img,"%regsvr32.exe") OR like(img,"%certutil.exe")) | eval tf=lower(TargetFilename) | where (like(tf,"%\\temp\\%") OR like(tf,"%\\appdata\\roaming%") OR like(tf,"%\\appdata\\local%") OR like(tf,"%\\programdata%") OR like(tf,"%\\startup\\%") OR like(tf,"%\\templates\\%")) | where match(tf,"\.(exe|dll|hta|vbs|js|ps1|wsf|lnk|scr|bat|cmd|dotm|xlam|xll)$") | table _time, host, User, Image, TargetFilename, Hashes | sort - _time
I3
Macro / Child Process Network Callout (C2 / Stage-2 Fetch)
MANUAL + KQL
WHY CHECK

The loader must reach out to fetch stage 2 or register with C2. An outbound connection initiated by an Office process, or by the script host it spawned, to an external host is the confirmation that flips this to SEV1 — the attacker now has a channel into your network.

📍 Portal Navigation — Microsoft Defender XDR
security.microsoft.com› Hunting› Advanced Hunting
  • 1Run the DeviceNetworkEvents KQL below scoped to the affected DeviceId to surface connections whose initiating process is Office or a script host.
  • 2For each RemoteUrl / RemoteIP, pivot to Threat Intelligence → URL/IP page and cross-check your TI feed (pivot SOP-65). Newly-registered domains and raw-IP callouts are strong TP signals.
  • 3Check for beaconing regularity — repeated connections at a fixed interval indicate an established implant (pivot SOP-09 C2 Beaconing).
  • 4Confirm whether the connection succeeded (ActionType ConnectionSuccess) or was blocked at the proxy/firewall — this drives whether stage 2 actually landed.
DETECTS: Outbound connections initiated by an Office application or a script host it spawned — stage-2 download or C2 registration
KQL — Microsoft Sentinel / Defender XDR Advanced Hunting
// Network callouts from Office / script-host processes (last 1h) let netParents = dynamic(["winword.exe","excel.exe","powerpnt.exe","outlook.exe","onenote.exe","mspub.exe","msaccess.exe","powershell.exe","pwsh.exe","mshta.exe","wscript.exe","cscript.exe","rundll32.exe","regsvr32.exe","certutil.exe","bitsadmin.exe","curl.exe"]); DeviceNetworkEvents | where Timestamp > ago(1h) | where InitiatingProcessFileName in~ (netParents) | where RemoteIPType == "Public" | where ActionType in ("ConnectionSuccess","ConnectionRequest","InboundConnectionAccepted","ConnectionFound") | project Timestamp, DeviceName, DeviceId, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteUrl, RemoteIP, RemotePort, ActionType | order by Timestamp desc
DETECTS: Same coverage in Splunk — Sysmon network-connect (EID 3) where the connecting process is an Office binary or script host reaching a public destination
SPL — Splunk
index=* sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=3 | eval img=lower(Image) | where (like(img,"%winword.exe") OR like(img,"%excel.exe") OR like(img,"%powerpnt.exe") OR like(img,"%outlook.exe") OR like(img,"%onenote.exe") OR like(img,"%powershell.exe") OR like(img,"%pwsh.exe") OR like(img,"%mshta.exe") OR like(img,"%wscript.exe") OR like(img,"%cscript.exe") OR like(img,"%rundll32.exe") OR like(img,"%regsvr32.exe") OR like(img,"%certutil.exe") OR like(img,"%bitsadmin.exe")) | where Initiated="true" AND DestinationIsIpv6="false" | table _time, host, User, Image, DestinationHostname, DestinationIp, DestinationPort | sort - _time

A blocked callout is NOT a benign outcome. It means the loader tried to reach C2 and your controls held — but the macro still ran, the endpoint is still compromised, and the actor may retry via a fallback domain. A blocked connection is confirmation, not exoneration. Isolate anyway.

I4
Office Persistence — Templates & Add-ins (T1137)
MANUAL + KQL
WHY CHECK

Beyond the one-shot macro, actors survive reboots by weaponising Office itself — a poisoned global template (Normal.dotm, an XLSTART workbook), a WLL/XLL/VBA add-in, or an Outlook VbaProject.OTM. These re-execute the payload every time the user opens Office, so cleaning only the dropped binary leaves the door open.

📍 Portal Navigation — Microsoft Defender XDR
security.microsoft.com› Hunting› Advanced Hunting
  • 1Run the combined DeviceFileEvents + DeviceRegistryEvents KQL below on the affected device to surface template drops and add-in registration.
  • 2Inspect the Office Trusted Locations / add-in registry paths for values pointing at unexpected DLL/XLL files or user-writable paths.
  • 3For OneNote-based lures, check for onenote.exe writing embedded attachments to %TEMP%\OneNote and executing them.
  • 4If a template/add-in is confirmed weaponised, this is persistence — it MUST be removed in Eradication (E1) and re-checked to 0 hits.
Persistence LocationMeaningSeverity
%APPDATA%\Microsoft\Templates\Normal.dotmWord global template — code runs on every Word launchCRITICAL
%APPDATA%\Microsoft\Excel\XLSTART\*.xls*Excel auto-open workbook — runs on every Excel launchCRITICAL
%APPDATA%\Microsoft\Outlook\VbaProject.OTMOutlook VBA project — runs on Outlook eventsCRITICAL
HKCU\...\Office\<ver>\<app>\Addins\*COM/VBA add-in registered to auto-loadHIGH
*.xll / *.wll add-in in Trusted LocationNative Excel/Word add-in DLL — code execution on loadHIGH
HKCU\...\Office\<ver>\Word\Security\Trusted LocationsNew trusted location added to bypass macro protectionsHIGH
DETECTS: Writes to Office global templates / XLSTART / Outlook OTM, or add-in registry registration — Office application startup persistence
KQL — Office Template & Add-in Persistence
// Template/XLSTART/OTM drops + add-in registration (last 24h) let tmpl = DeviceFileEvents | where Timestamp > ago(24h) | where FolderPath has_any (@"\Microsoft\Templates\Normal.dotm", @"\Excel\XLSTART", @"\Outlook\VbaProject.OTM", @"\Word\STARTUP", @"\AddIns") or FileName endswith ".xll" or FileName endswith ".wll" | project Timestamp, DeviceName, DeviceId, AccountName, FileName, FolderPath, InitiatingProcessFileName, SHA256, Src="File"; let reg = DeviceRegistryEvents | where Timestamp > ago(24h) | where ActionType == "RegistryValueSet" | where RegistryKey has @"\Office\" and (RegistryKey has @"\Addins" or RegistryKey has "Trusted Locations" or RegistryKey has "VBAWarnings") | project Timestamp, DeviceName, DeviceId, AccountName, FileName=RegistryValueName, FolderPath=RegistryKey, InitiatingProcessFileName, SHA256="", Src="Registry"; union tmpl, reg | order by Timestamp desc
DETECTS: Same coverage in Splunk — Sysmon FileCreate (EID 11) to Office template/add-in paths, or registry set (EID 13) to Office Addins / Trusted Locations / VBAWarnings
SPL — Splunk
index=* sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational (EventCode=11 OR EventCode=13) | eval tf=lower(coalesce(TargetFilename,TargetObject)) | where (like(tf,"%\\microsoft\\templates\\normal.dotm") OR like(tf,"%\\excel\\xlstart%") OR like(tf,"%\\outlook\\vbaproject.otm") OR like(tf,"%\\word\\startup%") OR like(tf,"%\\addins%") OR match(tf,"\.(xll|wll)$") OR like(tf,"%\\office\\%trusted locations%") OR like(tf,"%\\office\\%vbawarnings")) | table _time, host, User, EventCode, Image, tf, Details | sort - _time

VBAWarnings set to 1 in HKCU (macros enabled without notification) is a strong pre-attack tell — an actor lowering the macro guardrail before delivery. Alert on any change to that value outside a managed GPO/Intune policy.

I5
Delivery Correlation — Email & Container Format
MANUAL + KQL
WHY CHECK

Tying the on-endpoint execution back to the delivery email proves the vector, identifies every other recipient who got the same lure, and gives you the sender, subject and attachment hash to purge tenant-wide before more users click.

📍 Portal Navigation — Microsoft Defender for Office 365
security.microsoft.com› Email & collaboration› Explorer (Threat Explorer)
  • 1In Threat Explorer, filter Recipients = the affected user and the time window just before the execution to find the delivering message.
  • 2Capture the sender address, sender IP, subject, and the attachment SHA256 — then run the EmailAttachmentInfo KQL to find all other recipients of the same attachment hash.
  • 3Note the delivery format — a macro doc inside an ISO/IMG/ZIP/7z or a OneNote file indicates deliberate Mark-of-the-Web evasion.
  • 4Feed the attachment hash + sender into Containment (email purge) and Eradication (block indicators).
DETECTS: The delivery email and every recipient of the same malicious attachment hash — scope and eradication targeting
KQL — Email Delivery & Attachment Fan-out
// Find the delivering message + all recipients of the same attachment (last 7d) let target = "[email protected]"; // affected user from I1 let badHash = EmailAttachmentInfo | where Timestamp > ago(7d) | where RecipientEmailAddress =~ target | where FileType in~ ("docm","xlsm","xls","doc","xlsb","pptm","one","iso","img","zip","7z","rar","lnk") | project SHA256; EmailAttachmentInfo | where Timestamp > ago(7d) | where SHA256 in (badHash) | join kind=inner (EmailEvents | where Timestamp > ago(7d)) on NetworkMessageId | project Timestamp, SenderFromAddress, SenderIPv4, Subject, RecipientEmailAddress, FileName, FileType, SHA256, DeliveryAction, ThreatTypes | order by Timestamp desc
DETECTS: Same coverage in Splunk — message-tracking / MDO logs for the sender+attachment across all recipients
SPL — Splunk
index=email (sourcetype=o365:reporting:messagetrace OR sourcetype=mdo:email) | search attachment_hash=* (file_type IN ("docm","xlsm","xls","doc","pptm","one","iso","img","zip","7z","lnk")) | stats values(recipient) as recipients, values(subject) as subjects, dc(recipient) as recipient_count by sender, sender_ip, attachment_name, attachment_hash | sort - recipient_count
I6
IOC Extraction & FP / TP Decision Gate
VERDICT
WHY CHECK

Before escalating, extract every pivotable indicator and make an explicit call. The IOCs feed the fleet-wide sweep and the block list; the decision gate stops you both from closing a real intrusion and from isolating a legitimately-signed business macro.

Extract and record:

  • 1Dropped payload SHA256 / filename / path (from I2)
  • 2C2 URL / domain / IP / port (from I3)
  • 3Delivering sender address, sender IP, subject, attachment hash (from I5)
  • 4Affected DeviceId(s), AccountName(s), and the exact parent→child command line (from I1)
  • 5Any persistence artefact — template/add-in path or registry value (from I4)
True Positive SignalsFalse Positive Signals
Office spawns powershell/mshta/wscript/cmd with encoded or download command lineEnterprise line-of-business macro digitally signed by a trusted, documented publisher
Payload dropped to %Temp%/%AppData% and executedAdd-in DLL/XLL belongs to a known deployed business application (matches allow-list)
Outbound callout to newly-registered domain / raw IP / TI-matched hostAutomation via a managed, signed template pushed by IT (GPO/Intune) with a change record
Same parent→child chain on multiple endpoints / delivered by phishing emailSecurity tool / RMM component whose parent is misattributed to Office (verify true parent)
Persistence written (Normal.dotm / XLSTART / add-in) with no change ticketRed-team / authorised phishing simulation confirmed by a scope + tester source

"It's probably a signed corporate macro" is a hypothesis, not a verdict. Confirm the Authenticode signer and a matching allow-list/change record before closing. An attacker with a stolen code-signing cert, or a user talked into enabling an unsigned macro, both look "normal" at a glance.

🚫

03 — CONTAINMENT

IMMEDIATE ACTION
C1
Verdict & Escalation Decision
DECISION GATE
▶ Based on Identification Findings:
Confirmed Office spawned a script host AND (payload dropped/executed OR outbound C2 callout OR persistence written OR chain on multiple hosts) — SEV1: execute C2 isolation immediately, escalate to L2/IR
Uncertain Office spawned a script host with suspicious command line, but no drop/callout confirmed yet — SEV2: isolate the endpoint, complete I2/I3/I5, do not release until resolved
False Pos. Signed trusted-publisher macro or documented business add-in matching allow-list/change record — document publisher + change ref, close ticket, tune the rule

Do not "wait and watch" a confirmed Office-spawns-shell chain to gather more evidence. The loader stage is measured in seconds; every minute unisolated is a minute for credential theft, lateral movement and beacon persistence. Isolate first, forensicate the isolated host after.

C2
Isolate Endpoint & Preserve Volatile Evidence
MDE ISOLATION
📍 Portal Navigation — MDE Device Isolation
security.microsoft.com› Assets› Devices› [Device Name]› Isolate device
  • 1Before isolating, start a Live Response session (Actions → Initiate Live Response) and collect a memory image, running process list, and network connection list — this volatile state disappears once you cut the network.
  • 2Kill the live malicious chain: in Live Response run getfile on the dropped payload (for evidence) then kill the loader PID and any spawned child processes.
  • 3Click Actions (⋮) → Isolate device → Full isolation. Confirm the device status changes to Isolated.
  • 4Under Incidents & alerts, link every related alert (child-process, drop, network) into one incident and set severity.
  • 5Run I1 across the whole fleet (remove the DeviceId scope) to confirm whether the same parent→child chain hit other endpoints — an email-delivered lure usually did.
C3
Contain the Identity, Network & Delivery Channel
IDENTITY + EMAIL + NET
  • 1Identity: if the payload could have stolen credentials/tokens (infostealer, LSASS access, browser cookie theft — pivot SOP-83), in Entra ID → Users → [user] → Revoke sessions and force a password reset. Treat the account as compromised.
  • 2Network: block the C2 URL/domain/IP from I3 via Settings → Endpoints → Indicators → URLs/Domains → Add indicator (and IP) with action Block, tenant-wide.
  • 3File: block the payload SHA256 from I2 via Settings → Endpoints → Indicators → File hashes → Add indicator → Block and remediate.
  • 4Email: in Threat Explorer, select the delivering message(s) from I5 → Take action → Soft delete / Move to Deleted Items for every recipient, and block the sender/attachment hash.
  • 5If multiple endpoints were hit (from C2 step 5), isolate each and repeat identity containment for each affected user.

Purge the email from ALL recipients, not just the one who detonated it. The others simply haven't clicked yet — removing the lure before they do prevents the next five incidents.

🗑

04 — ERADICATION

CLEANUP
E1
Remove Payload, Persistence & Restore the Endpoint
ERADICATION
  • 1Via Live Response, delete the dropped payload(s) from I2 (remediate / remove) and confirm quarantine of any file the block-hash indicator flagged.
  • 2Remove Office persistence from I4: delete/replace a weaponised Normal.dotm, clear XLSTART and Word\STARTUP, remove malicious VbaProject.OTM, and delete rogue add-in registry values under HKCU\...\Office\<ver>\<app>\Addins.
  • 3Hunt for secondary persistence the loader may have created — scheduled tasks, Run keys, WMI subscriptions, services (cross-reference SOP-26 and SOP-30).
  • 4Run a full Defender scan on the isolated host: Start-MpScan -ScanType FullScan via Live Response. Reset the compromised user's credentials and revoke tokens if not already done in C3.
  • 5Close the entry vector: confirm "Block macros from running in Office files from the Internet" is enforced by policy (Intune/GPO), enable the relevant ASR rules — "Block Office apps from creating child processes", "Block Office apps from creating executable content", "Block Win32 API calls from Office macros" — in Block mode.
  • 6Reconstruct the timeline: delivery (I5) → user enabled content → spawn (I1) → drop (I2) → callout (I3) → persistence (I4). Record first-seen, what the actor touched, and what data/credentials were at risk.
VERIFY CLEAN: Re-run I1, I2 and I4 on the affected device scoped to after the cleanup timestamp — expected result is 0 hits
KQL — Post-Eradication Verification (expect 0 rows)
// Confirm no Office-spawns-shell, no new drops, no persistence after cleanup let cleanupTime = datetime(2026-09-21T20:00:00Z); // set to your remediation time let dev = "AFFECTED-DEVICE"; DeviceProcessEvents | where Timestamp > cleanupTime and DeviceName == dev | where InitiatingProcessFileName in~ ("winword.exe","excel.exe","powerpnt.exe","outlook.exe","onenote.exe") | where FileName in~ ("powershell.exe","pwsh.exe","cmd.exe","mshta.exe","wscript.exe","cscript.exe","rundll32.exe","regsvr32.exe","certutil.exe","bitsadmin.exe") | project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
SPL — Post-Eradication Verification (expect 0 rows)
index=* sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational EventCode=1 host="AFFECTED-DEVICE" earliest=-30m | eval pproc=lower(ParentImage), cproc=lower(Image) | where (like(pproc,"%winword.exe") OR like(pproc,"%excel.exe") OR like(pproc,"%powerpnt.exe") OR like(pproc,"%outlook.exe") OR like(pproc,"%onenote.exe")) | where (like(cproc,"%powershell.exe") OR like(cproc,"%cmd.exe") OR like(cproc,"%mshta.exe") OR like(cproc,"%wscript.exe") OR like(cproc,"%cscript.exe") OR like(cproc,"%rundll32.exe") OR like(cproc,"%regsvr32.exe")) | table _time, host, ParentImage, Image, CommandLine
Eradication Complete When
  • Dropped payload(s) deleted / quarantined and hash blocked tenant-wide
  • All Office persistence removed (Normal.dotm / XLSTART / OTM / add-ins clean)
  • Secondary persistence (tasks / Run keys / WMI / services) hunted and cleared
  • Full Defender scan clean; compromised credentials reset & sessions revoked
  • I1 / I2 / I4 re-run post-cleanup return 0 hits
  • Macro-from-internet block + Office child-process ASR rules enforced by policy
  • Delivery email purged from every recipient; sender + attachment blocked
  • Timeline reconstructed and attached to the incident record

Do not release the device from isolation on "payload deleted" alone. If the account credentials or browser tokens were exposed, the attacker may already hold a session elsewhere — reset identity and confirm no anomalous sign-ins (pivot SOP-04) before restoring network access.

📢

05 — ESCALATION

ESCALATION PATHS
ES1
Escalation Matrix & Notification
ESCALATION
TierTrigger ConditionWho to NotifyAction
L1 → L2L1 cannot call TP vs FP within 30 min; privileged/VIP user affected; same chain on >1 endpoint; suspicious spawn but callout unconfirmedSOC L2 AnalystIsolate, hand off with full I1–I6 findings
L2 → IRConfirmed execution + C2 callout / payload run; persistence written; credential-theft or beacon payload identified; lateral movement suspectedIncident Response TeamFull IR: scope fleet, hunt lateral movement, forensics on payload
IR → CISOMultiple endpoints compromised; ransomware-precursor / Cobalt Strike beacon confirmed; privileged/domain account credentials exposed; data at riskCISO / Security ManagementActivate major-incident process; consider business continuity
CISO → Exec/LegalCustomer/regulated data exposure (GDPR / PCI / HIPAA); public-facing or crown-jewel system reached; active ransomware encryptionExecutive team, Legal/DPOBreach assessment; GDPR 72-hour notification clock starts
ExternalConfirmed breach beyond in-house capacity; law-enforcement or third-party notification requiredMSSP / Forensics vendor / Law enforcementEngage retainer; preserve evidence chain of custody

Bring to every escalation:

  • 1Incident ID; affected device(s) and user(s)
  • 2The exact parent→child command line and dropped payload SHA256
  • 3C2 indicators (URL/domain/IP) and delivery details (sender, subject, attachment hash)
  • 4Timeline of events and containment actions already taken
  • 5Current confidence level (TP confirmed / suspected / unverified) and fleet-wide scope

If the payload is identified as a Cobalt Strike / loader beacon or the actor reaches a domain-privileged account, treat this as an active hands-on-keyboard intrusion and escalate straight to IR + CISO — do not down-grade because it "started as one phishing email". This is exactly how major ransomware incidents begin.


Stay Threat-Ready

Follow CyberHawk Threat Intel for daily SOC analyst playbooks, detection engineering guides, and threat intelligence.

📺 YouTube 🎤 TikTok 🐦 X / Twitter 📡 Telegram
All SOPs Blog Web App (Free)
They can't exploit you if you are the Exploit.