// question

While investigating process creation logs on a Linux device, you observe a privileged hardware interrogation step used to reveal virtualization details. Which utility was invoked?

Reference KQL answer and model-by-model comparison.

31dad7ad-2286-4c02-ae92-274418c85fec
question id
20/23
models correct
1
valid answer
87%
success rate
// reference answer

Human-validated correct answer for this question.

dmidecode
// model comparison
ModelAnswerKQL queryStatusTriesTimeCost
gemini-2.5-flash-preview-04-17
dmidecode
DeviceProcessEvents | where ActionType == "ProcessCreated" | where AccountName == "root" | where FileName in ("virt-what", "dmidecode", "systemd-detect-virt", "lshw") | project Timestamp, DeviceName, FileName, ProcessCommandLine, AccountName
pass125.16s0.0136
gpt-35-turbo
no answer
no query generatedfail50.00s0.0111
gpt-4-turbo-2024-04-09
dmidecode
DeviceProcessEvents
| where ProcessCommandLine contains 'dmidecode'
| project DeviceName, InitiatingProcessAccountName, ProcessCommandLine, ProcessCreationTime
pass112.65s0.0910
gpt-4.1
dmidecode
DeviceProcessEvents
| where FileName in~ ("dmidecode", "lshw", "lscpu", "lspci", "systemd-detect-virt", "virt-what", "dmesg", "hostnamectl")
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, AccountName, InitiatingProcessAccountName, ProcessTokenElevation
| sort by TimeGenerated desc
pass210.77s0.0232
gpt-4.1-finetuned
dmidecode
// Query to detect if a privileged hardware interrogation utility is invoked
union DeviceProcessEvents, DeviceNetworkEvents, DeviceFileEvents, DeviceEvents
| where ActionType == "ProcessCreated" // Focus on process creation events
| where ProcessCommandLine contains "lscpu" // Looking for 'lscpu' command specifically
// Optionally narrow to execute as root (UID 0) or Sudo users -- for example:
// | where InitiatingProcessAccountName =~ "root" or InitiatingProcessCommandLine contains "/usr/bin/sudo"
| project-reorder Timestamp, DeviceName, InitiatingProcessAccountUpn, InitiatingProcessCommandLine, ProcessCommandLine, InitiatingProcessParentFileName, InitiatingProcessParentCreationTime
| summarize eventCount = count(), earliestEvent = min(Timestamp), latestEvent = max(Timestamp) by bin(Timestamp, 1d), DeviceName, InitiatingProcessAccountUpn, InitiatingProcessCommandLine, ProcessCommandLine, InitiatingProcessParentFileName, InitiatingProcessParentCreationTime
| order by eventCount desc
pass115.50s0.0177
gpt-4.1-mini
no answer
no query generatedfail50.00s0.0073
gpt-4.1-nano
dmidecode
DeviceProcessEvents
| where FileName in ('dmidecode', 'lshw', 'systeminfo', 'biosdecode', 'xxd')
| project TimeGenerated, DeviceName, ProcessId, FileName, ProcessCommandLine
| order by TimeGenerated desc
pass12.05s0.0005
gpt-4o
dmidecode
DeviceProcessEvents
| where InitiatingProcessCommandLine has_any ('lscpu', 'dmidecode', 'virt-what') or FileName has_any ('lscpu', 'dmidecode', 'virt-what')
| project InitiatingProcessCommandLine, FileName, InitiatingProcessCreationTime, DeviceName, ProcessId
pass16.58s0.0382
gpt-5-high
dmidecode
let virtualization_utils = dynamic(["dmidecode","systemd-detect-virt","virt-what","lshw","lscpu","hostnamectl"]);
DeviceProcessEvents
| join kind=inner (DeviceInfo | where OSPlatform == "Linux" | project DeviceId) on DeviceId
| where tolower(FileName) in (virtualization_utils) or ProcessCommandLine has_any (virtualization_utils)
| where AccountName =~ "root" or ProcessTokenElevation =~ "Elevated"
| extend UtilityInvoked = tolower(
    case(
        FileName in~ ("dmidecode","systemd-detect-virt","virt-what","lshw","lscpu","hostnamectl"), FileName,
        ProcessCommandLine has "dmidecode", "dmidecode",
        ProcessCommandLine has "systemd-detect-virt", "systemd-detect-virt",
        ProcessCommandLine has "virt-what", "virt-what",
        ProcessCommandLine has "lshw", "lshw",
        ProcessCommandLine has "lscpu", "lscpu",
        ProcessCommandLine has "hostnamectl", "hostnamectl",
        "unknown"
    ))
