Script Execution via Microsoft HTML Application

Identifies the execution of scripts via HTML applications using Windows utilities rundll32.exe or mshta.exe. Adversaries may bypass process and/or signature-based defenses by proxying execution of malicious content with signed binaries.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2020/09/09"
  3integration = ["endpoint", "windows", "system", "sentinel_one_cloud_funnel", "m365_defender", "crowdstrike"]
  4maturity = "production"
  5updated_date = "2026/04/30"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Identifies the execution of scripts via HTML applications using Windows utilities rundll32.exe or mshta.exe. Adversaries
 11may bypass process and/or signature-based defenses by proxying execution of malicious content with signed binaries.
 12"""
 13from = "now-9m"
 14index = [
 15    "logs-m365_defender.event-*",
 16    "logs-sentinel_one_cloud_funnel.*",
 17    "logs-system.security*",
 18    "logs-windows.forwarded*",
 19    "logs-windows.sysmon_operational-*",
 20    "winlogbeat-*",
 21    "logs-endpoint.events.process-*",
 22    "logs-crowdstrike.fdr*",
 23    "endgame-*"
 24]
 25language = "eql"
 26license = "Elastic License v2"
 27name = "Script Execution via Microsoft HTML Application"
 28risk_score = 73
 29rule_id = "181f6b23-3799-445e-9589-0018328a9e46"
 30severity = "high"
 31tags = [
 32    "Domain: Endpoint",
 33    "OS: Windows",
 34    "Use Case: Threat Detection",
 35    "Tactic: Defense Evasion",
 36    "Data Source: Windows Security Event Logs",
 37    "Data Source: Sysmon",
 38    "Data Source: SentinelOne",
 39    "Data Source: Microsoft Defender XDR",
 40    "Data Source: Elastic Defend",
 41    "Data Source: Crowdstrike",
 42    "Resources: Investigation Guide",
 43    "Data Source: Elastic Endgame",
 44]
 45timestamp_override = "event.ingested"
 46type = "eql"
 47
 48query = '''
 49process where host.os.type == "windows" and event.type == "start" and
 50 process.name : ("rundll32.exe", "mshta.exe") and
 51  (
 52     (process.command_line :
 53        (
 54        "*script*eval(*",
 55         "*script*GetObject*",
 56         "*.regread(*",
 57         "*WScript.Shell*",
 58         "*.run(*",
 59         "*).Exec()*",
 60         "*mshta*http*",
 61         "*mshtml*RunHTMLApplication*",
 62         "*mshtml*,#135*",
 63         "*StrReverse*",
 64         "*.RegWrite*",
 65         /* Issue #379 */
 66         "*window.close(*",
 67         "* Chr(*"
 68         )
 69     and not ?process.parent.executable :
 70                  ("?:\\Program Files (x86)\\Citrix\\System32\\wfshell.exe",
 71                   "?:\\Program Files (x86)\\Microsoft Office\\Office*\\MSACCESS.EXE",
 72                   "?:\\Program Files\\Quokka.Works GTInstaller\\GTInstaller.exe")
 73     ) or
 74
 75    (process.name : "mshta.exe" and
 76     not process.command_line : ("*.hta*", "*.htm*", "-Embedding") and ?process.args_count >=2) or
 77
 78     /* Execution of HTA file downloaded from the internet */
 79     (process.name : "mshta.exe" and process.command_line : "*\\Users\\*\\Downloads\\*.hta*") or
 80
 81     /* Execution of HTA file from archive */
 82     (process.name : "mshta.exe" and
 83      process.args : ("?:\\Users\\*\\Temp\\7z*", "?:\\Users\\*\\Temp\\Rar$*", "?:\\Users\\*\\Temp\\Temp?_*", "?:\\Users\\*\\Temp\\BNZ.*"))
 84   )
 85'''
 86
 87note = """## Triage and analysis
 88
 89### Investigating Script Execution via Microsoft HTML Application
 90
 91#### Possible investigation steps
 92
 93- Which HTML-application proxy path did the alert capture?
 94  - Why: proxy path determines the containment target.
 95  - Focus: `process.name`, `process.command_line`, and `process.args_count`: ".hta", ".htm", "vbscript:", "javascript:", "GetObject("script:")", "mshtml,RunHTMLApplication", "mshtml,#135", "http", "WScript.Shell", "StrReverse", "window.close(", or "Chr(".
 96  - Implication: escalate on inline script, remote retrieval, obfuscation, "RunHTMLApplication", archive/temp execution, or non-HTA "mshta.exe"; lower concern only for one stable internal HTA/HTM path with no inline script, remote locator, or obfuscation.
 97
 98- Is the proxy binary a genuine Microsoft LOLBin or a masqueraded executable?
 99  - Focus: `process.executable`, `process.pe.original_file_name`, `process.hash.sha256`, `process.code_signature.subject_name`, and `process.code_signature.trusted`.
