// question

Review the Linux process creation records to find which user account management utility was used to reactivate the previously locked and expired account.

Reference KQL answer and model-by-model comparison.

d2b95631-62d7-45a3-aaef-0972cea97931
question id
16/23
models correct
1
valid answer
70%
success rate
// reference answer

Human-validated correct answer for this question.

usermod
// model comparison
ModelAnswerKQL queryStatusTriesTimeCost
gemini-2.5-flash-preview-04-17
usermod
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where (ProcessCommandLine contains "usermod" and (ProcessCommandLine contains "-U" or ProcessCommandLine contains "-e"))
    or (ProcessCommandLine contains "chage" and ProcessCommandLine contains "-E")
    or (ProcessCommandLine contains "passwd" and ProcessCommandLine contains "-u")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
pass446.47s0.0229
gpt-35-turbo
no answer
no query generatedfail50.00s0.0109
gpt-4-turbo-2024-04-09
usermod
DeviceProcessEvents
| where ActionType == 'ProcessCreated'
| where FileName in ('usermod', 'passwd') and ProcessCommandLine has_any ('-U', 'unlock')
| project DeviceName, FileName, ProcessCommandLine, TimeGenerated
pass111.05s0.0542
gpt-4.1
usermod
DeviceProcessEvents
| where FileName in~ ('usermod','passwd','chage','gpasswd','vipw','vigr')
| where ProcessCommandLine has_any('--unlock','-U','--expiredate','passwd')
| project TimeGenerated, DeviceName, AccountName, InitiatingProcessAccountName, FileName, ProcessCommandLine
pass14.79s0.0133
gpt-4.1-finetuned
no answer
no query generatedfail50.00s0.0287
gpt-4.1-mini
usermod
DeviceProcessEvents
| where FileName in ("usermod", "passwd", "chage", "gpasswd") or ProcessCommandLine has_any ("usermod", "passwd", "chage", "gpasswd")
| where ProcessCommandLine has_any ("reactivate", "unlock", "unlocked", "lock", "locked", "expire", "expired", "activate", "activated")
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, AccountName
| summarize count(), make_list(ProcessCommandLine, 10) by FileName, AccountName
| order by count_ desc
pass13.85s0.0025
gpt-4.1-nano
no answer
no query generatedfail50.00s0.0013
gpt-4o
no answer
no query generatedfail50.00s0.0681
gpt-5-high
usermod
DeviceProcessEvents
| where ActionType == "ProcessCreated"
// Candidate Linux account management utilities
| where FileName in~ ("usermod", "passwd", "chage", "faillock", "pam_tally2")
// Look for commands indicative of unlocking or removing expiration/inactivity
| where (
        tolower(FileName) == "usermod" and ProcessCommandLine matches regex @"(^|\s)(-U|--unlock)($|\s)"
    ) or (
        tolower(FileName) == "passwd" and ProcessCommandLine matches regex @"(^|\s)(-u|--unlock)($|\s)"
    ) or (
        tolower(FileName) == "chage" and (ProcessCommandLine has "-E -1" or ProcessCommandLine has "--expiredate -1" or ProcessCommandLine has "-E never" or ProcessCommandLine has "--expiredate never" or ProcessCommandLine has "-I -1" or ProcessCommandLine has "--inactive -1")
    ) or (
        tolower(FileName) == "faillock" and ProcessCommandLine matches regex @"(^|\s)--reset($|\s)"
    ) or (
        tolower(FileName) == "pam_tally2" and (ProcessCommandLine matches regex @"(^|\s)--reset($|\s)" or ProcessCommandLine matches regex @"(^|\s)-r($|\s)")
    )