| summarize Executions=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated) by DeviceName, UtilityInvoked
| order by Executions desc, LastSeen desc
pass155.87s0.0435
gpt-5-mini-high
dmidecode
DeviceProcessEvents
| where isnotempty(ProcessCommandLine) or isnotempty(FileName)
// Normalize a command string to pick the best source
| extend cmdSource = iff(isnotempty(ProcessCommandLine), ProcessCommandLine, FileName)
// Get the first token from the commandline (the invoked binary) and/or basename from FileName
| extend invokedRaw = tostring(split(cmdSource, " ")[0])
| extend invoked = tolower(iff(isnotempty(FileName), extract(@"([^\\/]+)$", 1, FileName), invokedRaw))
// Look for common Linux virtualization/hardware interrogation utilities (dmidecode is the most-common privileged one)
| where invoked has_any ("dmidecode", "systemd-detect-virt", "lscpu", "lshw", "cpuid", "lspci", "virt-what")
// Flag likely-elevated runs (root account or sudo in commandline)
| extend isElevated = tostring(AccountName) == "root" or tostring(InitiatingProcessAccountName) == "root" or tolower(cmdSource) contains "sudo"
| project TimeGenerated, DeviceName, DeviceId, invoked, FileName, ProcessCommandLine, AccountName, InitiatingProcessAccountName, ProcessId, InitiatingProcessId, isElevated
| order by TimeGenerated desc
| limit 500
pass124.40s0.0061
gpt-5-mini-low
dmidecode
// NOTE: Do not hardcode a time filter here; set the timerange in the portal/timepicker when running the query
let utils = dynamic(["dmidecode","virt-what","systemd-detect-virt","lshw","lspci","dmesg","lsmod","/proc/cpuinfo","grep -i hypervisor","cpuid"]);
DeviceProcessEvents
| where isnotempty(ProcessCommandLine) or isnotempty(FileName)
// Filter for known virtualization/hardware-interrogation utilities (case-insensitive)
| where (
    tolower(ProcessCommandLine) contains "dmidecode" or tolower(FileName) contains "dmidecode"
    or tolower(ProcessCommandLine) contains "virt-what" or tolower(FileName) contains "virt-what"
    or tolower(ProcessCommandLine) contains "systemd-detect-virt" or tolower(FileName) contains "systemd-detect-virt"
    or tolower(ProcessCommandLine) contains "lshw" or tolower(FileName) contains "lshw"
    or tolower(ProcessCommandLine) contains "lspci" or tolower(FileName) contains "lspci"
    or tolower(ProcessCommandLine) contains "dmesg" or tolower(FileName) contains "dmesg"
    or tolower(ProcessCommandLine) contains "lsmod" or tolower(FileName) contains "lsmod"
    or tolower(ProcessCommandLine) contains "/proc/cpuinfo" or tolower(ProcessCommandLine) contains "grep -i hypervisor"
    or tolower(ProcessCommandLine) contains "cpuid" or tolower(FileName) contains "cpuid"
)
| extend Utility = case(
    tolower(ProcessCommandLine) contains "dmidecode" or tolower(FileName) contains "dmidecode", "dmidecode",
    tolower(ProcessCommandLine) contains "virt-what" or tolower(FileName) contains "virt-what", "virt-what",
    tolower(ProcessCommandLine) contains "systemd-detect-virt" or tolower(FileName) contains "systemd-detect-virt", "systemd-detect-virt",
    tolower(ProcessCommandLine) contains "lshw" or tolower(FileName) contains "lshw", "lshw",
    tolower(ProcessCommandLine) contains "lspci" or tolower(FileName) contains "lspci", "lspci",
    tolower(ProcessCommandLine) contains "lsmod" or tolower(FileName) contains "lsmod", "lsmod",
    tolower(ProcessCommandLine) contains "dmesg" or tolower(FileName) contains "dmesg", "dmesg",
    tolower(ProcessCommandLine) contains "/proc/cpuinfo" or tolower(ProcessCommandLine) contains "grep -i hypervisor", "/proc/cpuinfo/grep",
    tolower(ProcessCommandLine) contains "cpuid" or tolower(FileName) contains "cpuid", "cpuid",
    "other")
