Persistence via Microsoft Office AddIns

Detects attempts to establish persistence on an endpoint by abusing Microsoft Office add-ins.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2020/10/16"
  3integration = ["endpoint", "windows", "m365_defender", "sentinel_one_cloud_funnel", "crowdstrike"]
  4maturity = "production"
  5updated_date = "2026/05/03"
  6
  7[rule]
  8author = ["Elastic"]
  9description = "Detects attempts to establish persistence on an endpoint by abusing Microsoft Office add-ins."
 10from = "now-9m"
 11index = [
 12    "logs-endpoint.events.file-*",
 13    "winlogbeat-*",
 14    "logs-windows.sysmon_operational-*",
 15    "endgame-*",
 16    "logs-m365_defender.event-*",
 17    "logs-sentinel_one_cloud_funnel.*",
 18    "logs-crowdstrike.fdr*",
 19]
 20language = "eql"
 21license = "Elastic License v2"
 22name = "Persistence via Microsoft Office AddIns"
 23references = ["https://labs.withsecure.com/publications/add-in-opportunities-for-office-persistence"]
 24risk_score = 73
 25rule_id = "f44fa4b6-524c-4e87-8d9e-a32599e4fb7c"
 26severity = "high"
 27tags = [
 28    "Domain: Endpoint",
 29    "OS: Windows",
 30    "Use Case: Threat Detection",
 31    "Tactic: Persistence",
 32    "Data Source: Elastic Endgame",
 33    "Data Source: Elastic Defend",
 34    "Data Source: Sysmon",
 35    "Data Source: Microsoft Defender XDR",
 36    "Data Source: SentinelOne",
 37    "Data Source: Crowdstrike",
 38    "Resources: Investigation Guide",
 39]
 40timestamp_override = "event.ingested"
 41type = "eql"
 42
 43query = '''
 44file where host.os.type == "windows" and event.type != "deletion" and
 45 file.extension : ("wll","xll","ppa","ppam","xla","xlam") and
 46 file.path : (
 47    "C:\\Users\\*\\AppData\\Roaming\\Microsoft\\Word\\Startup\\*",
 48    "C:\\Users\\*\\AppData\\Roaming\\Microsoft\\AddIns\\*",
 49    "C:\\Users\\*\\AppData\\Roaming\\Microsoft\\Excel\\XLSTART\\*",
 50
 51    /* Crowdstrike specific condition as it uses NT Object paths */
 52    "\\Device\\HarddiskVolume*\\Users\\*\\AppData\\Roaming\\Microsoft\\Word\\Startup\\*",
 53    "\\Device\\HarddiskVolume*\\Users\\*\\AppData\\Roaming\\Microsoft\\AddIns\\*",
 54    "\\Device\\HarddiskVolume*\\Users\\*\\AppData\\Roaming\\Microsoft\\Excel\\XLSTART\\*"
 55 ) and
 56 not (file.name : "~$*" and process.name : "excel.exe" and ?file.size in (0, 165))
 57'''
 58
 59note = """## Triage and analysis
 60
 61### Investigating Persistence via Microsoft Office AddIns
 62
 63#### Possible investigation steps
 64
 65- Which Office add-in autoload mechanism does the alert show?
 66  - Focus: alert `file.path`, `file.name`, `file.extension`, and `user.id` on `host.id`: "wll" maps to Word Startup, "xla"/"xlam" to Excel XLSTART, and "xll"/"ppa"/"ppam" to add-in locations that may need loader settings.
 67  - Implication: escalate when a user-profile Office startup or add-in path receives a one-off or user-initiated add-in; lower suspicion only when path, name, extension, writer, and provenance all fit the same recognized deployment or repair.
 68
 69- Does the artifact identity or provenance look like a staged payload?
 70  - Why: DLL-style "wll"/"xll" and Office container add-ins have different expected headers, so rename and origin fields can expose payload staging.
 71  - Focus: `file.Ext.header_bytes`, `file.Ext.original.path`, `file.origin_url`, and `file.Ext.windows.zone_identifier`.
 72  - Implication: escalate when headers, rename history, internet-zone provenance, or archive/mail-cache origin conflict with the claimed add-in; lower suspicion when format and provenance align with the same recognized vendor package.
 73
 74- Does the writer process fit an add-in installer or a dropper chain?
 75  - Focus: writer `process.executable`, `process.command_line`, `process.parent.executable`, and `process.code_signature.subject_name`.
 76  - Implication: escalate when browsers, mail clients, scripting engines, archive tools, or unsigned user-writable binaries write the add-in; lower suspicion when signer, path, command line, and parent all match the same recognized installer or managed integration. Signer trust alone never clears the placement.
 77
 78- If registry telemetry is available, did the writer create loader settings required for this add-in type?
 79  - Why: the alert is a file write; loader settings, when visible, show whether Office was configured to consume the add-in rather than merely store it.
 80  - Focus: same `host.id` and writer `process.entity_id`; check `registry.path`, `registry.value`, `registry.data.type`, and `registry.data.strings` for Office loader values pointing to the alerted file. $investigate_0
 81  - Implication: escalate when loader values reference the alerted file or directory; do not require registry corroboration when path, provenance, or writer evidence is already suspicious. Missing registry telemetry is unresolved, not benign.
 82
 83- Did Office later load the add-in or spawn follow-on activity from it?
 84  - Focus: later Office `process.name` values "WINWORD.EXE", "EXCEL.EXE", or "POWERPNT.EXE" on the same `host.id`, Office `process.entity_id`, child `process.parent.entity_id`, child `process.executable`, and, if library telemetry exists, `dll.path` matching the add-in.
 85    - $investigate_1
 86    - $investigate_2
 87  - Hint: missing library telemetry is unresolved, not benign; use those pivots and child process expansion from recovered Office instances as fallback execution evidence.
 88  - Implication: escalate when Office loads the add-in path, starts a child from the same session, or touches a payload dropped with the add-in; do not wait for library telemetry when file, writer, or loader evidence already warrants escalation.
 89
 90- If local evidence is suspicious or unresolved, what related host activity changes scope?
 91  - Focus: related alerts on the same `host.id`, especially document delivery, script execution, suspicious file writes, Office child processes, or additional persistence activity. $investigate_3
 92  - Implication: expand scope when related host alerts connect the add-in write to delivery, execution, credential access, or another persistence mechanism; do not close solely because related alerts are absent.
 93
 94- What disposition do the add-in mechanism, artifact identity, writer lineage, loader state, Office execution, and scope support?
 95  - Escalate on suspicious provenance, unexpected writer lineage, matching loader values, Office follow-on execution, or related host activity; close only when file, writer, provenance, loader state, and Office behavior align with one verified deployment or integration and no contradictions remain; preserve artifacts and escalate mixed or incomplete evidence.
 96
 97### False positive analysis
 98
 99- Managed Office add-in deployment, repair, and productivity, accessibility, or CRM first-use installs can place files in these paths. Close only when writer `process.executable`, `process.command_line`, signer `process.code_signature.subject_name`, parent `process.parent.executable`, final `file.path`, required loader state, provenance fields, later Office `process.name`, and child `process.executable` all align with one deployment or vendor workflow and no contradictory evidence remains. Use change or inventory records as corroboration, not as a telemetry substitute.
100- Before creating an exception, build it from the minimum current-case pattern: `file.path`, writer `process.code_signature.subject_name`, writer `process.parent.executable`, required loader-state pattern, and `host.id` or `user.id` scope. Avoid exceptions on Office startup directories, file extensions, or Office process names alone.
101
102### Response and remediation
103
104- If confirmed benign, reverse temporary containment and document the verified workflow with `file.path`, `file.hash.sha256`, writer `process.executable`, signer `process.code_signature.subject_name`, and any recovered loader-state evidence. Create any exception from that exact workflow pattern and scope it narrowly to the confirmed host or user cohort.
105- If suspicious but unconfirmed, preserve the alert export, the add-in file and hash from `file.path` and `file.hash.sha256`, writer `process.entity_id` and `process.command_line`, and any recovered loader-state, library-load, or child-process evidence before deleting anything. Apply reversible containment first, such as quarantining the add-in file, disabling the affected Office add-in path, or temporarily restricting Office execution on the host.
106- If confirmed malicious, isolate the host if its role can tolerate interruption, then terminate responsible Office or loader processes only after preserving their entity IDs, command lines, and the add-in file evidence. Remove the malicious add-in, clear associated Office loader configuration, restore affected Office add-in settings, and remediate the delivery path that introduced the file. Reset credentials only if the investigation also shows account misuse.
107- Review related hosts and users for the same `file.path`, `file.hash.sha256`, writer lineage, and loader-state pattern before eradication. For Word WLL cases, do not rely on the Office UI alone to prove the add-in is disabled; verify the file and supporting configuration are gone.
108- Post-incident hardening: restrict write access to Office startup directories and add-in loader locations, prefer signed managed add-in deployment, retain process/file plus registry or library telemetry needed to confirm later Office execution, and document adjacent variants such as Word WLL autoload abuse or registry-backed Office add-in loading in the case record.
109"""
110
111setup = """## Setup
112
113This rule is designed for data generated by [Elastic Defend](https://www.elastic.co/security/endpoint-security), which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules.
114
115Setup instructions: https://ela.st/install-elastic-defend
116
117### Additional data sources
118
119This rule also supports the following third-party data sources. For setup instructions, refer to the links below:
120
121- [CrowdStrike](https://ela.st/crowdstrike-integration)
122- [Microsoft Defender XDR](https://ela.st/m365-defender)
123- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
124- [Sysmon Event ID 11 - File Create](https://ela.st/sysmon-event-11-setup)
125"""
126
127[rule.investigation_fields]
128field_names = [
129    "@timestamp",
130    "event.action",
131    "host.id",
132    "user.id",
133    "process.entity_id",
134    "process.pid",
135    "process.executable",
136    "process.command_line",
137    "process.parent.executable",
138    "process.code_signature.subject_name",
139    "file.path",
140    "file.extension",
141    "file.hash.sha256",
142    "file.origin_url",
143]
144
145[transform]
146
147[[transform.investigate]]
148label = "Registry events for the same writing process"
149description = ""
150providers = [
151  [
152    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
153    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" },
154    { excluded = false, field = "event.category", queryType = "phrase", value = "registry", valueType = "string" }
155  ],
156  [
157    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
158    { excluded = false, field = "process.pid", queryType = "phrase", value = "{{process.pid}}", valueType = "string" },
159    { excluded = false, field = "event.category", queryType = "phrase", value = "registry", valueType = "string" }
160  ]
161]
162relativeFrom = "now-1h"
163relativeTo = "now"
164
165[[transform.investigate]]
166label = "Office process starts on the host"
167description = ""
168providers = [
169  [
170    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
171    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
172    { excluded = false, field = "process.name", queryType = "phrase", value = "WINWORD.EXE", valueType = "string" }
173  ],
174  [
175    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
176    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
177    { excluded = false, field = "process.name", queryType = "phrase", value = "EXCEL.EXE", valueType = "string" }
178  ],
179  [
180    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
181    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
182    { excluded = false, field = "process.name", queryType = "phrase", value = "POWERPNT.EXE", valueType = "string" }
183  ]
184]
185relativeFrom = "now-24h/h"
186relativeTo = "now"
187
188[[transform.investigate]]
189label = "Library loads for the add-in path"
190description = ""
191providers = [
192  [
193    { excluded = false, field = "event.category", queryType = "phrase", value = "library", valueType = "string" },
194    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
195    { excluded = false, field = "dll.path", queryType = "phrase", value = "{{file.path}}", valueType = "string" }
196  ]
197]
198relativeFrom = "now-24h/h"
199relativeTo = "now"
200
201[[transform.investigate]]
202label = "Alerts associated with the host"
203description = ""
204providers = [
205  [
206    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
207    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
208  ]
209]
210relativeFrom = "now-48h/h"
211relativeTo = "now"
212
213[[rule.threat]]
214framework = "MITRE ATT&CK"
215
216[[rule.threat.technique]]
217id = "T1137"
218name = "Office Application Startup"
219reference = "https://attack.mitre.org/techniques/T1137/"
220
221[[rule.threat.technique.subtechnique]]
222id = "T1137.006"
223name = "Add-ins"
224reference = "https://attack.mitre.org/techniques/T1137/006/"
225
226[rule.threat.tactic]
227id = "TA0003"
228name = "Persistence"
229reference = "https://attack.mitre.org/tactics/TA0003/"