// Only Linux endpoints
| join kind=leftsemi (
    DeviceInfo
    | where OSPlatform =~ "Linux"
    | project DeviceId
) on DeviceId
| extend Utility = tolower(FileName)
// Best-effort extraction of target username (varies by utility)
| extend TargetUser = case(
        Utility in ("usermod","passwd","chage"), extract(@"(?:^|\s)([^-\s][^\s]*)\s*$", 1, ProcessCommandLine),
        Utility in ("faillock","pam_tally2"), coalesce(extract(@"--user\s+([^\s]+)", 1, ProcessCommandLine), extract(@"(^|\s)-u\s+([^\s]+)", 2, ProcessCommandLine)),
        ""
    )
| extend ReactivationAction = case(
        Utility == "usermod", "Unlock account (usermod -U/--unlock)",
        Utility == "passwd", "Unlock account (passwd -u/--unlock)",
        Utility == "chage" and (ProcessCommandLine has "-E -1" or ProcessCommandLine has "-E never" or ProcessCommandLine has "--expiredate -1" or ProcessCommandLine has "--expiredate never"), "Remove/disable account expiration (chage -E -1/never)",
        Utility == "chage" and (ProcessCommandLine has "-I -1" or ProcessCommandLine has "--inactive -1"), "Remove password inactivity (chage -I -1)",
        Utility == "faillock", "Reset failed logon counter (faillock --reset)",
        Utility == "pam_tally2", "Reset failed logon counter (pam_tally2 --reset)",
        "Possible reactivation"
    )
// Summarize which utility was used (avoids returning too many rows)
| summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), EventCount=count(), SampleCommand=any(ProcessCommandLine), AnyTarget=anyif(TargetUser, isnotempty(TargetUser)) by Utility, ReactivationAction
| order by LastSeen desc
pass2245.08s0.1274
gpt-5-mini-high
usermod
let linuxDevices = DeviceInfo
| where isnotempty(OSPlatform) and tolower(OSPlatform) contains "linux"
| distinct DeviceId;

let utilities = dynamic(["passwd","usermod","chage","chpasswd","gpasswd","pwconv","pwunconv","faillock","pam_tally2","pam_faillock"]);

DeviceProcessEvents
| where DeviceId in (linuxDevices)
| where isnotempty(ProcessCommandLine) or isnotempty(FileName)
| extend FileNameLower = tolower(tostring(FileName)), Cmd = tostring(ProcessCommandLine)
// match known utilities in filename or command line
| where FileNameLower in (utilities) or tolower(Cmd) has_any(utilities)
| extend CmdLower = tolower(Cmd)
// derive the utility name (prefer file name if present)
| extend UsedUtility = iff(FileNameLower in (utilities), FileNameLower, tostring(extract(@"\b(passwd|usermod|chage|chpasswd|gpasswd|pwconv|pwunconv|faillock|pam_tally2|pam_faillock)\b", 1, CmdLower)))
// detect common unlock/unexpire/reactivation indicators
| extend HasUnlockFlag = CmdLower matches regex @"\b(-u|--unlock|\-U|--unlock|\-U|--reset)\b" or CmdLower contains "unlock" or CmdLower contains "reset="
| extend HasExpireRemove = CmdLower matches regex @"\b(-E|--expire|--inactive|\-I)\b" or CmdLower contains "chage -e -1" or CmdLower matches regex @"chage\s+-E\s+-1" or CmdLower matches regex @"chage\s+-d\b"
| extend LikelyReactivation = HasUnlockFlag or HasExpireRemove or CmdLower contains "reactivate" or CmdLower contains "unexpire"
| where LikelyReactivation
// reduce volume by returning the most recent matching event per initiating account + utility + device
| summarize arg_max(ProcessCreationTime, *) by InitiatingProcessAccountName, UsedUtility, DeviceId
| project ProcessCreationTime, TimeGenerated, DeviceName, DeviceId, InitiatingProcessAccountName, InitiatingProcessAccountDomain, UsedUtility, HasUnlockFlag, HasExpireRemove, ProcessCommandLine, ProcessId, InitiatingProcessId
| order by ProcessCreationTime desc
| take 200
pass245.37s0.0122
gpt-5-mini-low
no answer
no query generatedfail50.00s0.0211
gpt-5-mini-medium
no answer
no query generatedfail50.00s0.0150
gpt-5-nano-high
usermod
DeviceProcessEvents
| where tolower(InitiatingProcessFileName) in ("passwd", "usermod", "chage")
| extend Cmd = tostring(InitiatingProcessCommandLine)
| extend CmdLC = tolower(Cmd)
| extend UtilityUsed = case(
    CmdLC contains_cs "passwd", "passwd",
    CmdLC contains_cs "usermod", "usermod",
    CmdLC contains_cs "chage", "chage",
    "unknown")
