// question

On a Linux endpoint, process events reveal a chain of group‐enumeration utilities executed by a single session. Which utility was used to query the system’s group database?

Reference KQL answer and model-by-model comparison.

952931a4-af0b-4335-bbbe-73c8c5b327ae
question id
12/23
models correct
1
valid answer
52%
success rate
// reference answer

Human-validated correct answer for this question.

getent
// model comparison
ModelAnswerKQL queryStatusTriesTimeCost
gemini-2.5-flash-preview-04-17
getent
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where ProcessCommandLine contains " getent group" or ProcessCommandLine contains " /etc/group"
| project Timestamp, DeviceName, FileName, ProcessCommandLine, AccountName, InitiatingProcessCommandLine, InitiatingProcessFileName, LogonId, InitiatingProcessSessionId, CreatedProcessSessionId
pass113.44s0.0071
gpt-35-turbo
no answer
no query generatedfail50.00s0.0113
gpt-4-turbo-2024-04-09
no answer
no query generatedfail50.00s0.2382
gpt-4.1
getent
DeviceProcessEvents
| where FileName in~ ("getent", "cat", "groups", "id")
| where ProcessCommandLine has_any ("group", "/etc/group")
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessSessionId
| summarize UtilitiesUsed=make_set(FileName) by InitiatingProcessSessionId, DeviceName, AccountName
pass15.41s0.0112
gpt-4.1-finetuned
no answer
no query generatedfail50.00s0.0858
gpt-4.1-mini
no answer
no query generatedfail50.00s0.0079
gpt-4.1-nano
getent group
DeviceProcessEvents
| where FileName in ('getent', 'groups', 'id')
| where ProcessCommandLine contains 'group'
| project TimeGenerated, DeviceName, InitiatingProcessFileName, ProcessCommandLine, ProcessId, InitiatingProcessId, InitiatingProcessParentId
pass23.63s0.0008
gpt-4o
id
let linuxDevices = DeviceInfo
| where OSPlatform == 'Linux'
| distinct DeviceId;
DeviceProcessEvents
| where DeviceId in (linuxDevices)
| where ProcessCommandLine has_any ('id', 'getent', 'groups') or FileName has_any ('id', 'getent', 'groups')
| summarize count() by FileName
fail25.02s0.0273
gpt-5-high
getent
let linux_devices = DeviceInfo
| where OSPlatform == "Linux"
| summarize arg_max(TimeGenerated, *) by DeviceId
| project DeviceId;
let group_enum_sessions =
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where DeviceId in (linux_devices)
| extend cmd = tostring(ProcessCommandLine)
| where tolower(FileName) in ("id","groups","getent","cat","grep","awk","cut") or cmd has "/etc/group" or cmd has "getent group"
| summarize utils = make_set(tolower(FileName)), firstSeen=min(TimeGenerated), lastSeen=max(TimeGenerated) by DeviceId, DeviceName, InitiatingProcessSessionId
| where array_length(utils) >= 2;
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where DeviceId in (linux_devices)
| extend cmd = tostring(ProcessCommandLine)
| where tolower(FileName) == "getent" or cmd matches regex @"\bgetent\s+group\b"
| where cmd has "group"  // ensure it's querying the group database
| join kind=inner (group_enum_sessions) on DeviceId, InitiatingProcessSessionId
| project TimeGenerated, DeviceId, DeviceName, InitiatingProcessSessionId, UtilityUsedToQueryGroupDB = "getent", ProcessCommandLine
| order by TimeGenerated asc
pass183.92s0.0524
gpt-5-mini-high
getent
let linuxDevices = DeviceInfo
| where tolower(OSPlatform) has "linux"
| distinct DeviceId;
DeviceProcessEvents
| where DeviceId in (linuxDevices)
// look for common group-enumeration commands or reads of /etc/group
| where tolower(ProcessCommandLine) has_any ("getent", "/etc/group", "groups", "id -g", "id -G")
| extend tool = case(
    tolower(ProcessCommandLine) contains "getent", "getent",
    tolower(ProcessCommandLine) contains "cat /etc/group" or tolower(ProcessCommandLine) contains "/etc/group", "cat /etc/group",
    tolower(ProcessCommandLine) contains "groups", "groups",
    tolower(ProcessCommandLine) contains "id -g" or tolower(ProcessCommandLine) contains "id -G" or tolower(FileName) == "id", "id",
    "other")