Triage and analysis

Investigating Persistence via Microsoft Office AddIns

Possible investigation steps

  • Which Office add-in autoload mechanism does the alert show?

    • Focus: alert file.path, file.name, file.extension, and user.id on host.id: "wll" maps to Word Startup, "xla"/"xlam" to Excel XLSTART, and "xll"/"ppa"/"ppam" to add-in locations that may need loader settings.
    • Implication: escalate when a user-profile Office startup or add-in path receives a one-off or user-initiated add-in; lower suspicion only when path, name, extension, writer, and provenance all fit the same recognized deployment or repair.
  • Does the artifact identity or provenance look like a staged payload?

    • Why: DLL-style "wll"/"xll" and Office container add-ins have different expected headers, so rename and origin fields can expose payload staging.
    • Focus: file.Ext.header_bytes, file.Ext.original.path, file.origin_url, and file.Ext.windows.zone_identifier.
    • Implication: escalate when headers, rename history, internet-zone provenance, or archive/mail-cache origin conflict with the claimed add-in; lower suspicion when format and provenance align with the same recognized vendor package.
  • Does the writer process fit an add-in installer or a dropper chain?

    • Focus: writer process.executable, process.command_line, process.parent.executable, and process.code_signature.subject_name.
    • Implication: escalate when browsers, mail clients, scripting engines, archive tools, or unsigned user-writable binaries write the add-in; lower suspicion when signer, path, command line, and parent all match the same recognized installer or managed integration. Signer trust alone never clears the placement.
  • If registry telemetry is available, did the writer create loader settings required for this add-in type?

    • Why: the alert is a file write; loader settings, when visible, show whether Office was configured to consume the add-in rather than merely store it.
    • Focus: same host.id and writer process.entity_id; check registry.path, registry.value, registry.data.type, and registry.data.strings for Office loader values pointing to the alerted file. $investigate_0
    • Implication: escalate when loader values reference the alerted file or directory; do not require registry corroboration when path, provenance, or writer evidence is already suspicious. Missing registry telemetry is unresolved, not benign.
  • Did Office later load the add-in or spawn follow-on activity from it?

    • Focus: later Office process.name values "WINWORD.EXE", "EXCEL.EXE", or "POWERPNT.EXE" on the same host.id, Office process.entity_id, child process.parent.entity_id, child process.executable, and, if library telemetry exists, dll.path matching the add-in.
      • $investigate_1
      • $investigate_2
    • Hint: missing library telemetry is unresolved, not benign; use those pivots and child process expansion from recovered Office instances as fallback execution evidence.
    • Implication: escalate when Office loads the add-in path, starts a child from the same session, or touches a payload dropped with the add-in; do not wait for library telemetry when file, writer, or loader evidence already warrants escalation.
  • If local evidence is suspicious or unresolved, what related host activity changes scope?

    • Focus: related alerts on the same host.id, especially document delivery, script execution, suspicious file writes, Office child processes, or additional persistence activity. $investigate_3
    • Implication: expand scope when related host alerts connect the add-in write to delivery, execution, credential access, or another persistence mechanism; do not close solely because related alerts are absent.
  • What disposition do the add-in mechanism, artifact identity, writer lineage, loader state, Office execution, and scope support?

    • Escalate on suspicious provenance, unexpected writer lineage, matching loader values, Office follow-on execution, or related host activity; close only when file, writer, provenance, loader state, and Office behavior align with one verified deployment or integration and no contradictions remain; preserve artifacts and escalate mixed or incomplete evidence.

