EXPLORE
← Back to Explore
elastichighTTP

Suspicious Microsoft HTML Application Child Process

Identifies Mshta.exe spawning a suspicious child process. This may indicate adversarial activity, as Mshta is often leveraged by adversaries to execute malicious scripts and evade detection.

Detection Query

process where host.os.type == "windows" and event.type == "start" and
  process.parent.name : "mshta.exe" and process.command_line != null and
  (
   process.name : (
       "cmd.exe", "powershell.exe", "certutil.exe", "bitsadmin.exe", "curl.exe", "msiexec.exe",
       "schtasks.exe", "reg.exe", "wscript.exe", "rundll32.exe"
   ) or
   process.executable : ("C:\\Users\\*\\*.exe", "\\Device\\HarddiskVolume*\\Users\\*\\*.exe")
  ) and
  not (process.name : "cmd.exe" and process.command_line : "*\\HP\\HP*HPUDC*") and
  not ?process.parent.command_line : "*\\HP\\*\\HPSolutionsPortal.hta*"

Author

Elastic

Created

2025/08/19

Data Sources

Elastic EndgameElastic DefendWindows Security Event LogsMicrosoft Defender XDRSysmonSentinelOneCrowdstrikeendgame-*logs-crowdstrike.fdr*logs-endpoint.events.process-*logs-m365_defender.event-*logs-sentinel_one_cloud_funnel.*logs-system.security*logs-windows.forwarded*logs-windows.sysmon_operational-*winlogbeat-*

Tags

Domain: EndpointOS: WindowsUse Case: Threat DetectionTactic: Defense EvasionData Source: Elastic EndgameData Source: Elastic DefendData Source: Windows Security Event LogsData Source: Microsoft Defender XDRData Source: SysmonData Source: SentinelOneData Source: CrowdstrikeResources: Investigation Guide
Raw Content
[metadata]
creation_date = "2025/08/19"
integration = ["endpoint", "windows", "system", "m365_defender", "sentinel_one_cloud_funnel", "crowdstrike"]
maturity = "production"
updated_date = "2026/04/29"

[rule]
author = ["Elastic"]
description = """
Identifies Mshta.exe spawning a suspicious child process. This may indicate adversarial activity, as Mshta is often
leveraged by adversaries to execute malicious scripts and evade detection.
"""
from = "now-9m"
index = [
    "endgame-*",
    "logs-crowdstrike.fdr*",
    "logs-endpoint.events.process-*",
    "logs-m365_defender.event-*",
    "logs-sentinel_one_cloud_funnel.*",
    "logs-system.security*",
    "logs-windows.forwarded*",
    "logs-windows.sysmon_operational-*",
    "winlogbeat-*",
]
language = "eql"
license = "Elastic License v2"
name = "Suspicious Microsoft HTML Application Child Process"
references = [
    "https://lolbas-project.github.io/lolbas/Binaries/Mshta/",
]
risk_score = 73
rule_id = "48e60a73-08e8-42aa-8f51-4ed92c64dbea"
severity = "high"
tags = [
    "Domain: Endpoint",
    "OS: Windows",
    "Use Case: Threat Detection",
    "Tactic: Defense Evasion",
    "Data Source: Elastic Endgame",
    "Data Source: Elastic Defend",
    "Data Source: Windows Security Event Logs",
    "Data Source: Microsoft Defender XDR",
    "Data Source: Sysmon",
    "Data Source: SentinelOne",
    "Data Source: Crowdstrike",
    "Resources: Investigation Guide",
]
timestamp_override = "event.ingested"
type = "eql"