// flag whether this event queried the system group database (getent group)
| extend queried_system_group_db = iff(tool == "getent" or tolower(ProcessCommandLine) has "getent group", true, false)
| project TimeGenerated, DeviceName, DeviceId, FileName, ProcessId, CreatedProcessSessionId, InitiatingProcessFileName, InitiatingProcessId, ProcessCommandLine, tool, queried_system_group_db
| order by TimeGenerated asc
pass136.70s0.0099
gpt-5-mini-low
getent
DeviceProcessEvents
| where FileName =~ "bash" or FileName =~ "sh" or FileName has_any ("getent", "groupmems", "members", "gpasswd", "cat") or ProcessCommandLine has "/etc/group" // capture shells and known utilities
| extend SessionId = coalesce(CreatedProcessSessionId, InitiatingProcessSessionId, ProcessId, InitiatingProcessId)
| summarize FirstProcess=min(ProcessCreationTime), any_DeviceName=any(DeviceName) by SessionId, InitiatingProcessAccountName, InitiatingProcessId
| join kind=inner (
    DeviceProcessEvents
    | extend SessionId = coalesce(CreatedProcessSessionId, InitiatingProcessSessionId, ProcessId, InitiatingProcessId)
    | where FileName has_any ("getent", "groupmems", "members", "gpasswd", "cat") or ProcessCommandLine has "/etc/group" or ProcessCommandLine has "getent" or ProcessCommandLine has "group" or ProcessCommandLine has "members"
    | project TimeGenerated, DeviceName, ProcessCreationTime, ProcessId, ProcessCommandLine, FileName, FolderPath, InitiatingProcessAccountName, SessionId
) on SessionId
| where ProcessCreationTime >= FirstProcess and ProcessCreationTime <= FirstProcess + 1h
| summarize arg_min(ProcessCreationTime, *) by SessionId
| project SessionId, DeviceName, ProcessCreationTime, FileName, ProcessId, ProcessCommandLine, InitiatingProcessAccountName
| order by ProcessCreationTime asc
pass110.96s0.0046
gpt-5-mini-medium
no answer
no query generatedfail50.00s0.0136
gpt-5-nano-high
no answer
no query generatedfail50.00s0.0085
gpt-5-nano-medium
no answer
no query generatedfail50.00s0.0082
grok-3-beta
no answer
no query generatedfail50.00s0.0925
grok-3-mini-beta
getent
let LinuxDevices = DeviceInfo | where OSPlatform == 'Linux' | distinct DeviceId;
DeviceProcessEvents
| where DeviceId in (LinuxDevices)
| where (FileName == 'groups' or ProcessCommandLine contains 'getent group')
| summarize distinct_utilities = make_set(FileName) by InitiatingProcessSessionId
| project InitiatingProcessSessionId, distinct_utilities
pass116.86s0.0015
o1-high
getent
DeviceProcessEvents
| where FileName in~ ("getent", "cat", "id", "groups")
| where ProcessCommandLine has_any ("group", "/etc/group")
| project TimeGenerated, DeviceName, InitiatingProcessSessionId, FileName, FolderPath, ProcessCommandLine
| order by TimeGenerated asc
pass3103.00s0.4782
o1-low
getent
DeviceInfo
| where OSPlatform == "Linux"
| join kind=inner (
    DeviceProcessEvents
    | where ProcessCommandLine has_any("getent group", "/etc/group")
) on DeviceId
| project TimeGenerated, DeviceName, InitiatingProcessSessionId, FileName, ProcessCommandLine
| order by TimeGenerated desc
pass133.94s0.4710
o3-high
getent
// 1.  Define the group-enumeration utilities we are interested in
let group_enum_utils = dynamic(["id", "groups", "getent"]);

// 2.  Pull Linux process events that reference any of those binaries
let enum_calls = DeviceProcessEvents
| where Timestamp > ago(1d)   // (Time range placeholder – will be overridden by portal picker)
| where FolderPath startswith "/"              // crude indicator we are on a Linux host
| where FileName in (group_enum_utils)
| extend SessionId = coalesce(InitiatingProcessSessionId, CreatedProcessSessionId);

// 3.  Find sessions that executed more than one of the enumeration utilities (a chain)
let chained_sessions = enum_calls
| summarize util_set = makeset(FileName) by DeviceId, DeviceName, SessionId
| where array_length(util_set) > 1
| project DeviceId, DeviceName, SessionId;

// 4.  From those sessions pick the call that queried the system’s group database – “getent”
DeviceProcessEvents
| where Timestamp > ago(1d)
| where FileName == "getent" and ProcessCommandLine contains "group"
| extend SessionId = coalesce(InitiatingProcessSessionId, CreatedProcessSessionId)
| join kind=inner (chained_sessions) on SessionId
| project TimeGenerated, DeviceName, SessionId, AccountName, FileName, ProcessCommandLine
| order by TimeGenerated asc
pass135.21s0.0210
o3-mini-high
getent
DeviceProcessEvents
| where ProcessCommandLine contains "getent" and ProcessCommandLine contains "group"
| project TimeGenerated, DeviceName, InitiatingProcessSessionId, FileName, ProcessCommandLine, ProcessCreationTime, FolderPath
pass141.09s0.0141
o3-mini-low
getent
DeviceProcessEvents
| where ProcessCommandLine has "group"
| summarize ProcessChain = make_set(FileName) by InitiatingProcessSessionId
| where array_index_of(ProcessChain, "getent") >= 0
| project InitiatingProcessSessionId, ProcessChain

// The resulting output shows sessions (InitiatingProcessSessionId) where the chain of utilities includes 'getent', which is used to query the system's group database.
pass131.69s0.0118
o4-mini-high
no answer
no query generatedfail50.00s0.0487
o4-mini-low
no answer
no query generatedfail50.00s0.0388