
File Attack Deep Dives: Office Documents as an Attack Surface
Every way an Office document attacks: macros, remote templates, embedded objects, hyperlinks, QR handoffs and invoice fraud, plus the signals that catch each.
以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。
Every way an Office document attacks: macros, remote templates, embedded objects, hyperlinks, QR handoffs and invoice fraud, plus the signals that catch each.
A document is a container that can carry code, but it does not need any. The same file can deliver a click, a phone handoff, or a payment request with no macro and no executable at all. Read the structure, then read the intent.
Part 2 of this series, HTML as an attack surface, covered the one file type that is also a program. Office documents are the opposite problem: the container is ordinary, and the attack lives either in a hidden binary part or in the words and links on the page. This part covers both. First the code, so you know where a macro hides and every way it fires. Then the documents that carry no code at all, because those are the ones a macro policy never touches.
Invoice_Q3.docma normal document, with code in vbaProject.binOpened in WordProtected View loads the macro project but keeps it dormant“Enable Content” clickedthe human hands over executionAutoOpen firesDocument_Open / Workbook_Open runs the codeOffice spawns a script hostdownloads and runs the second stageEvery step after "Opened in Word" happens on the endpoint, after the gateway has already handed the document over.
Where does the code hide?
The VBA project lives in one opaque binary part, and its path depends on the host:
A modern macro-enabled document (.docm, .xlsm, .pptm) is a ZIP archive of XML parts. Rename a copy to .zip, extract it, and every part is readable XML except one: the VBA project blob.
Inside that blob sits an OLE compound file holding the compressed VBA source plus a per-version compiled cache, with a dir stream describing the project and one stream per code module. Three markers confirm a package really carries a project: the vbaProject.bin part itself, a macroEnabled.12 content type in [Content_Types].xml, and a vbaProject relationship wiring the workbook to the blob. A plain .xlsx has none of these, which is why saving an .xlsm down to .xlsx strips the code.
Legacy .doc and .xls files skip the ZIP layer entirely: the whole file is the compound document, and the VBA lives in Macros/VBA or _VBA_PROJECT_CUR/VBA storages.
Analyst tooling reads this layout directly. oledump.py lists the compound streams and flags macro-bearing ones with a capital M, while olevba extracts and deobfuscates the source without opening the document. A structure-first triage, stream list before source read, tells you in seconds whether there is anything to detonate at all.
These names are the switch. If one appears in the project, the code runs on open. Before reading a single line of VBA, an analyst asks whether anything runs automatically, and the triggers fall into three groups, matched case-insensitively:
This is the moment the whole class turns on: a normal-looking invoice, one yellow bar, one click. Everything after that is the application obeying the file.
A single line in Document_Open calling Shell is a different threat from a long sophisticated macro with no automatic trigger. But the absence of an auto-exec name is not a clean bill of health: documents pair triggerless macros with "enable content" social engineering, or with remote template injection, where an attachedTemplate relationship points at an external .dotm that carries the real code.
Two structural evasions deserve their own checks. VBA stomping exploits the compiled cache: Excel may run the per-version P-code without recompiling the visible source, so the code you read is not the code that runs. Detection compares the P-code disassembly against the source and flags divergence. XLM 4.0 macros, the pre-VBA Excel language, hide in concealed sheets and are missed outright by VBA-only parsers, so sheet inspection belongs in the triage alongside stream inspection. And macros are not even required: DDE (Dynamic Data Exchange) fields can launch a command from a code-free document when the user accepts a prompt.
Step through the sequence and watch the gap open between what a control sees and what the machine actually does:
a Word document (.docm), no executable, no archive
a ZIP whose vbaProject.bin holds an opaque OLE blob of VBA source plus compiled p-code
word/vbaProject.bin [Content_Types].xml → macroEnabled.12 word/_rels/document.xml.rels → vbaProject
← PrevStage 1 of 5Next →
What if the document carries no code at all?
Blocking macros closes one door and leaves the rest of the building open. Every vector below is a normal document doing something a document is supposed to do, which is exactly why inspection has nothing to flag.
The document is a pretext: a "protected document", an unpaid invoice, a "sign to receive" notice. It wants one click, and the link lands on a credential page or a payload. It is an old trick, and it exists precisely to get past attachment scanners, which inspect the file rather than where a link leads. Proofpoint still sees it at scale: in 2024 it documented a campaign that put the links inside PDF attachments (TA450).
Put the link in a picture. A QR code is an image, so text scanners walk past it, and the person who scans it is on a phone that sits outside the proxy, the logging, and often the managed device. It is the same handoff Part 2 describes for HTML pages, moved into a document, and it is why "scan this to verify" has become a standard lure.
Here nothing executes and nothing is clicked. The document is a financial request with a plausible story and a new bank account, and the transfer is the payload. That is business email compromise: impersonation in service of financial theft. The FBI's IC3 described the pattern in its BEC advisory, and it remains one of the costliest categories in its annual report.
A document can carry another file inside it, dressed as an innocent icon. The embedded object can be a script, a package, or an executable, and opening it runs the content rather than the container. That makes it a proxy-execution problem as much as a document problem.
Because nothing dangerous is visible at the point of inspection. A dormant macro is inert until consent, and a code-free lure is only text. Classic controls look for a known macro hash or flag any macro at all. Both fail the same way: attackers build low-volume, per-target documents, so signatures miss, and the generic "enable content" warning still gets clicked by enough people. Obfuscation frameworks widen the gap. Cisco Talos documented MacroPack-generated documents uploaded between May and July 2024 from sources in China, Pakistan, Russia, and the US, each carrying generic "enable content" lures and multi-stage VBA that delivered Havoc, Brute Ratel, and PhantomCore payloads (MacroPack abuse).
This is not theoretical either. In February 2025, SentinelOne researchers described a Ghostwriter campaign, prepared since mid-2024 and active by November, that sent RAR archives via Google Drive containing Excel workbooks with Macropack-obfuscated macros. Enabling content wrote a DLL that staged PicassoLoader while a decoy workbook held the victim's attention (Ghostwriter campaign).
The pattern across both campaigns is the point: per-sample builds defeat hashes, layered obfuscation defeats strings, and the human click defeats the rest.
Structure before detonation, behavior after. Work through these in order of signal quality.
Pick a pattern below, see how it lands, then reveal the tell and the detection.
How it lands. A .docm or .xlsm carries VBA in word/vbaProject.bin or xl/vbaProject.bin. On open with content enabled, an AutoOpen or Document_Open entry point runs code that downloads and executes a payload.
The fix follows the tell. Extract and audit macros without opening the document, flag auto-exec entry points before reading bodies, detonate in a sandbox that clicks through "enable content" the way a user would, and alert on the Office-spawns-script-host pair at the endpoint. Block macros in files from the internet where the business allows it. Microsoft blocks them by default now, and that one default removes most of the commodity path (internet macros blocked). Where a business needs macros, the behavioral chain is the backstop that obfuscation cannot move.
For the code-free half there is nothing to detonate, so the controls look different. Resolve every link and QR target at analysis time, put a change-of-bank-details call-back in front of the finance team, and stop treating "no macros" as a verdict. A document with no code can still be the most expensive thing in the inbox.
Does blocking internet macros stop macro attacks?
Mostly, for the commodity path. Documents from the web open under policy that refuses to run the code. But low-volume targeted lures, trusted-sender compromise, and remote template fetches all route around the block, so endpoint behavioral detection still matters.
Why not just alert on every document with a macro?
Because legitimate enterprise workflows run on macros: finance workbooks, reporting templates, and line-of-business forms all carry VBA. Alert on the auto-exec entry point plus suspicious primitives or a suspicious parent-child process chain, not on macro presence alone.
No. Remote template injection, XLM macro sheets, and DDE all deliver execution from a document with no vbaProject.bin, and the vectors above need no code at all: a link, a QR code, a changed bank account, or an embedded object. Read the whole structure and the intent, not just the obvious part.
What can a scanner even see in a document with no code?
Text, links, QR images, and embedded objects. Resolve those four and you have covered the code-free half. The work is in following each one to its target, not in finding a signature that will not be there.
A quick self-check on document macros. Pick an option to see the answer.
-
Where does the VBA project live in a modern .xlsm workbook?
-
Which finding best survives macro obfuscation?
-
A .docx arrives with no vbaProject.bin but still wants to run code. What is the likely vector?
-
Why can reading the VBA source mislead you?
-
A .docx arrives with no macro project but asks you to sign in to view it. What is the vector?
-
Why is a QR code inside a document harder to filter than a link?
-
Which control actually stops a fraudulent invoice with changed bank details?
Next in this series: PDF URL actions, then LNK and ISO containers, each with its own payload pattern and detection.
Senior software lead at Abnormal.AI, prev. CRED and Gojek. Backend engineer working on AI, security, and engineering leadership. Based in Bangalore.
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。