A suspicious Word, Excel, RTF or OneNote attachment needs a fast, repeatable verdict, and opening it in Office to "see what it does" is the one thing an analyst must not do. Malicious documents hide their logic in VBA macros, Excel 4.0 (XLM) formulas, embedded OLE objects, DDE fields, external template references and embedded files, and each hiding place needs a different static check. This guide sets out a triage workflow for defenders: how to handle the sample safely, identify the real file format, find active content with the open source oletools suite and related parsers, recognise remote template injection, and turn the findings into indicators and controls. It is written for SOC analysts, incident responders and email security teams. It describes analysis of documents already received, not how to build them.
Key takeaways
- Identify the container before the content. File extension is a claim, not a fact: decide whether you hold an OLE2 compound file, an OOXML ZIP, RTF, XML, CSV or a OneNote file, because each needs different tools.
- Static first, dynamic second. oleid, olevba, mraptor, msodde, rtfobj and oleobj answer most triage questions without executing anything; send to a sandbox only what static analysis cannot resolve.
- No macro does not mean benign. Remote template references, DDE fields, embedded OLE packages and OneNote attachments deliver payloads with no VBA at all.
- Source code can lie. VBA is stored as compressed source and as compiled p-code; when they disagree, the p-code is what normally runs, so check both on anything suspicious.
- The output is indicators and controls, not a report. URLs, hashes, template hosts and behaviour should flow into blocking, hunting and policy within the same shift.
Where this fits
The Malware Analysis Guide for Defenders sets out the tiered method, lab design and reporting for all malware types. This page is the document-specific triage workflow that sits inside that method. Prevention controls for macros (Mark of the Web blocking, signed macros, trusted locations) are in the Macro Malware Guide, add-in abuse is in the Malicious Office Add-ins Guide, and OneNote delivery controls are in the OneNote Malware Delivery Guide. In ATT&CK v20 terms the documents covered here arrive through T1566.001 Spearphishing Attachment and need the user action described in T1204.002 Malicious File.
Handling samples safely
- Isolated analysis host: a Linux analysis VM without Office installed is the safest default for static work, because the document cannot run. Keep it off the corporate network, with no mapped shares and no stored credentials.
- Transport: move samples in password-protected archives and rename them with a non-executable extension. oledump can analyse a file inside a password-protected ZIP without extracting it, and oletools tools accept zip input with a password option.
- Do not trigger outbound connections: remote templates, DDE and linked objects can contact attacker infrastructure, and ATT&CK notes that template references can force authentication attempts over SMB or HTTPS. Never open the sample on a domain-joined Windows host.
- Preserve evidence: hash the original (SHA-256), keep the original email (headers and message ID) and record where the file came from. See the Email Forensics and Header Analysis Guide.
- Check Mark of the Web on endpoint copies: Microsoft documents that Windows records the source zone in the Zone.Identifier stream (ZoneId 3 is Internet). Files synced by the OneDrive client or saved to FAT32 do not carry it, which explains why some copies run macros when others are blocked.
- Encrypted documents: password-protected Office files hide their streams. msoffcrypto-tool decrypts Office files with the password (often given in the lure email), and recent olevba versions report passwords used and can write decrypted copies.
Step 1: identify the real format
| Container | Typical extensions | Where active content hides | First tools |
|---|---|---|---|
| OLE2 compound file (Office 97 to 2003) | .doc, .xls, .ppt, .dot, .xlt | VBA project streams, Macros sheets (XLM), ObjectPool embedded objects | oleid, oledump, olevba, oleobj |
| OOXML ZIP (Office 2007 and later) | .docx, .docm, .xlsx, .xlsm, .xlsb, .pptm, .dotm | vbaProject.bin (an OLE2 file inside the ZIP), relationship files with external targets, embedded objects, customUI | olevba, oleobj, unzip listing of parts |
| RTF | .rtf, often renamed .doc | Embedded OLE objects and packages; the \*\template control word for remote templates | rtfobj |
| Word or Excel XML, MHT | .xml, .mht, renamed .doc | Embedded base64 VBA project | olevba |
| CSV and SLK | .csv, .slk | DDE formulas; XLM in SLK | msodde, olevba |
| OneNote | .one, .onepkg | Embedded files (scripts, shortcuts, HTML applications) behind a fake button | ftguess to confirm format, then a OneNote-aware parser |
The oletools ftguess tool identifies file formats and containers, and since version 0.60.2 recognises OneNote; oleid calls it and reports format, encryption, VBA and XLM presence and embedded objects. A .doc that ftguess reports as RTF is itself a finding, because renaming RTF to .doc is a common way to reach Word's RTF parser.
Step 2: find and read the active content
| Tool | What it answers | How to read the result |
|---|---|---|
| oleid | What is inside: format, encryption, VBA and XLM macros, embedded objects | Any risk indicator raised decides which tool runs next |
| mraptor | Is the macro likely malicious, without signatures? | Flags A (auto-execution), W (write to disk or memory) and X (execute outside VBA); suspicious when A and (W or X). Exit code 20 means suspicious, 2 macro OK, 0 no macro |
| olevba | Macro source, auto-exec triggers, suspicious keywords, IOCs, obfuscation | Summary rows of type AutoExec (AutoOpen, Auto_Open, Workbook_Open), Suspicious (Shell, Lib, Environ, URLDownloadToFileA), IOC (URLs, IPs, executable names). Decoding options reveal Hex, Base64, StrReverse and Dridex-encoded strings |
| oledump | Stream-level view of OLE2 files | Streams marked M contain VBA; select a stream and decompress it to read the module; plugins and YARA rules run per stream |
| pcodedmp | What the compiled p-code says | Compare with the decompressed source; a mismatch or empty source with populated p-code means the source was tampered with |
| XLMMacroDeobfuscator | What Excel 4.0 formulas do in .xls, .xlsm and .xlsb | Emulates XLM without full execution to recover the formula chain and URLs |
| msodde | DDE and DDEAUTO fields in Word, Excel, RTF, CSV and XML | Any DDE field in a received document is suspicious; it also undoes QUOTE field obfuscation |
| rtfobj, oleobj | Embedded OLE objects and packages | Extract the embedded file, hash it and triage it as its own sample; oleobj also flags customUI onLoad |
Reading macro code without running it
- Find the trigger: AutoOpen, Document_Open, Workbook_Open or a form control event. No trigger usually means the user is told to click something.
- Follow the strings: obfuscated strings are assembled by concatenation, Chr() arithmetic, reversed strings and encodings. Let olevba decode what it can and note what it cannot; the decoded URLs and file paths are the most valuable indicators.
- Name the action: download (URLDownloadToFile, XMLHTTP), write (file system objects, ADODB.Stream), execute (Shell, WScript.Shell, WMI process creation, CreateObject on scripting hosts), or Win32 API declarations through Lib. Map each to ATT&CK: T1059.005 Visual Basic for the macro itself, T1027 Obfuscated Files or Information for the encoding.
- Look for environment checks: olevba flags anti-sandbox and anti-virtualisation patterns. Their presence tells you a sandbox run may come back clean.
Source versus p-code
The pcodedmp project documents that VBA exists as compressed source code, as p-code compiled as each line is entered, and as execodes stored in streams named __SRP_ once the code has run. Most tools read the source. Because the p-code is usually what executes, a document whose source has been removed or replaced while the p-code remains (often called VBA stomping) can look clean to source-only tools. When olevba reports a VBA project but the source is empty or harmless, or when mraptor and an anti-malware verdict disagree, disassemble the p-code before closing the ticket.
Step 3: macro-less techniques
Remote template injection
ATT&CK T1221 Template Injection describes documents whose template reference points at a remote resource that is fetched when the document loads, so the delivered file carries no macro, script or exploit for static scanners to find. In OOXML Word documents the reference is a relationship of type attachedTemplate with an external target in the settings relationship part; in RTF it is the \*\template control word. Triage steps:
- List the ZIP parts and read every .rels file for TargetMode="External" targets.
- Record the full URL or UNC path. An http, https or file:// path to an unfamiliar host is a finding; a UNC path to an internet address is also a credential exposure risk (forced authentication).
- Do not fetch the template from the analysis host. Retrieve it, if at all, through a controlled sandbox or a threat intelligence service, then analyse it as a new sample (it is usually a macro-enabled .dotm or an RTF).
- Block the host at the proxy and DNS layers and hunt for other documents referencing it.
DDE, embedded objects and links
- DDE (T1559.002 Dynamic Data Exchange): fields that request command execution, found by msodde in Word, Excel, RTF and CSV files.
- OLE packages: embedded executables, scripts or shortcuts, extracted with rtfobj or oleobj. Treat each as a new sample; see the Malicious LNK Files Guide for shortcut payloads.
- Exploit-bearing objects: oleobj added detection of the initial stage of CVE-2021-40444. An embedded object or relationship that points to an HTML page on an external host warrants the same handling as a remote template.
OneNote lures
OneNote files carry embedded files behind an image that tells the user to double-click. Microsoft blocks direct opening of embedded files with dangerous extensions in OneNote for Microsoft 365 from Version 2304 (Current Channel rollout 1 May 2023), using the same extension list as Outlook, Word, Excel and PowerPoint, managed by the "Block additional file extensions for OLE embedding" and "Allow file extensions for OLE embedding" policies. For analysis, confirm the format with ftguess, extract embedded files with a OneNote-aware parser, and triage each as its own sample.
Step 4: decide, and when to go dynamic
| Static result | Verdict | Next action |
|---|---|---|
| No VBA, XLM, DDE, external relationship or embedded object; format matches extension | Likely benign | Close with hash recorded; release if quarantined |
| Macro with A and (W or X), decoded download URL | Malicious | Extract IOCs, block, hunt; sandbox only to capture second stage |
| Remote template or external object link to unfamiliar host | Malicious until disproved | Block host, retrieve template in a controlled way, hunt for siblings |
| Heavy obfuscation olevba cannot decode, or anti-sandbox checks | Suspicious | Emulate (XLMMacroDeobfuscator, p-code), then detonate in a sandbox configured to defeat the checks |
| Encrypted with no password available | Unknown | Treat as suspicious; check the lure email for the password; block by hash |
| Signed macro from an internal publisher | Verify | Confirm the certificate and the business owner; a signed macro is not automatically safe |
Use a sandbox when static analysis stops at an encoded blob, an emulator gap or a remote stage you need to observe. The Malware Sandbox Guide covers sandbox configuration, including Office versions, network simulation and evasion handling. For a small team, a well-maintained static toolkit plus a commercial or shared sandbox service is usually enough; a large SOC benefits from automating oleid and mraptor in the email pipeline and reserving analyst time for the suspicious and unknown rows.
Step 5: turn findings into indicators and controls
- Indicators: SHA-256 of the document and every extracted object, URLs and hosts (including template hosts), dropped file names and paths, VBA module names and distinctive strings. Write a YARA rule for the family's reusable traits rather than only the hash; see the YARA Rules Guide.
- Email: search mailboxes for the same attachment hash, sender infrastructure and subject, and purge copies. The Email Gateway and Message Trace Detection Guide covers the search.
- Endpoint: check whether the attack surface reduction rules or equivalent EDR behaviour rules would have stopped the chain. In Microsoft Defender the relevant rules include "Block all Office applications from creating child processes" (d4f940ab-401b-4efc-aadc-ad5f3c50688a), "Block Office applications from creating executable content" (3b576869-a4ec-4529-8536-b80a7769e899) and "Block Win32 API calls from Office macros" (92e97fa1-2edf-4476-bdd6-9dd0b4dddc7b); hunt for their audit events (for example AsrOfficeChildProcessAudited) on hosts where the document was opened.
- Policy: where a document reached a user with macros enabled, find out why: a trusted location, a Trusted Document, a signed macro or a missing Mark of the Web. NCSC guidance is that disabling macros is the only effective protection, with internet blocking, trusted locations and signing as fallbacks, and anti-malware set to scan all documents through AMSI.
- Where identity fits: if a remote template or embedded link pointed at an SMB path on the internet, treat the opening user's credential as exposed and reset it; if the macro ran, assume browser sessions and tokens on that host were in reach. See the Initial Access Techniques Guide.
Detection and measurement
| Metric | Why it matters | Target |
|---|---|---|
| Median time from reported attachment to verdict | Speed of containment for the rest of the recipients | Under 30 minutes for static verdicts |
| Share of verdicts reached by static analysis alone | Shows the toolkit is doing the work; sandbox time is reserved for hard cases | Track the trend; investigate drops |
| Indicators published per malicious sample, and time to block | Analysis only helps if it reaches controls | Block within the same shift |
| Hosts where an Office process spawned a child process or wrote an executable | Measures how often prevention failed downstream | Zero in blocking mode; every audit hit reviewed |
| Samples later found malicious after a benign static verdict | Calibration of the triage rules (p-code, templates, encryption) | Zero; each one triggers a workflow review |
Common failure patterns
- Trusting the extension: an RTF renamed to .doc goes through VBA tools, nothing is found, and the embedded OLE object is missed.
- Stopping at "no macros": remote template, DDE and OneNote lures carry no VBA, so a macro-only triage clears them.
- Reading only the source: stomped VBA shows harmless or empty source while the p-code still runs.
- Detonating with the network open: the sandbox fetches the remote template from a production IP or leaks NTLM authentication, tipping off the operator and exposing credentials.
- Clean sandbox, closed ticket: anti-sandbox checks flagged by olevba were ignored, and the document behaves differently on a real user host.
- Analysis that never leaves the analyst: indicators sit in a ticket while copies of the same lure remain in other mailboxes.
Framework mapping
| Framework | Reference |
|---|---|
| MITRE ATT&CK v20 | T1566.001 Spearphishing Attachment, T1204.002 Malicious File, T1059.005 Visual Basic, T1221 Template Injection, T1559.002 Dynamic Data Exchange, T1137.001 Office Template Macros, T1027 Obfuscated Files or Information |
| ATT&CK mitigations | M1042 Disable or Remove Feature or Program, M1040 Behavior Prevention on Endpoint, M1049 Antivirus/Antimalware, M1017 User Training |
| MITRE D3FEND | D3-FA File Analysis, D3-EFA Emulated File Analysis, D3-DA Dynamic Analysis |
| NIST CSF 2.0 | DE.AE-02 adverse events analysed; RS.AN-03 analysis to establish what took place |
| NIST SP 800-53 Rev. 5 | SI-3 Malicious Code Protection, IR-4 Incident Handling, SI-8 Spam Protection |
| CIS Controls v8.1 | Control 9 Email and Web Browser Protections, Control 10 Malware Defenses |
Practitioner checklist
- Build a Linux static analysis VM with oletools, oledump, pcodedmp, XLMMacroDeobfuscator and msoffcrypto-tool, isolated from the corporate network.
- Write a handling procedure: password-protected transport, SHA-256 on receipt, original email preserved.
- Run ftguess or oleid first on every sample and route by real format, not extension.
- Check every OOXML and RTF sample for external template and object references, not only macros.
- Compare VBA source with p-code whenever a VBA project is present and the source looks clean.
- Define when a sample goes to the sandbox, and configure the sandbox to block or simulate outbound SMB.
- Publish hashes, URLs and template hosts to email, proxy, DNS and EDR controls within the shift.
- Hunt for Office child-process and executable-content events on every host where the document was opened.
- Review each confirmed sample for the policy gap that let it run (trusted location, signed macro, missing Mark of the Web).
Standards and references
- MITRE ATT&CK: Template Injection (T1221)
- NCSC: Macro security for Microsoft Office
- Microsoft Learn: Macros from the internet are blocked by default in Office
- Microsoft Learn: OneNote blocks embedded files that have dangerous extensions
- Microsoft Learn: Attack surface reduction rules reference
- oletools project: python-oletools documentation and source
- pcodedmp project: VBA p-code disassembler
- Didier Stevens: oledump.py
Related NHI Mgmt Group resources: Malware Analysis Guide for Defenders · Macro Malware Guide · Malware Sandbox Guide · Digital Forensics (DFIR) Guide