query = '''
process where host.os.type == "windows" and event.type == "start" and
  process.parent.name : "mshta.exe" and process.command_line != null and
  (
   process.name : (
       "cmd.exe", "powershell.exe", "certutil.exe", "bitsadmin.exe", "curl.exe", "msiexec.exe",
       "schtasks.exe", "reg.exe", "wscript.exe", "rundll32.exe"
   ) or
   process.executable : ("C:\\Users\\*\\*.exe", "\\Device\\HarddiskVolume*\\Users\\*\\*.exe")
  ) and
  not (process.name : "cmd.exe" and process.command_line : "*\\HP\\HP*HPUDC*") and
  not ?process.parent.command_line : "*\\HP\\*\\HPSolutionsPortal.hta*"
'''

note = """## Triage and analysis

### Investigating Suspicious Microsoft HTML Application Child Process

#### Possible investigation steps

- What did mshta broker into the child process?
  - Focus: `process.name`, `process.executable`, `process.command_line`, and `process.parent.command_line`, separating interpreters, script engines, transfer tools, installers, persistence utilities, DLL proxy loaders, and user-profile binaries; for transfer, installer, or user-profile children, recover same-child file and network/DNS events. $investigate_0 $investigate_1
  - Implication: treat download, staging, persistence, scripting, or arbitrary user-space execution as high-risk proxy execution; narrow only when child arguments and mshta command line identify one recognized HTA-driven deployment, enrollment, support, or internal-portal flow. Missing file, network, or DNS telemetry is unresolved, not benign.

- Is the child binary identity consistent with its claimed role?
  - Focus: `process.executable`, `process.hash.sha256`, `process.pe.original_file_name`, `process.code_signature.subject_name`, and `process.code_signature.trusted`.
  - Implication: renamed, unsigned/untrusted, user-writable, newly seen, or PE-mismatched children strengthen proxy-execution; a trusted signer identifies the binary but does not clear the mshta chain.

- What source did mshta execute?
  - Focus: `process.parent.executable`, `process.parent.command_line`, `process.parent.code_signature.subject_name`, and `process.parent.code_signature.trusted`, checking expected System32/SysWOW64 mshta plus inline "vbscript:"/"javascript:", "script:" monikers, remote URLs, ADS syntax, UNC paths, temp/downloads, or "INetCache" sources.
  - Implication: inline scriptlets, remote/ADS-backed content, user-writable sources, obfuscation, or unexpected signer/path make mshta the likely delivery mechanism; internal HTAs, vendor packages, or deployment sources must still match the child workflow.

- What process launched mshta?
  - Why: recovering the mshta start event shows whether a browser, document, archive tool, installer, or management process initiated the chain.
  - Focus: process-start events on `host.id` where recovered `process.entity_id` equals alert `process.parent.entity_id`; if absent, use `host.id`, `process.parent.pid`, and a tight alert window, then inspect recovered `process.parent.executable` and `process.parent.command_line`. $investigate_2
  - Implication: Office, browser, archive, chat, script-host, or unexpected-service launchers indicate delivery or user-execution risk; software-distribution, support, enrollment, or portal launchers explain the chain only when they start the same flow on the same host cohort.

- Did the same mshta instance launch more suspicious children?
  - Focus: process-start events on `host.id` where `process.parent.entity_id` matches alert `process.parent.entity_id`; fall back to `host.id`, `process.parent.pid`, and a tight alert window; inspect child `process.name`, `process.executable`, and `process.command_line`. $investigate_3
  - Implication: same-instance fan-out into shells, transfer tools, schedulers, configuration changes, script hosts, or multiple user-space binaries widens response beyond one child; a single child stays narrow only if it matches the recovered benign workflow.

- Does the user, session, and host cohort fit that workflow?
  - Focus: `user.id`, `host.name`, `process.Ext.session_info.logon_type`, and recovered launcher `process.parent.executable`, using `host.id` as the stable host anchor.
  - Implication: standard-user, shared-workstation, unusual remote/service-session, or non-management-host context raises priority without matching workflow history; cohort fit is reassuring only when session type and launcher match the deployment, support, enrollment, or portal pattern.

- If local evidence is suspicious or unresolved, does alert history show broader proxy execution?
  - Focus: related alerts for `user.id` in 48 hours where the same child `process.executable` or mshta command pattern (`process.command_line`, `process.parent.command_line`) recurs in proxy-execution alerts. $investigate_4
  - Hint: if the user view is quiet or ambiguous, compare related alerts for `host.id` in 48 hours; quiet history does not clear unresolved local evidence. $investigate_5
  - Implication: escalate scope when the same delivery path or child-command pattern recurs across proxy-execution alerts; stay local only when the chain is resolved and related history fits the same recognized workflow.

- Escalate on suspicious child intent, identity mismatch, inline/remote/ADS mshta source, abnormal launcher, same-mshta fan-out, or broader proxy-execution history; close only when process evidence binds one exact recognized workflow on this host and no contradictions remain; preserve the process tree and escalate mixed or incomplete evidence.

### False positive analysis

- HP printer software (HPSolutionsPortal.hta) uses mshta to run a vendor portal that spawns cmd.exe for UDC telemetry cleanup and rundll32.exe for printui operations. The rule excludes the UDC cmd.exe pattern cross-source and the parent HTA path when `process.parent.command_line` is available. On sources without parent command_line (CrowdStrike, SecurityLog), these alerts still fire; confirm by matching `process.command_line` to HP ProgramData paths or printui.dll printer-name arguments before closing.
- Treat software distribution, device enrollment, remote support, or internal HTA portals as benign candidates only after process telemetry proves the same chain. Confirm child `process.executable`, `process.command_line`, `process.hash.sha256`, signer, mshta `process.parent.command_line`, recovered launcher executable/command line, and `user.id` plus `host.id` cohort. Use change records, support tickets, asset-role inventories, or prior alerts only as corroboration; never close unresolved local process evidence on recurrence or workflow labels alone.
- Do not close on partial matches. Inline scriptlets, remote URLs, ADS syntax, user-profile child executables, unexpected launchers, or same-mshta fan-out contradict a benign HTA workflow unless process telemetry and outside confirmation verify that exact activity.
- Build exceptions from the minimum confirmed pattern: recovered launcher `process.parent.executable`, mshta `process.parent.command_line`, child `process.executable` plus `process.command_line`, and stable `user.id` or `host.id` cohort. Avoid exceptions on mshta alone, `process.name` alone, or `user.name` alone.

### Response and remediation

- If confirmed benign, record the child `process.command_line`, mshta `process.parent.command_line`, recovered launcher `process.parent.executable`, `user.id`, and `host.id` evidence that validated the workflow, then reverse temporary containment. Create an exception only for that narrow process pattern, using prior alerts as stability evidence when available.
- If suspicious but unconfirmed, preserve the alert record, process tree, child `process.entity_id`, alert `process.parent.entity_id`, child and mshta command lines, child `process.hash.sha256`, signer evidence, recovered launcher, `process.Ext.session_info.logon_type`, and related-alert results before containment. Apply reversible controls first, such as blocking the exact HTA URL or share visible in `process.parent.command_line`, restricting the child hash or path, or increasing monitoring on the affected `host.id` and `user.id`.
- If confirmed malicious, isolate the host or terminate the mshta/child process only after recording the child and mshta entity IDs, command lines, launcher, hash, signer, user, and host evidence. If endpoint response is unavailable, hand off that preserved evidence to the team that can contain the endpoint or affected account.
- After containment, block confirmed malicious child hashes, child executable paths, and exact mshta command-line sources, then remove only scripts, binaries, scheduled tasks, or persistence changes proven to belong to this chain. Remediate the delivery vector that started mshta, such as browser download, attachment, archive extraction, remote share, software package, or compromised management workflow.
- Post-incident hardening: restrict mshta use for users and hosts that do not need HTA execution, package legitimate HTA workflows through signed deployment tooling, and record adjacent variants such as inline "vbscript:" / "javascript:", remote "script:" monikers, ADS-backed HTAs, and INetCache retrievals for future triage.
"""

