Mehmet Ergene

Detecting Vulnerable Drivers (a.k.a. LOLDrivers) the Right Way Using Microsoft Defender for Endpoint

Empty space, drag to resize
A recent poll I conducted revealed a concerning gap in understanding around how to detect vulnerable drivers using Microsoft Defender for Endpoint (MDE) telemetry. So, the results prompted this post; not just to clarify, but to help prevent the propagation of inaccurate detection methods.

Misconceptions in Driver Load Events

In the poll, 20% of respondents selected a table that doesn't even exist in MDE. Even more troubling, 47% chose the ImageLoadEvents table (referring to DeviceImageLoadEvents), which is an actual table but doesn't contain driver load events. Only 33% answered correctly.

Let's set the record straight. The DeviceImageLoadEvents table, as you can see in the documentation, logs DLL load activity, not the driver load activity. Drivers typically use the .sys file extension, not .dll. (If you've ever seen a driver in DLL format, I'd genuinely be interested to know.)

The Correct Data Source: DeviceEvents

To accurately detect driver loads, use the DeviceEvents table where ActionType == "DriverLoad". If you don't know where and how driver load events are logged, you could just do a search in (Table_Name) FileName:".sys" to identify these events by filtering on .sys file extensions (or simply examining distinct ActionType values for each table).

Here's where things also go off-track: AI-generated responses often mislead. For example, some models might suggest queries like:
DeviceFileEvents
| where ActionType == "DriverLoad" // there isn't such event in file events
or:
DeviceImageLoadEvents
| where ActionType == "DriverLoad" // there isn't such event in image load events.
These queries are incorrect. While AI can be useful, always validate your detection logic, especially before sharing it publicly to help others (?!?!!?).

A Reliable KQL Example Using LOLDrivers.io

To detect known vulnerable drivers (LOLDrivers) using MDE telemetry, here's a query that pulls the data from the loldrivers.io dataset and joins it with driver load events both on SHA1 and SHA256 values since there are some missing SHA1 and SHA256 values in LOLDrivers:
let LOLDrivers = externaldata (Category:string, KnownVulnerableSamples:dynamic, Verified:string ) [h@"https://www.loldrivers.io/api/drivers.json"]
    with (format=multijson, ingestionMapping='[{"Column":"Category","Properties":{"Path":"$.Category"}},{"Column":"KnownVulnerableSamples","Properties":{"Path":"$.KnownVulnerableSamples"}},{"Column":"Verified","Properties":{"Path":"$.Verified"}}]')
| mv-expand KnownVulnerableSamples
| extend SHA1 = tostring(KnownVulnerableSamples.SHA1), SHA256 = tostring(KnownVulnerableSamples.SHA256)
;
// you can filter the drivers further based on category or verified status
DeviceEvents
| where ActionType == "DriverLoad"
| join kind=inner (LOLDrivers | where isnotempty(SHA256)) on SHA256
| union (
  DeviceEvents
  | where ActionType == "DriverLoad"
  | join kind=inner (LOLDrivers | where isnotempty(SHA1)) on SHA1
)

Final Thoughts

Incorrect guidance, whether from AI tools or well-meaning individuals, can dilute the effectiveness of detection engineering. Always verify your queries using documentation and telemetry validation. Precision matters when you're building detections.
Share this post