// Summary: how many times each utility was invoked, last seen per device
| summarize Count = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by Utility, DeviceName, DeviceId
| order by LastSeen desc
| limit 50

// To also see detailed recent events for matched utilities, uncomment the following block or run it separately:
// DeviceProcessEvents
// | where <same filter as above>
// | extend Utility = <same case(...) statement>
// | project TimeGenerated, DeviceName, DeviceId, AccountName, AccountDomain = AccountDomain, FileName, ProcessId, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountName, Utility
// | order by TimeGenerated desc
// | take 50
pass246.52s0.0110
gpt-5-mini-medium
dmidecode
// Search for process creations on Linux devices that match common virtualization interrogation utilities
let tools = dynamic(["dmidecode","virt-what","systemd-detect-virt","lscpu","lspci","/proc/cpuinfo","cat /proc/cpuinfo","dmesg","lsmod","virsh","virt-what","hostnamectl","egrep -i virtual|hypervisor|kvm|vmware|vbox"]);
DeviceProcessEvents
| where TimeGenerated between (startofday(ago(30d)) .. now())
// join to DeviceInfo to ensure Linux OSPlatform or distribution
| join kind=inner (
    DeviceInfo
    | where tostring(OSPlatform) =~ "Linux" or tostring(OSDistribution) =~ "Ubuntu" or tostring(OSDistribution) =~ "CentOS" or tostring(OSDistribution) =~ "Debian" or tostring(OSDistribution) =~ "RHEL" or OSDistribution contains "Linux"
    | project DeviceId, DeviceName, OSPlatform, OSDistribution
) on DeviceId
| where ActionType == "ProcessCreated" or ProcessCommandLine != ""
| where (
    // search in FileName and ProcessCommandLine for known utility names or patterns
    (FileName has_any ("dmidecode","virt-what","systemd-detect-virt","lscpu","lspci","dmesg","lsmod","virsh","hostnamectl","egrep"))
    or (ProcessCommandLine has_any ("dmidecode","virt-what","systemd-detect-virt","lscpu","lspci","/proc/cpuinfo","cat /proc/cpuinfo","dmesg","lsmod","virsh","hostnamectl","egrep"))
)
| extend MatchedTool = case(
    ProcessCommandLine has "dmidecode" or FileName has "dmidecode","dmidecode",
    ProcessCommandLine has "virt-what" or FileName has "virt-what","virt-what",
    ProcessCommandLine has "systemd-detect-virt" or FileName has "systemd-detect-virt","systemd-detect-virt",
    ProcessCommandLine has "lscpu" or FileName has "lscpu","lscpu",
    ProcessCommandLine has "lspci" or FileName has "lspci","lspci",
    ProcessCommandLine has "/proc/cpuinfo" or ProcessCommandLine has "cat /proc/cpuinfo" or FileName has "cpuinfo","/proc/cpuinfo",
    ProcessCommandLine has "dmesg" or FileName has "dmesg","dmesg",
    ProcessCommandLine has "lsmod" or FileName has "lsmod","lsmod",
    ProcessCommandLine has "virsh" or FileName has "virsh","virsh",
    ProcessCommandLine has "hostnamectl" or FileName has "hostnamectl","hostnamectl",
    ProcessCommandLine has "egrep" or FileName has "egrep","egrep",
    "other")
