Untrusted Driver Loaded

Identifies an untrusted driver loaded by the Windows kernel. Adversaries may modify code signing policies to enable execution of unsigned or self-signed kernel code.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2023/01/27"
  3integration = ["endpoint"]
  4maturity = "production"
  5updated_date = "2026/05/01"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Identifies an untrusted driver loaded by the Windows kernel. Adversaries may modify code signing policies to
 11enable execution of unsigned or self-signed kernel code.
 12"""
 13from = "now-9m"
 14index = ["logs-endpoint.events.library-*"]
 15language = "eql"
 16license = "Elastic License v2"
 17name = "Untrusted Driver Loaded"
 18references = [
 19    "https://github.com/hfiref0x/TDL",
 20    "https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653559(v=vs.85)?redirectedfrom=MSDN",
 21]
 22risk_score = 73
 23rule_id = "d8ab1ec1-feeb-48b9-89e7-c12e189448aa"
 24severity = "high"
 25tags = [
 26    "Domain: Endpoint",
 27    "OS: Windows",
 28    "Use Case: Threat Detection",
 29    "Tactic: Defense Evasion",
 30    "Resources: Investigation Guide",
 31    "Data Source: Elastic Defend",
 32]
 33timestamp_override = "event.ingested"
 34type = "eql"
 35
 36query = '''
 37driver where host.os.type == "windows" and process.pid == 4 and
 38  (dll.code_signature.trusted == false or dll.code_signature.exists == false) and
 39  /* errorExpired and errorRevoked are handled by d12bac54-ab2a-4159-933f-d7bcefa7b61d */
 40  not dll.code_signature.status : ("errorExpired", "errorRevoked", "errorCode_endpoint:*") and
 41  
 42  /* HP DOT4 printer driver family FPs (Dot4.sys, Dot4Prt.sys, Dot4usb.sys, Dot4Scan.sys) */
 43  not dll.hash.sha256 : (
 44        "f21c1d478180bc5e932bb2c2e4618e3ed463ca87acedeb139682d218435f82f1",
 45        "7e2f2a139e897eae56038b920bda9381094bc0ae9e626f6634e6b444b8b0c91f",
 46        "12ffdf5f48a79b1b4adbb88ba2cb6c59dd6719554e8ea6beefe99b3e3c66f1ac",
 47        "dbc6afaf80141e2480e19878f581edfe9c2b018da2ec527c4025ff04d5587afd"
 48  )
 49'''
 50
 51note = """## Triage and analysis
 52
 53### Investigating Untrusted Driver Loaded
 54
 55#### Possible investigation steps
 56
 57- What exact kernel driver loaded, and what trust failure made it alert?
 58  - Focus: `process.pid`, `dll.path`, `dll.code_signature.exists`, `dll.code_signature.trusted`, and `dll.code_signature.status`.
 59  - Implication: escalate when System loaded an unsigned or untrusted driver from a non-vendor, user-writable, temp, or renamed path; lower concern only when the trust failure fits a controlled driver-development or hardware-validation host class.
 60
 61- Does the driver identity map to a known vulnerable driver, BYOVD chain, or offensive loader?
 62  - Why: TDL-style and BYOVD activity may be easier to recognize by stable hash, original PE name, or signer than current file name.
 63  - Focus: `dll.hash.sha256`, `dll.pe.original_file_name`, `dll.code_signature.subject_name`, and `dll.code_signature.thumbprint_sha256`.
 64  - Implication: escalate when hash, original name, or signer maps to a vulnerable-driver blocklist, signature-bypass loader, or malicious kernel tooling; lower concern only when the same artifact is tied to a controlled lab or validation cohort.
 65
 66- Does recency or rename timing show the driver was staged for this load?
 67  - Focus: `dll.Ext.relative_file_creation_time`, `dll.Ext.relative_file_name_modify_time`, and `dll.path`; if file-event telemetry is available, use the same `host.id` and path to identify who wrote or renamed it. $investigate_0
 68  - Implication: escalate when the driver appeared just before load, was recently renamed, or was written by an unrelated staging process. Missing file-event telemetry leaves provenance unresolved, not benign.
 69
 70- What resident service or device identity is tied to the loaded image?
 71  - Focus: compare `dll.path`, `dll.hash.sha256`, and `dll.code_signature.subject_name` with current Osquery driver inventory and service output.
 72  - Hint: For non-Microsoft drivers by `image`, `service`, `signed`, `subject_name`, and `VtLink`; use it as current-state context, and keep the alert as the historical load record if no matching image exists.
 73    - $osquery_0
 74  - Hint: For unsigned current drivers when the alert shows missing or untrusted signature metadata; current signed or service values do not prove what existed at `@timestamp`.
 75    - $osquery_1
 76  - Implication: escalate when current inventory lacks a coherent image or service entry, the service is unexpected for the host, or other unsigned drivers do not fit the host role. Treat osquery as corroboration; do not delay escalation when alert-local identity, trust, or recency evidence is decisive.
 77
 78- Did signing or code-integrity control activity make this load possible?
 79  - Why: 64-bit Windows normally enforces kernel-mode driver signing, while test-signing, DSE tampering, or vulnerable-driver loaders can open a path for untrusted kernel code.
 80  - Focus: same-host process events around the load using `host.id`, `process.name`, `process.executable`, and `process.command_line` for bcdedit test-signing/nointegritychecks changes or known vulnerable-driver loader activity. $investigate_1
 81  - Implication: escalate when surrounding process evidence shows test-signing changes, code-integrity bypass tooling, or vulnerable-driver loader execution; absent process evidence weakens this corroborator but does not clear an unexplained untrusted driver load.
 82
 83- Does the host cohort and prevalence fit a controlled driver workflow?
 84  - Focus: `host.id`, `host.name`, and the smallest stable indicator, usually `dll.hash.sha256`, `dll.path`, or `dll.code_signature.subject_name`.
 85  - Hint: broaden only when identity, recency, inventory, or tampering evidence remains suspicious or unresolved. $investigate_2
 86  - Implication: escalate when the driver appears on production systems, user-writable paths, unrelated hosts, or outside the expected lab cohort; lower concern only when artifact, path pattern, signer, and host cohort consistently match a controlled validation workflow.
 87
 88- Using identity, trust failure, staging/provenance, osquery inventory, signing-control evidence, and host-cohort spread: escalate unauthorized kernel code, BYOVD, or signature-bypass evidence; close only when telemetry binds the load to one controlled driver workflow; preserve artifacts and escalate mixed or incomplete cases.
 89
 90### False positive analysis
 91
 92- Controlled driver-development, OEM hardware validation, and authorized security or EDR compatibility testing can load test-signed or unsigned drivers on isolated lab hosts. Confirm first with telemetry: `dll.hash.sha256`, `dll.path`, `dll.code_signature.status` or `dll.code_signature.subject_name`, current osquery image and service output, and `host.id` cohort must align with one workflow. Use build, test, or change records only after telemetry binds the exact artifact and cohort; if unavailable, require prior alerts for the same driver artifact and host cohort before exceptioning. If any evidence dimension contradicts the workflow, do not close as benign.
 93- Build exceptions only from the minimum confirmed pattern, such as `dll.hash.sha256` plus `dll.path` plus bounded `host.id` cohort or service identity. Avoid exceptions on `dll.name`, signer, or generic unsigned-driver conditions alone.
 94
 95### Response and remediation
 96
 97- If confirmed benign:
 98  - Reverse temporary containment and document the driver artifact, host cohort, current osquery image and service values, and any corroborating external record. Keep exceptions narrow to the confirmed hash, path, host cohort, or service identity.
 99- If suspicious but unconfirmed:
100  - Preserve the driver file if accessible, the alert event export, osquery driver inventory results, surrounding signing-control process events, and the case timeline before containment or cleanup.
101  - Apply reversible containment first, such as temporary network restriction or heightened monitoring, while scoping the same `dll.hash.sha256` or `dll.path` across other hosts.
102  - Escalate to host isolation before reboot, uninstall, or cleanup only if evidence shows code-integrity tampering, vulnerable-driver loader activity, post-load abuse, or spread outside the expected lab cohort.
103- If confirmed malicious:
104  - Isolate the host after preserving the driver artifact, service or boot-start context, signing-control evidence, and affected `host.id` or `host.name`. If endpoint response is unavailable, hand off that evidence set to the team that can contain the system.
105  - Scope other hosts for the same `dll.hash.sha256`, `dll.path`, or `dll.code_signature.subject_name` before uninstalling the driver, deleting the file, removing the backing service, or rebooting.
106  - Remove the malicious driver, related service or boot-start entry, and code-signing or DSE changes identified during investigation, then remediate the loader or vulnerable-driver path that introduced it.
107- Post-incident hardening:
108  - Re-enable or enforce driver-signing and code-integrity controls on the affected host class, block confirmed malicious or vulnerable `dll.hash.sha256` values and `dll.path` locations, and restrict test-signing to isolated lab systems.
109  - Document any BYOVD family, loader service name, or host-cohort pattern uncovered during triage for future response cases.
110"""
111
112setup = """## Setup
113
114This 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.
115
116Setup instructions: https://ela.st/install-elastic-defend
117"""
118
119[rule.investigation_fields]
120field_names = [
121    "@timestamp",
122    "host.name",
123    "host.id",
124    "process.pid",
125    "dll.path",
126    "dll.name",
127    "dll.hash.sha256",
128    "dll.pe.original_file_name",
129    "dll.code_signature.exists",
130    "dll.code_signature.trusted",
131    "dll.code_signature.status",
132    "dll.code_signature.subject_name",
133    "dll.code_signature.thumbprint_sha256",
134    "dll.Ext.relative_file_creation_time",
135    "dll.Ext.relative_file_name_modify_time",
136]
137
138[transform]
139
140[[transform.osquery]]
141label = "Osquery - Retrieve All Non-Microsoft Drivers with Virustotal Link"
142query = """
143SELECT concat('https://www.virustotal.com/gui/file/', sha1) AS VtLink, class, description, directory, image,
144issuer_name, manufacturer, service, signed, subject_name FROM drivers JOIN authenticode ON drivers.image =
145authenticode.path JOIN hash ON drivers.image = hash.path WHERE NOT (provider == "Microsoft" AND signed == "1")
146"""
147
148[[transform.osquery]]
149label = "Osquery - Retrieve All Unsigned Drivers with Virustotal Link"
150query = """
151SELECT concat('https://www.virustotal.com/gui/file/', sha1) AS VtLink, class, description, directory, image,
152issuer_name, manufacturer, service, signed, subject_name FROM drivers JOIN authenticode ON drivers.image =
153authenticode.path JOIN hash ON drivers.image = hash.path WHERE signed == "0"
154"""
155
156[[transform.investigate]]
157label = "File events for the loaded driver path"
158description = ""
159providers = [
160  [
161    { excluded = false, field = "event.category", queryType = "phrase", value = "file", valueType = "string" },
162    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
163    { excluded = false, field = "file.path", queryType = "phrase", value = "{{dll.path}}", valueType = "string" }
164  ]
165]
166relativeFrom = "now-1h"
167relativeTo = "now"
168
169[[transform.investigate]]
170label = "Process events on the driver host"
171description = ""
172providers = [
173  [
174    { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" },
175    { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
176  ]
177]
178relativeFrom = "now-1h"
179relativeTo = "now"
180
181[[transform.investigate]]
182label = "Alerts associated with the driver identity"
183description = ""
184providers = [
185  [
186    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
187    { excluded = false, field = "dll.hash.sha256", queryType = "phrase", value = "{{dll.hash.sha256}}", valueType = "string" }
188  ],
189  [
190    { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
191    { excluded = false, field = "dll.path", queryType = "phrase", value = "{{dll.path}}", valueType = "string" }
192  ]
193]
194relativeFrom = "now-48h/h"
195relativeTo = "now"
196
197[[rule.threat]]
198framework = "MITRE ATT&CK"
199[[rule.threat.technique]]
200id = "T1036"
201name = "Masquerading"
202reference = "https://attack.mitre.org/techniques/T1036/"
203[[rule.threat.technique.subtechnique]]
204id = "T1036.001"
205name = "Invalid Code Signature"
206reference = "https://attack.mitre.org/techniques/T1036/001/"
207
208[rule.threat.tactic]
209id = "TA0005"
210name = "Defense Evasion"
211reference = "https://attack.mitre.org/tactics/TA0005/"

Triage and analysis

Investigating Untrusted Driver Loaded

Possible investigation steps

  • What exact kernel driver loaded, and what trust failure made it alert?

    • Focus: process.pid, dll.path, dll.code_signature.exists, dll.code_signature.trusted, and dll.code_signature.status.
    • Implication: escalate when System loaded an unsigned or untrusted driver from a non-vendor, user-writable, temp, or renamed path; lower concern only when the trust failure fits a controlled driver-development or hardware-validation host class.
  • Does the driver identity map to a known vulnerable driver, BYOVD chain, or offensive loader?

    • Why: TDL-style and BYOVD activity may be easier to recognize by stable hash, original PE name, or signer than current file name.
    • Focus: dll.hash.sha256, dll.pe.original_file_name, dll.code_signature.subject_name, and dll.code_signature.thumbprint_sha256.
    • Implication: escalate when hash, original name, or signer maps to a vulnerable-driver blocklist, signature-bypass loader, or malicious kernel tooling; lower concern only when the same artifact is tied to a controlled lab or validation cohort.
  • Does recency or rename timing show the driver was staged for this load?

    • Focus: dll.Ext.relative_file_creation_time, dll.Ext.relative_file_name_modify_time, and dll.path; if file-event telemetry is available, use the same host.id and path to identify who wrote or renamed it. $investigate_0
    • Implication: escalate when the driver appeared just before load, was recently renamed, or was written by an unrelated staging process. Missing file-event telemetry leaves provenance unresolved, not benign.
  • What resident service or device identity is tied to the loaded image?

    • Focus: compare dll.path, dll.hash.sha256, and dll.code_signature.subject_name with current Osquery driver inventory and service output.
    • Hint: For non-Microsoft drivers by image, service, signed, subject_name, and VtLink; use it as current-state context, and keep the alert as the historical load record if no matching image exists.
      • $osquery_0
    • Hint: For unsigned current drivers when the alert shows missing or untrusted signature metadata; current signed or service values do not prove what existed at @timestamp.
      • $osquery_1
    • Implication: escalate when current inventory lacks a coherent image or service entry, the service is unexpected for the host, or other unsigned drivers do not fit the host role. Treat osquery as corroboration; do not delay escalation when alert-local identity, trust, or recency evidence is decisive.
  • Did signing or code-integrity control activity make this load possible?

    • Why: 64-bit Windows normally enforces kernel-mode driver signing, while test-signing, DSE tampering, or vulnerable-driver loaders can open a path for untrusted kernel code.
    • Focus: same-host process events around the load using host.id, process.name, process.executable, and process.command_line for bcdedit test-signing/nointegritychecks changes or known vulnerable-driver loader activity. $investigate_1
    • Implication: escalate when surrounding process evidence shows test-signing changes, code-integrity bypass tooling, or vulnerable-driver loader execution; absent process evidence weakens this corroborator but does not clear an unexplained untrusted driver load.
  • Does the host cohort and prevalence fit a controlled driver workflow?

    • Focus: host.id, host.name, and the smallest stable indicator, usually dll.hash.sha256, dll.path, or dll.code_signature.subject_name.
    • Hint: broaden only when identity, recency, inventory, or tampering evidence remains suspicious or unresolved. $investigate_2
    • Implication: escalate when the driver appears on production systems, user-writable paths, unrelated hosts, or outside the expected lab cohort; lower concern only when artifact, path pattern, signer, and host cohort consistently match a controlled validation workflow.
  • Using identity, trust failure, staging/provenance, osquery inventory, signing-control evidence, and host-cohort spread: escalate unauthorized kernel code, BYOVD, or signature-bypass evidence; close only when telemetry binds the load to one controlled driver workflow; preserve artifacts and escalate mixed or incomplete cases.

False positive analysis

  • Controlled driver-development, OEM hardware validation, and authorized security or EDR compatibility testing can load test-signed or unsigned drivers on isolated lab hosts. Confirm first with telemetry: dll.hash.sha256, dll.path, dll.code_signature.status or dll.code_signature.subject_name, current osquery image and service output, and host.id cohort must align with one workflow. Use build, test, or change records only after telemetry binds the exact artifact and cohort; if unavailable, require prior alerts for the same driver artifact and host cohort before exceptioning. If any evidence dimension contradicts the workflow, do not close as benign.
  • Build exceptions only from the minimum confirmed pattern, such as dll.hash.sha256 plus dll.path plus bounded host.id cohort or service identity. Avoid exceptions on dll.name, signer, or generic unsigned-driver conditions alone.

Response and remediation

  • If confirmed benign:
    • Reverse temporary containment and document the driver artifact, host cohort, current osquery image and service values, and any corroborating external record. Keep exceptions narrow to the confirmed hash, path, host cohort, or service identity.
  • If suspicious but unconfirmed:
    • Preserve the driver file if accessible, the alert event export, osquery driver inventory results, surrounding signing-control process events, and the case timeline before containment or cleanup.
    • Apply reversible containment first, such as temporary network restriction or heightened monitoring, while scoping the same dll.hash.sha256 or dll.path across other hosts.
    • Escalate to host isolation before reboot, uninstall, or cleanup only if evidence shows code-integrity tampering, vulnerable-driver loader activity, post-load abuse, or spread outside the expected lab cohort.
  • If confirmed malicious:
    • Isolate the host after preserving the driver artifact, service or boot-start context, signing-control evidence, and affected host.id or host.name. If endpoint response is unavailable, hand off that evidence set to the team that can contain the system.
    • Scope other hosts for the same dll.hash.sha256, dll.path, or dll.code_signature.subject_name before uninstalling the driver, deleting the file, removing the backing service, or rebooting.
    • Remove the malicious driver, related service or boot-start entry, and code-signing or DSE changes identified during investigation, then remediate the loader or vulnerable-driver path that introduced it.
  • Post-incident hardening:
    • Re-enable or enforce driver-signing and code-integrity controls on the affected host class, block confirmed malicious or vulnerable dll.hash.sha256 values and dll.path locations, and restrict test-signing to isolated lab systems.
    • Document any BYOVD family, loader service name, or host-cohort pattern uncovered during triage for future response cases.

References

Related rules

to-top