| extend TargetAccount = tostring(extract(@"([A-Za-z0-9._-]+)$", 1, CmdLC))
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, InitiatingProcessAccountDomain, UtilityUsed, TargetAccount, Cmd, CmdLC
| sort by TimeGenerated desc
pass144.25s0.0027
gpt-5-nano-medium
usermod
DeviceProcessEvents
| where InitiatingProcessFileName in ('usermod','passwd','chage')
   or InitiatingProcessCommandLine contains 'usermod'
   or InitiatingProcessCommandLine contains 'passwd'
   or InitiatingProcessCommandLine contains 'chage'
| extend CmdLine = tostring(InitiatingProcessCommandLine)
| where CmdLine contains '-U' or CmdLine contains '--unlock' or CmdLine contains 'passwd -u' or CmdLine contains 'passwd --unlock' or CmdLine contains 'usermod -U' or CmdLine contains 'usermod --unlock'
| join kind=inner (DeviceInfo | where tolower(OSPlatform) contains 'linux') on DeviceId
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, AccountName, InitiatingProcessFileName, CmdLine
| summarize LastActionTime = max(TimeGenerated) by Actor = InitiatingProcessAccountName, Utility = InitiatingProcessFileName, TargetAccount = AccountName
| sort by LastActionTime desc
| take 5
| project LastActionTime, Actor, Utility, TargetAccount
pass135.51s0.0028
grok-3-beta
no answer
no query generatedfail50.00s0.1552
grok-3-mini-beta
usermod
DeviceProcessEvents
| where ActionType == 'ProcessCreated'
| where ProcessCommandLine contains 'usermod' or ProcessCommandLine contains 'chage' or ProcessCommandLine contains 'passwd'
| where ProcessCommandLine contains '-U' or ProcessCommandLine contains '-E'  // Filtering for unlock (-U) or expiration-related (-E) options
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, FileName
| order by TimeGenerated desc
pass112.27s0.0028
o1-high
usermod
// Replace YOUR_TIME_FILTER with your desired time filter, e.g. TimeGenerated >= ago(7d)
DeviceInfo
| where OSPlatform == "Linux"
| join kind=inner (
    DeviceProcessEvents
    | where ActionType == "ProcessCreated"
    // you can adjust the file names or commands as needed
    | where FileName in~ ("passwd", "usermod", "chage")
    // look for keywords typical of reactivating/unlocking accounts
    | where ProcessCommandLine has_any ("unlock", "-u", "-U", "--unlock")
) on DeviceId
| where TimeGenerated >= ago(7d) // or your custom time filter
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, AccountName, FileName, ProcessCommandLine, FolderPath
| order by TimeGenerated desc
pass122.17s0.2161
o1-low
usermod
DeviceProcessEvents
| join kind=inner (
    DeviceInfo
    | where OSPlatform == "Linux"
    | project DeviceId
) on DeviceId
| where ActionType == "ProcessCreated"
| where FileName in~ ("passwd", "chage", "usermod", "chpasswd")
| where ProcessCommandLine has_any (" -u", " -U", " -e", " -E", "unlock", "unexpire")
| project TimeGenerated, DeviceName, AccountDomain, AccountName, InitiatingProcessAccountName, FileName, ProcessCommandLine
| order by TimeGenerated desc
| limit 100
pass239.26s0.3208
o3-high
usermod
// ---------------------------------------------
// Which Linux user-account utility (passwd/usermod/chage …) was used
// to reactivate a previously locked & expired account?
// ---------------------------------------------
let AccountMgmtBins = dynamic(["passwd","usermod","chage"]);        // common binaries
let UnlockFlags     = dynamic(["-u","-U","--unlock"]);               // unlock a locked account
let ExpireFlags     = dynamic(["-e","-E","--expiredate"]);           // change / reset expiry date (incl. "-E -1")

