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, anduser.idonhost.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.
- Focus: alert
-
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, andfile.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, andprocess.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.
- Focus: writer
-
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.idand writerprocess.entity_id; checkregistry.path,registry.value,registry.data.type, andregistry.data.stringsfor 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.namevalues "WINWORD.EXE", "EXCEL.EXE", or "POWERPNT.EXE" on the samehost.id, Officeprocess.entity_id, childprocess.parent.entity_id, childprocess.executable, and, if library telemetry exists,dll.pathmatching 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.
- Focus: later Office
-
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.
- Focus: related alerts on the same
-
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, signerprocess.code_signature.subject_name, parentprocess.parent.executable, finalfile.path, required loader state, provenance fields, later Officeprocess.name, and childprocess.executableall 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, writerprocess.code_signature.subject_name, writerprocess.parent.executable, required loader-state pattern, andhost.idoruser.idscope. 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, writerprocess.executable, signerprocess.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.pathandfile.hash.sha256, writerprocess.entity_idandprocess.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
- Creation of a Hidden Local User Account
- Persistence via Hidden Run Key Detected
- Persistence via TelemetryController Scheduled Task Hijack
- Suspicious ImagePath Service Creation
- Suspicious Startup Shell Folder Modification