setup = """## Setup

This 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.

Setup instructions: https://ela.st/install-elastic-defend

### Additional data sources

This rule also supports the following third-party data sources. For setup instructions, refer to the links below:

- [CrowdStrike](https://ela.st/crowdstrike-integration)
- [Microsoft Defender XDR](https://ela.st/m365-defender)
- [SentinelOne Cloud Funnel](https://ela.st/sentinel-one-cloud-funnel)
- [Sysmon Event ID 1 - Process Creation](https://ela.st/sysmon-event-1-setup)
- [Windows Process Creation Logs](https://ela.st/audit-process-creation)
"""

[rule.investigation_fields]
field_names = [
    "@timestamp",
    "host.name",
    "host.id",
    "user.name",
    "user.id",
    "process.entity_id",
    "process.pid",
    "process.executable",
    "process.command_line",
    "process.Ext.session_info.logon_type",
    "process.pe.original_file_name",
    "process.hash.sha256",
    "process.code_signature.trusted",
    "process.parent.entity_id",
    "process.parent.command_line",
]

[transform]

[[transform.investigate]]
label = "File events for the child process"
description = ""
providers = [
  [
    { excluded = false, field = "event.category", queryType = "phrase", value = "file", valueType = "string" },
    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
  ]
]
relativeFrom = "now-1h"
relativeTo = "now"