// 1. Identify Linux endpoints so we don’t mix in Windows data
let LinuxDevices = DeviceInfo
| where OSPlatform =~ "Linux"
| project DeviceId, DeviceName;

// 2. Look for process-creation events that match our criteria
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| join kind=inner (LinuxDevices) on DeviceId
| where FileName in~ (AccountMgmtBins)                               // the binary
      and (ProcessCommandLine has_any (UnlockFlags)                   // unlock flags
           or ProcessCommandLine has_any (ExpireFlags)                // expiry-date flags
           or ProcessCommandLine matches regex "-E\\s+-1")            // typical “set to never expire”

// 3. Surface the interesting information
| extend Utility          = tolower(FileName)
| project TimeGenerated,
          DeviceName,
          Utility,
          InitiatingUser   = InitiatingProcessAccountName,
          ProcessCommandLine

// 4. Summarise so we can see which utility was used and when
| summarize FirstSeen = min(TimeGenerated),
            LastSeen  = max(TimeGenerated),
            Executions = count(),
            ExampleCmds = make_set(ProcessCommandLine, 5)
            by Utility
| order by LastSeen desc
pass265.16s0.0451
o3-mini-high
usermod
DeviceProcessEvents
// Timerange is set externally via function parameters
| where FileName in ("usermod", "passwd", "chage")
| where ProcessCommandLine has_any ("-U", "--unlock", "unlock")
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, AccountName
| distinct TimeGenerated, DeviceName, FileName, ProcessCommandLine, AccountName
pass234.94s0.0195
o3-mini-low
usermod
DeviceProcessEvents
| where FileName has_any ("usermod", "passwd")
| where ProcessCommandLine contains "-U"
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, InitiatingProcessAccountName
| order by TimeGenerated desc
pass111.43s0.0111
o4-mini-high
usermod
DeviceProcessEvents
// Limit to process creation events
| where ActionType in ("ProcessCreated", "Start", "ProcessStart")
// Focus on known user account management utilities
| where FileName in ("passwd", "usermod", "chage", "gpasswd")
// Look for flags related to unlocking or re‐enabling accounts
| extend Cmd = ProcessCommandLine
| where Cmd has_any ("--unlock", "-u", "-U", "--expire", "-E")
// Only successful operations (if exit code is captured)
| extend ExitCode = toint(AdditionalFields.ExitCode)
| where isnull(ExitCode) or ExitCode == 0
// Restrict to Linux devices
| join kind=inner (
    DeviceInfo
    | where OSPlatform == "Linux"
    | project DeviceId, OSPlatform
) on DeviceId
// Present the key details
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, FileName, ProcessCommandLine, ExitCode
| sort by TimeGenerated desc
pass372.29s0.0326
o4-mini-low
usermod
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where FileName in ("passwd", "usermod", "chage")
| extend LowerCmd = tolower(ProcessCommandLine)
// passwd unlock flags, usermod unlock flags, chage expiredate flags
| where (FileName == "passwd" and (LowerCmd contains "-u " or LowerCmd contains "--unlock"))
      or (FileName == "usermod" and (LowerCmd contains "-u " or LowerCmd contains "--unlock"))
      or (FileName == "chage" and (LowerCmd contains "-e " or LowerCmd contains "--expiredate"))
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, FileName, ProcessCommandLine
| order by TimeGenerated asc
pass263.73s0.0179