| summarize Count = count(), Examples = make_list(pack("TimeGenerated", TimeGenerated, "DeviceName", DeviceName, "Account", InitiatingProcessAccountName, "FileName", FileName, "ProcessCommandLine", ProcessCommandLine), 10) by MatchedTool
| order by Count desc
| where Count > 0
pass116.44s0.0057
gpt-5-nano-high
dmidecode
DeviceProcessEvents
| where TimeGenerated >= ago(1d)
| extend CmdTool = InitiatingProcessCommandLine
| extend UtilityFromCmd = extract("(dmidecode|systemd-detect-virt|virt-what|lshw|lscpu|hwinfo)", 1, CmdTool)
| extend Utility = iff(InitiatingProcessFileName in ('dmidecode','systemd-detect-virt','virt-what','lshw','lscpu','hwinfo'), InitiatingProcessFileName, UtilityFromCmd)
| where isnotempty(Utility)
| project TimeGenerated, DeviceName, DeviceId, Utility, InitiatingProcessFileName, InitiatingProcessCommandLine
| summarize Count = count() by Utility, DeviceName, DeviceId, InitiatingProcessFileName, InitiatingProcessCommandLine, TimeGenerated
| order by TimeGenerated desc
pass157.97s0.0037
gpt-5-nano-medium
no answer
no query generatedfail50.00s0.0089
grok-3-beta
dmidecode
DeviceProcessEvents
| join kind=inner DeviceInfo on DeviceId
| where OSPlatform == 'Linux'
| where ProcessCommandLine has 'dmidecode' or ProcessCommandLine has 'virt-what' or ProcessCommandLine has 'lscpu' or FileName has 'dmidecode' or FileName has 'virt-what' or FileName has 'lscpu'
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, FolderPath, ProcessId, DeviceId
| order by TimeGenerated desc
| limit 50
pass324.02s0.0918
grok-3-mini-beta
dmidecode
DeviceProcessEvents
| join kind=inner (DeviceInfo | where OSPlatform == "Linux") on DeviceId
| where ProcessCommandLine has_any ("dmidecode", "lshw", "lscpu", "virt-what")
| summarize Utilities = make_set(FileName) by DeviceId
| project Utilities
pass118.89s0.0015
o1-high
dmidecode
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where FileName =~ "dmidecode" or ProcessCommandLine contains "dmidecode"
| where DeviceId in (DeviceInfo
    | where OSPlatform == "Linux"
    | distinct DeviceId)
| project TimeGenerated, DeviceId, DeviceName, FileName, ProcessCommandLine, InitiatingProcessCommandLine, AccountName, AccountDomain, LogonId
| order by TimeGenerated desc
pass230.23s0.3680
o1-low
dmidecode
DeviceInfo
| where OSPlatform == "Linux"
| summarize arg_max(TimeGenerated, *) by DeviceId
| join kind=inner (
    DeviceProcessEvents
    | where ActionType == "ProcessCreated"
    | where FileName =~ "dmidecode"
      or ProcessCommandLine has "dmidecode"
) on DeviceId
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, InitiatingProcessCommandLine, AccountName, FolderPath
pass123.45s0.3119
o3-high
dmidecode
// Identify the privileged utility used to interrogate hardware/virtualization details on Linux devices
let TimeRange = 1d;   // This will be overwritten by the workbook / function caller
let startTime = ago(TimeRange);
let linuxDevices = DeviceInfo
| where TimeGenerated >= startTime
| where OSPlatform =~ "Linux"
| distinct DeviceId;
DeviceProcessEvents
| where TimeGenerated >= startTime
| where DeviceId in (linuxDevices)
| where ActionType == "ProcessCreated"
// dmidecode requires root privileges and is commonly used to disclose virtualization information
| where FileName =~ "dmidecode" or ProcessCommandLine has "dmidecode"
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, 
          InitiatingProcessFileName, InitiatingProcessCommandLine, MD5, SHA256
| sort by TimeGenerated desc
pass148.08s0.0424
o3-mini-high
dmidecode
DeviceProcessEvents
| where ProcessCommandLine contains "dmidecode" or InitiatingProcessCommandLine contains "dmidecode"
| project TimeGenerated, DeviceName, ProcessId, FileName, ProcessCommandLine, InitiatingProcessCommandLine
| order by TimeGenerated desc
pass121.60s0.0217
o3-mini-low
dmidecode
DeviceProcessEvents
| where ProcessCommandLine contains "dmidecode" or InitiatingProcessCommandLine contains "dmidecode"
| project TimeGenerated, DeviceName, ProcessCommandLine, InitiatingProcessCommandLine, FileName
| order by TimeGenerated desc
pass115.30s0.0211
o4-mini-high
dmidecode

// Identify Linux devices
let LinuxDevices = DeviceInfo
  | where OSPlatform has "Linux" or OSDistribution has "linux"
  | distinct DeviceId;

// Find dmidecode invocations on those Linux devices
DeviceProcessEvents
| where DeviceId in (LinuxDevices)
      and (FileName == "dmidecode" or ProcessCommandLine has "dmidecode")
| project TimeGenerated,
          DeviceName,
          FileName,
          ProcessCommandLine,
          InitiatingProcessFileName,
          AccountName
| sort by TimeGenerated desc
pass127.28s0.0156
o4-mini-low
dmidecode
let LinuxDevices = DeviceInfo
| where OSPlatform contains "linux"
| distinct DeviceId;
DeviceProcessEvents
| where DeviceId in (LinuxDevices)
| where ProcessCommandLine contains "dmidecode"
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, ProcessCommandLine
pass132.12s0.0139