100  - Implication: escalate when "mshta.exe" or "rundll32.exe" runs from a user-writable or non-Windows path, has a mismatched original filename, or lacks a trusted Microsoft signature; canonical Microsoft identity lowers masquerade risk but does not clear suspicious arguments.
101
102- What parent and user context explain the launch?
103  - Focus: `process.parent.executable`, `process.parent.command_line`, `user.id`, and `host.id`.
104  - Implication: escalate when the parent is Office, a browser, archive utility, script host, user-writable executable, or a chain outside the rule's excluded parents; lower concern when the same parent, user cohort, and host cohort repeatedly launch the same recognized HTA workflow.
105
106- What referenced HTA, scriptlet, URL, or path can be recovered?
107  - Focus: `process.command_line`, `process.args`, and `process.working_directory`: literal HTA/HTM path, scriptlet URL, remote locator, archive/temp marker, or relative path; recover same-process file and network/DNS events when artifact or remote locator evidence exists. $investigate_0 $investigate_1
108  - Implication: escalate when the locator points to Downloads, Temp, archive extraction, external URLs, scriptlet retrieval, alternate data stream-like syntax, or a single-user path; lower concern only for the same stable internal path from the same recognized workflow. Missing file, network, or DNS telemetry is unresolved, not benign.
109
110- Did the proxy spawn follow-on code or payload execution?
111  - Focus: child starts on `host.id` where `process.parent.entity_id` equals alert `process.entity_id`; inspect child `process.executable`, `process.command_line`, `process.pe.original_file_name`, `process.code_signature.subject_name`, and `process.code_signature.trusted`. $investigate_2
112  - Hint: if `process.entity_id` is absent, use `host.id` + `process.pid` + the tight alert window as a weaker fallback; treat PID reuse as unresolved ambiguity.
113  - Implication: escalate when the proxy spawns shells, PowerShell, script hosts, "regsvr32.exe", another "rundll32.exe", unsigned payloads, or tooling unrelated to the parent workflow; lower concern when child activity stays within the same recognized signed application flow.
114
115- If evidence remains suspicious or incomplete, is it isolated?
116  - Focus: `user.id`, `host.id`, stable `process.command_line` fragments, child `process.executable`, and child `process.command_line` recovered above. $investigate_3 $investigate_4
117  - Implication: broaden scope when the same user, host, command fragment, or child process repeats across alerts or other hosts; keep scope local only when isolated and aligned with one recognized workflow.
118
119- Escalate on proxy script execution, masquerade, suspicious lineage, external/temporary sourcing, follow-on payloads, or recurrence; close only when command intent, binary identity, lineage, locator, child behavior, and scope align with one recognized internal HTA/HTM workflow; preserve artifacts and escalate when evidence is mixed or incomplete.
120
121### False positive analysis
122
123- Legacy internal HTA applications or support tools may use "mshta.exe" when identity, intent, and context align: canonical Microsoft `process.executable`, stable `process.parent.executable`, repeated `process.command_line` for one internal HTA/HTM path, consistent `user.id`/`host.id` cohort, and no child branching into shells or script hosts. If inventory, owner, or change records exist, require alignment with this telemetry; otherwise require recurrence of the same stable process pattern across prior alerts from this rule for the same cohort.
124- Vendor installers or deployment tools can trigger archive/temp HTA patterns when parent executable, signer context, command line, and bounded child chain match the same recognized package workflow. Do not close on parent name alone; contradictory locator, child process, user/host scope, or signer evidence stays suspicious. Exceptions should use the minimum confirmed pattern, such as `process.parent.executable` + stable `process.command_line` fragment + `host.id` or `user.id`, not `process.name`.
125
126### Response and remediation
127
128- If confirmed benign:
129  - Reverse temporary containment and record the parent workflow, `process.command_line`, extracted locator/path, `user.id`, `host.id`, and recurrence or business records that confirmed the recognized application path. Build exceptions only from the minimum stable workflow pattern, not from "mshta.exe" or "rundll32.exe" alone.
130- If suspicious but unconfirmed:
131  - Preserve the alert event export, process tree, `process.entity_id`, `process.pid`, `process.command_line`, `process.args`, parent lineage, user/host context, recovered child process events, and literal URLs or paths extracted from the command line before cleanup.
132  - Apply reversible containment tied to the findings, such as temporary destination restrictions for remote locators, child-process blocking, or heightened monitoring on the affected `host.id` and `user.id`; use host isolation only when child-process or staging evidence indicates active payload execution and host criticality permits it.
133- If confirmed malicious:
134  - Isolate the host or contain the affected identity after preserving the process and child-process evidence that established malicious execution. Terminate the proxy and spawned payload processes only after recording their identifiers and command lines.
135  - Block confirmed malicious command-line locators, child binaries, domains, and addresses identified during triage, then review other hosts and users for the same command fragment or child-process pattern before eradication.
136  - Remove the malicious HTA, scriptlet, archive-extracted payload, or staged child artifacts identified during investigation; remediate the parent document, browser, archive, or script delivery path; investigate credential exposure if follow-on behavior suggests collection or lateral movement.
137- Post-incident hardening:
138  - Restrict or monitor "mshta.exe" and unusual "rundll32.exe" script-execution paths where the business does not require them.
139  - Retain process telemetry for these binaries and record any missing artifact, library, or destination visibility that limited the case so future triage can account for the gap.
140"""
141
142setup = """## Setup
143
144This 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.
145
146Setup instructions: https://ela.st/install-elastic-defend
147
148### Additional data sources
149
150This rule also supports the following third-party data sources. For setup instructions, refer to the links below:
151
152- [CrowdStrike](https://ela.st/crowdstrike-integration)
153- [Microsoft Defender XDR](https://ela.st/m365-defender)
154- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
155- [Sysmon Event ID 1 - Process Creation](https://ela.st/sysmon-event-1-setup)
156- [Windows Process Creation Logs](https://ela.st/audit-process-creation)
157"""
158
159[rule.investigation_fields]
160field_names = [
161    "@timestamp",
162    "host.name",
163    "host.id",
164    "user.name",
165    "user.id",
166    "process.entity_id",
167    "process.code_signature.subject_name",
168    "process.executable",
169    "process.command_line",
170    "process.args",
171    "process.pe.original_file_name",
172    "process.code_signature.trusted",
173    "process.parent.entity_id",
174    "process.parent.executable",
175    "process.parent.command_line",
176]
177
178[transform]
179
180[[transform.investigate]]
181label = "File events for the same proxy instance"
182description = ""
183providers = [
184  [
185    { excluded = false, field = "event.category", queryType = "phrase", value = "file", valueType = "string" },
186    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
187    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
188  ]
189]
190relativeFrom = "now-1h"
191relativeTo = "now"
192
193[[transform.investigate]]
194label = "Network and DNS events for the same proxy instance"
195description = ""
196providers = [
197  [
198    { excluded = false, field = "event.category", queryType = "phrase", value = "network", valueType = "string" },
199    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
200    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
201  ],
202  [
203    { excluded = false, field = "event.category", queryType = "phrase", value = "dns", valueType = "string" },
204    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
205    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
206  ]
207]
208relativeFrom = "now-1h"
209relativeTo = "now"
210
211[[transform.investigate]]
212label = "Child process events for the same proxy instance"
213description = ""
214providers = [
215  [
216    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
217    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
218    { excluded = false, field = "process.parent.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
219  ]
220]
221relativeFrom = "now-1h"
222relativeTo = "now"
223
224[[transform.investigate]]
225label = "Alerts associated with the user"
226description = ""
227providers = [
228  [
229    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
230    { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
231  ]
232]
233relativeFrom = "now-48h/h"
234relativeTo = "now"
235
236[[transform.investigate]]
237label = "Alerts associated with the host"
238description = ""
239providers = [
240  [
241    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
242    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
243  ]
244]
245relativeFrom = "now-48h/h"
246relativeTo = "now"
247
248[[rule.threat]]
249framework = "MITRE ATT&CK"
250
251[[rule.threat.technique]]
252id = "T1218"
253name = "System Binary Proxy Execution"
254reference = "https://attack.mitre.org/techniques/T1218/"
255
256[[rule.threat.technique.subtechnique]]
257id = "T1218.005"
258name = "Mshta"
259reference = "https://attack.mitre.org/techniques/T1218/005/"
260
261[[rule.threat.technique.subtechnique]]
262id = "T1218.011"
263name = "Rundll32"
264reference = "https://attack.mitre.org/techniques/T1218/011/"
265
266[rule.threat.tactic]
267id = "TA0005"
268name = "Defense Evasion"
269reference = "https://attack.mitre.org/tactics/TA0005/"
270
271[[rule.threat]]
272framework = "MITRE ATT&CK"
273
274[[rule.threat.technique]]
275id = "T1059"
276name = "Command and Scripting Interpreter"
277reference = "https://attack.mitre.org/techniques/T1059/"
278
279[[rule.threat.technique.subtechnique]]
280id = "T1059.005"
281name = "Visual Basic"
282reference = "https://attack.mitre.org/techniques/T1059/005/"
283
284[[rule.threat.technique.subtechnique]]
285id = "T1059.007"
286name = "JavaScript"
287reference = "https://attack.mitre.org/techniques/T1059/007/"
288
289[rule.threat.tactic]
290id = "TA0002"
291name = "Execution"
292reference = "https://attack.mitre.org/tactics/TA0002/"

Triage and analysis

Investigating Script Execution via Microsoft HTML Application

Possible investigation steps

  • Which HTML-application proxy path did the alert capture?

    • Why: proxy path determines the containment target.
    • Focus: process.name, process.command_line, and process.args_count: ".hta", ".htm", "vbscript:", "javascript:", "GetObject("script:")", "mshtml,RunHTMLApplication", "mshtml,#135", "http", "WScript.Shell", "StrReverse", "window.close(", or "Chr(".
    • Implication: escalate on inline script, remote retrieval, obfuscation, "RunHTMLApplication", archive/temp execution, or non-HTA "mshta.exe"; lower concern only for one stable internal HTA/HTM path with no inline script, remote locator, or obfuscation.
  • Is the proxy binary a genuine Microsoft LOLBin or a masqueraded executable?

    • Focus: process.executable, process.pe.original_file_name, process.hash.sha256, process.code_signature.subject_name, and process.code_signature.trusted.
    • Implication: escalate when "mshta.exe" or "rundll32.exe" runs from a user-writable or non-Windows path, has a mismatched original filename, or lacks a trusted Microsoft signature; canonical Microsoft identity lowers masquerade risk but does not clear suspicious arguments.
  • What parent and user context explain the launch?

    • Focus: process.parent.executable, process.parent.command_line, user.id, and host.id.
    • Implication: escalate when the parent is Office, a browser, archive utility, script host, user-writable executable, or a chain outside the rule's excluded parents; lower concern when the same parent, user cohort, and host cohort repeatedly launch the same recognized HTA workflow.
  • What referenced HTA, scriptlet, URL, or path can be recovered?

    • Focus: process.command_line, process.args, and process.working_directory: literal HTA/HTM path, scriptlet URL, remote locator, archive/temp marker, or relative path; recover same-process file and network/DNS events when artifact or remote locator evidence exists. $investigate_0 $investigate_1
    • Implication: escalate when the locator points to Downloads, Temp, archive extraction, external URLs, scriptlet retrieval, alternate data stream-like syntax, or a single-user path; lower concern only for the same stable internal path from the same recognized workflow. Missing file, network, or DNS telemetry is unresolved, not benign.
  • Did the proxy spawn follow-on code or payload execution?

    • Focus: child starts on host.id where process.parent.entity_id equals alert process.entity_id; inspect child process.executable, process.command_line, process.pe.original_file_name, process.code_signature.subject_name, and process.code_signature.trusted. $investigate_2
    • Hint: if process.entity_id is absent, use host.id + process.pid + the tight alert window as a weaker fallback; treat PID reuse as unresolved ambiguity.
    • Implication: escalate when the proxy spawns shells, PowerShell, script hosts, "regsvr32.exe", another "rundll32.exe", unsigned payloads, or tooling unrelated to the parent workflow; lower concern when child activity stays within the same recognized signed application flow.
  • If evidence remains suspicious or incomplete, is it isolated?

    • Focus: user.id, host.id, stable process.command_line fragments, child process.executable, and child process.command_line recovered above. $investigate_3 $investigate_4
    • Implication: broaden scope when the same user, host, command fragment, or child process repeats across alerts or other hosts; keep scope local only when isolated and aligned with one recognized workflow.
  • Escalate on proxy script execution, masquerade, suspicious lineage, external/temporary sourcing, follow-on payloads, or recurrence; close only when command intent, binary identity, lineage, locator, child behavior, and scope align with one recognized internal HTA/HTM workflow; preserve artifacts and escalate when evidence is mixed or incomplete.

False positive analysis

  • Legacy internal HTA applications or support tools may use "mshta.exe" when identity, intent, and context align: canonical Microsoft process.executable, stable process.parent.executable, repeated process.command_line for one internal HTA/HTM path, consistent user.id/host.id cohort, and no child branching into shells or script hosts. If inventory, owner, or change records exist, require alignment with this telemetry; otherwise require recurrence of the same stable process pattern across prior alerts from this rule for the same cohort.
  • Vendor installers or deployment tools can trigger archive/temp HTA patterns when parent executable, signer context, command line, and bounded child chain match the same recognized package workflow. Do not close on parent name alone; contradictory locator, child process, user/host scope, or signer evidence stays suspicious. Exceptions should use the minimum confirmed pattern, such as process.parent.executable + stable process.command_line fragment + host.id or user.id, not process.name.

Response and remediation

  • If confirmed benign:
    • Reverse temporary containment and record the parent workflow, process.command_line, extracted locator/path, user.id, host.id, and recurrence or business records that confirmed the recognized application path. Build exceptions only from the minimum stable workflow pattern, not from "mshta.exe" or "rundll32.exe" alone.
  • If suspicious but unconfirmed:
    • Preserve the alert event export, process tree, process.entity_id, process.pid, process.command_line, process.args, parent lineage, user/host context, recovered child process events, and literal URLs or paths extracted from the command line before cleanup.
    • Apply reversible containment tied to the findings, such as temporary destination restrictions for remote locators, child-process blocking, or heightened monitoring on the affected host.id and user.id; use host isolation only when child-process or staging evidence indicates active payload execution and host criticality permits it.
  • If confirmed malicious:
    • Isolate the host or contain the affected identity after preserving the process and child-process evidence that established malicious execution. Terminate the proxy and spawned payload processes only after recording their identifiers and command lines.
    • Block confirmed malicious command-line locators, child binaries, domains, and addresses identified during triage, then review other hosts and users for the same command fragment or child-process pattern before eradication.
    • Remove the malicious HTA, scriptlet, archive-extracted payload, or staged child artifacts identified during investigation; remediate the parent document, browser, archive, or script delivery path; investigate credential exposure if follow-on behavior suggests collection or lateral movement.
  • Post-incident hardening:
    • Restrict or monitor "mshta.exe" and unusual "rundll32.exe" script-execution paths where the business does not require them.
    • Retain process telemetry for these binaries and record any missing artifact, library, or destination visibility that limited the case so future triage can account for the gap.

Related rules

to-top