[[transform.investigate]]
label = "Network and DNS events for the child process"
description = ""
providers = [
  [
    { excluded = false, field = "event.category", queryType = "phrase", value = "network", valueType = "string" },
    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
  ],
  [
    { excluded = false, field = "event.category", queryType = "phrase", value = "dns", valueType = "string" },
    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.entity_id}}", valueType = "string" }
  ]
]
relativeFrom = "now-1h"
relativeTo = "now"

[[transform.investigate]]
label = "Mshta parent process event"
description = ""
providers = [
  [
    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
    { excluded = false, field = "process.entity_id", queryType = "phrase", value = "{{process.parent.entity_id}}", valueType = "string" }
  ]
]
relativeFrom = "now-1h"
relativeTo = "now"

[[transform.investigate]]
label = "Process events launched by the same mshta instance"
description = ""
providers = [
  [
    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
    { excluded = false, field = "process.parent.entity_id", queryType = "phrase", value = "{{process.parent.entity_id}}", valueType = "string" }
  ]
]
relativeFrom = "now-1h"
relativeTo = "now"

[[transform.investigate]]
label = "Alerts associated with the user"
description = ""
providers = [
  [
    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
    { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
  ]
]
relativeFrom = "now-48h/h"
relativeTo = "now"

[[transform.investigate]]
label = "Alerts associated with the host"
description = ""
providers = [
  [
    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
  ]
]
relativeFrom = "now-48h/h"
relativeTo = "now"

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1218"
name = "System Binary Proxy Execution"
reference = "https://attack.mitre.org/techniques/T1218/"

[[rule.threat.technique.subtechnique]]
id = "T1218.005"
name = "Mshta"
reference = "https://attack.mitre.org/techniques/T1218/005/"

[[rule.threat.technique.subtechnique]]
id = "T1218.007"
name = "Msiexec"
reference = "https://attack.mitre.org/techniques/T1218/007/"

[[rule.threat.technique.subtechnique]]
id = "T1218.011"
name = "Rundll32"
reference = "https://attack.mitre.org/techniques/T1218/011/"

[rule.threat.tactic]
id = "TA0005"
name = "Defense Evasion"
reference = "https://attack.mitre.org/tactics/TA0005/"

[[rule.threat]]
framework = "MITRE ATT&CK"

[[rule.threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"

[[rule.threat.technique.subtechnique]]
id = "T1059.001"
name = "PowerShell"
reference = "https://attack.mitre.org/techniques/T1059/001/"

[[rule.threat.technique.subtechnique]]
id = "T1059.003"
name = "Windows Command Shell"
reference = "https://attack.mitre.org/techniques/T1059/003/"

[rule.threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"