ESXi Host Prepared for an Unsigned Install

Detects three changes on the same ESXi host within 1 hour: SSH enabled, ExecInstalledOnly turned off, and a VIB install with -f or --force and --no-sig-check. Together they open a remote shell, allow unsigned code to run, and bypass VIB signature checks. That sequence prepares the host to receive and run a package the normal controls would reject.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/09/30"
  3integration = ["vsphere"]
  4maturity = "production"
  5updated_date = "2026/09/30"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Detects three changes on the same ESXi host within 1 hour: SSH enabled, ExecInstalledOnly turned off, and a
 11VIB install with `-f` or `--force` and `--no-sig-check`. Together they open a remote shell, allow unsigned code to
 12run, and bypass VIB signature checks. That sequence prepares the host to receive and run a package the normal
 13controls would reject.
 14"""
 15false_positives = [
 16    """
 17    A documented maintenance window can enable SSH, relax ExecInstalledOnly, and force-install a vendor VIB on the
 18    same host. Confirm the change ticket and the VIB name before treating the sequence as malicious.
 19    """,
 20]
 21from = "now-1h"
 22language = "esql"
 23license = "Elastic License v2"
 24name = "ESXi Host Prepared for an Unsigned Install"
 25note = """## Triage and analysis
 26
 27### Investigating ESXi Host Prepared for an Unsigned Install
 28
 29The rule counts three behaviors on one host and alerts only when all three occur in the same 1-hour window.
 30SSH enablement is hostsvc/enable_ssh or the hostd sentence SSH access has been enabled. ExecInstalledOnly is
 31the kernel setting set to FALSE, or the advanced setting /User/ExecInstalledOnly set with -i 0. The install
 32is vib install with the -f or --force switch and --no-sig-check.
 33
 34#### Possible investigation steps
 35
 36- Read Esql.message_values and confirm each count is at least 1.
 37- Compare Esql.span_minutes with the change window. The three lines should sit close together.
 38- On the host, run esxcli software vib list and look for a VIB that was not part of the approved image.
 39- Check esxcli system settings kernel list -o execInstalledOnly and whether SSH is still enabled.
 40
 41### False positive analysis
 42
 43Vendor recovery and lab image builds sometimes force a VIB while SSH is open. The VIB name and the ticket should match.
 44
 45### Response and remediation
 46
 47- If the change was not approved, remove the unexpected VIB and set ExecInstalledOnly back to TRUE.
 48- Disable SSH when remote shell access is no longer required.
 49- Preserve shell.log and hostd.log for the host before rotating credentials.
 50"""
 51references = [
 52    "https://lolesxi-project.github.io/LOLESXi/#",
 53    "https://blogs.vmware.com/security/2022/10/esxi-targeting-ransomware-tactics-and-techniques-part-2.html",
 54    "https://detect.fyi/vmware-esxi-logging-detection-opportunities-4fb56411ec21",
 55]
 56setup = """## Setup
 57
 58This rule requires ESXi host logs collected by the Elastic vSphere integration: https://www.elastic.co/docs/reference/integrations/vsphere
 59"""
 60risk_score = 99
 61rule_id = "12c56e4a-8d36-5dab-a5b6-5322db31c901"
 62severity = "critical"
 63tags = [
 64    "Domain: Endpoint",
 65    "Data Source: VMware vSphere",
 66    "Use Case: Threat Detection",
 67    "Tactic: Defense Evasion",
 68    "Tactic: Lateral Movement",
 69    "Resources: Investigation Guide",
 70    "Rule Type: ES|QL",
 71    "Platform: VMware ESXi",
 72]
 73timestamp_override = "event.ingested"
 74type = "esql"
 75
 76query = '''
 77FROM logs-vsphere.log-*
 78| WHERE data_stream.dataset == "vsphere.log" AND event.module == "vsphere" and host.ip is not null
 79| EVAL Esql.message_lower = TO_LOWER(message)
 80| EVAL
 81    Esql.ssh_enabled = CASE(
 82      Esql.message_lower LIKE "*ssh access has been enabled*" OR Esql.message_lower LIKE "*hostsvc/enable_ssh*",
 83      1, 0
 84    ),
 85    Esql.exec_installed_only_disabled = CASE(
 86      Esql.message_lower LIKE "*execinstalledonly*" AND (
 87        Esql.message_lower LIKE "*false*" OR Esql.message_lower LIKE "* -i 0*" OR Esql.message_lower LIKE "* -v 0*"
 88      ),
 89      1, 0
 90    ),
 91    Esql.vib_force_install = CASE(
 92      Esql.message_lower LIKE "*vib install*" AND (
 93        Esql.message_lower LIKE "* -f *" OR Esql.message_lower LIKE "* -f"
 94        OR Esql.message_lower LIKE "* --force *" OR Esql.message_lower LIKE "* --force"
 95      ),
 96      1, 0
 97    )
 98| WHERE Esql.ssh_enabled == 1 OR Esql.exec_installed_only_disabled == 1 OR Esql.vib_force_install == 1
 99| STATS
100    Esql.ssh_enabled_count = SUM(Esql.ssh_enabled),
101    Esql.exec_installed_only_disabled_count = SUM(Esql.exec_installed_only_disabled),
102    Esql.vib_force_install_count = SUM(Esql.vib_force_install),
103    Esql.message_values = VALUES(message),
104    Esql.log_file_path_values = VALUES(vsphere.log.file.path),
105    Esql.first_seen = MIN(@timestamp),
106    Esql.last_seen = MAX(@timestamp)
107  BY host.ip
108| WHERE Esql.ssh_enabled_count > 0
109    AND Esql.exec_installed_only_disabled_count > 0
110    AND Esql.vib_force_install_count > 0
111| KEEP host.ip, Esql.ssh_enabled_count, Esql.exec_installed_only_disabled_count, Esql.vib_force_install_count,
112    Esql.message_values, Esql.log_file_path_values, Esql.first_seen, Esql.last_seen
113'''
114
115[[rule.threat]]
116framework = "MITRE ATT&CK"
117[[rule.threat.technique]]
118id = "T1562"
119name = "Impair Defenses"
120reference = "https://attack.mitre.org/techniques/T1562/"
121[[rule.threat.technique.subtechnique]]
122id = "T1562.001"
123name = "Disable or Modify Tools"
124reference = "https://attack.mitre.org/techniques/T1562/001/"
125
126[[rule.threat.technique]]
127id = "T1553"
128name = "Subvert Trust Controls"
129reference = "https://attack.mitre.org/techniques/T1553/"
130[[rule.threat.technique.subtechnique]]
131id = "T1553.006"
132name = "Code Signing Policy Modification"
133reference = "https://attack.mitre.org/techniques/T1553/006/"
134
135[rule.threat.tactic]
136id = "TA0005"
137name = "Defense Evasion"
138reference = "https://attack.mitre.org/tactics/TA0005/"
139
140[[rule.threat]]
141framework = "MITRE ATT&CK"
142[[rule.threat.technique]]
143id = "T1021"
144name = "Remote Services"
145reference = "https://attack.mitre.org/techniques/T1021/"
146[[rule.threat.technique.subtechnique]]
147id = "T1021.004"
148name = "SSH"
149reference = "https://attack.mitre.org/techniques/T1021/004/"
150
151[rule.threat.tactic]
152id = "TA0008"
153name = "Lateral Movement"
154reference = "https://attack.mitre.org/tactics/TA0008/"
155
156[rule.investigation_fields]
157field_names = [
158    "host.ip",
159    "Esql.ssh_enabled_count",
160    "Esql.exec_installed_only_disabled_count",
161    "Esql.vib_force_install_count",
162    "Esql.message_values",
163    "Esql.log_file_path_values",
164    "Esql.first_seen",
165    "Esql.last_seen",
166]

Triage and analysis

Investigating ESXi Host Prepared for an Unsigned Install

The rule counts three behaviors on one host and alerts only when all three occur in the same 1-hour window. SSH enablement is hostsvc/enable_ssh or the hostd sentence SSH access has been enabled. ExecInstalledOnly is the kernel setting set to FALSE, or the advanced setting /User/ExecInstalledOnly set with -i 0. The install is vib install with the -f or --force switch and --no-sig-check.

Possible investigation steps

  • Read Esql.message_values and confirm each count is at least 1.
  • Compare Esql.span_minutes with the change window. The three lines should sit close together.
  • On the host, run esxcli software vib list and look for a VIB that was not part of the approved image.
  • Check esxcli system settings kernel list -o execInstalledOnly and whether SSH is still enabled.

False positive analysis

Vendor recovery and lab image builds sometimes force a VIB while SSH is open. The VIB name and the ticket should match.

Response and remediation

  • If the change was not approved, remove the unexpected VIB and set ExecInstalledOnly back to TRUE.
  • Disable SSH when remote shell access is no longer required.
  • Preserve shell.log and hostd.log for the host before rotating credentials.

References

Related rules

to-top