False positive analysis

  • Managed Office add-in deployment, repair, and productivity, accessibility, or CRM first-use installs can place files in these paths. Close only when writer process.executable, process.command_line, signer process.code_signature.subject_name, parent process.parent.executable, final file.path, required loader state, provenance fields, later Office process.name, and child process.executable all align with one deployment or vendor workflow and no contradictory evidence remains. Use change or inventory records as corroboration, not as a telemetry substitute.
  • Before creating an exception, build it from the minimum current-case pattern: file.path, writer process.code_signature.subject_name, writer process.parent.executable, required loader-state pattern, and host.id or user.id scope. Avoid exceptions on Office startup directories, file extensions, or Office process names alone.

Response and remediation

  • If confirmed benign, reverse temporary containment and document the verified workflow with file.path, file.hash.sha256, writer process.executable, signer process.code_signature.subject_name, and any recovered loader-state evidence. Create any exception from that exact workflow pattern and scope it narrowly to the confirmed host or user cohort.
  • If suspicious but unconfirmed, preserve the alert export, the add-in file and hash from file.path and file.hash.sha256, writer process.entity_id and process.command_line, and any recovered loader-state, library-load, or child-process evidence before deleting anything. Apply reversible containment first, such as quarantining the add-in file, disabling the affected Office add-in path, or temporarily restricting Office execution on the host.
  • If confirmed malicious, isolate the host if its role can tolerate interruption, then terminate responsible Office or loader processes only after preserving their entity IDs, command lines, and the add-in file evidence. Remove the malicious add-in, clear associated Office loader configuration, restore affected Office add-in settings, and remediate the delivery path that introduced the file. Reset credentials only if the investigation also shows account misuse.
  • Review related hosts and users for the same file.path, file.hash.sha256, writer lineage, and loader-state pattern before eradication. For Word WLL cases, do not rely on the Office UI alone to prove the add-in is disabled; verify the file and supporting configuration are gone.
  • Post-incident hardening: restrict write access to Office startup directories and add-in loader locations, prefer signed managed add-in deployment, retain process/file plus registry or library telemetry needed to confirm later Office execution, and document adjacent variants such as Word WLL autoload abuse or registry-backed Office add-in loading in the case record.

References

Related rules

to-top