// question

In a Linux environment, you observe a process labeled like the cron daemon but running from an unexpected path. Investigate creation events to uncover the actual filename used by this fake cron process.

Reference KQL answer and model-by-model comparison.

a315bfff-7a98-403b-b442-2ea1b255e556
question id
11/23
models correct
1
valid answer
48%
success rate
// reference answer

Human-validated correct answer for this question.

crond
// model comparison
ModelAnswerKQL queryStatusTriesTimeCost
gemini-2.5-flash-preview-04-17
crond
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where FileName contains "cron"
| where strcat(FolderPath, "/", FileName) !in ("/usr/sbin/cron", "/usr/bin/cron", "/sbin/cron")
| project TimeGenerated, DeviceName, FileName, FolderPath, ProcessCommandLine, InitiatingProcessCommandLine, ProcessId
pass115.22s0.0071
gpt-35-turbo
no answer
no query generatedfail50.00s0.0110
gpt-4-turbo-2024-04-09
crond
DeviceProcessEvents
| where FileName contains 'cron' and not(FolderPath startswith '/usr/sbin/')
| project DeviceName, FileName, FolderPath, ProcessCommandLine, ProcessCreationTime, InitiatingProcessCommandLine, InitiatingProcessFileName, InitiatingProcessFolderPath
| order by ProcessCreationTime desc
pass215.92s0.0998
gpt-4.1
cron
DeviceProcessEvents
| where FileName == "cron"
| where FolderPath !in ("/usr/sbin", "/usr/bin")
// Optionally: add more standard cron paths as needed
| project TimeGenerated, DeviceName, AccountName, FolderPath, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessFolderPath, SHA256
| order by TimeGenerated desc
fail18.09s0.0169
gpt-4.1-finetuned
no answer
no query generatedfail50.00s0.0725
gpt-4.1-mini
crond
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where FileName contains "cron"
| where FolderPath !contains "/usr/sbin/" and FolderPath !contains "/usr/bin/" and FolderPath !contains "/bin/"
| project DeviceName, FileName, FolderPath, ProcessCreationTime, ProcessCommandLine, InitiatingProcessFileName
| sort by ProcessCreationTime desc
pass27.14s0.0030
gpt-4.1-nano
no answer
no query generatedfail50.00s0.0017
gpt-4o
no answer
no query generatedfail50.00s0.0478
gpt-5-high
crond
let LinuxDevices = DeviceInfo
| where OSPlatform =~ "Linux"
| summarize arg_max(TimeGenerated, DeviceName) by DeviceId
| project DeviceId, DeviceName;
let SuspiciousCronProcs =
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| join kind=inner (LinuxDevices) on DeviceId
| extend fn = tolower(FileName),
         fp = tolower(FolderPath),
         pcmd = tostring(ProcessCommandLine),
         ipcmd = tostring(InitiatingProcessCommandLine)
| extend LabeledCron = fn in ("cron","crond")
| extend ExecASpoof = pcmd has "exec -a cron" or pcmd has "exec -a crond" or ipcmd has "exec -a cron" or ipcmd has "exec -a crond"
| extend ExpectedCronDir = fp startswith "/usr/sbin/" or fp startswith "/sbin/"
| where (LabeledCron and ExpectedCronDir == false) or ExecASpoof
| extend ExecAChildTarget = extract(@"(?i)exec\s+-a\s+\S+\s+(\S+)", 1, pcmd)
| extend ExecAParentTarget = extract(@"(?i)exec\s+-a\s+\S+\s+(\S+)", 1, ipcmd)
| extend ActualExecutedBinaryRaw = coalesce(ExecAChildTarget, ExecAParentTarget, FolderPath)
| extend ActualExecutedBinary = trim(" '\"", ActualExecutedBinaryRaw)
| extend CronLabelUsed = iif(LabeledCron, FileName,
                             coalesce(
                               extract(@"(?i)exec\s+-a\s+((cron|crond))\b", 1, pcmd),
                               extract(@"(?i)exec\s+-a\s+((cron|crond))\b", 1, ipcmd)))
| extend ActualExecutedFileName = extract(@"([^/\\]+)$", 1, ActualExecutedBinary)
| project CronProcTime=TimeGenerated, DeviceId, DeviceName, CronLabelUsed,
          OnDiskImagePath=FolderPath, ActualExecutedBinary, ActualExecutedFileName,
          ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine,
          SHA256, MD5, ReportId;
let FileHistory =
DeviceFileEvents
| where ActionType in ("FileCreated","FileRenamed")
| project DeviceId,
          FileEventTime=TimeGenerated,
          FileEventAction=ActionType,
          FilePath=FolderPath,
          NewFileName=FileName,
          PreviousPath=strcat(PreviousFolderPath, iif(isempty(PreviousFileName), "", strcat("/", PreviousFileName)));
let Base =
SuspiciousCronProcs
| extend FileEventTime = datetime(null), FileEventAction = "", FilePath = "", PreviousPath = "", NewFileName = "";
let OnDiskJoin =
SuspiciousCronProcs
| join kind=leftouter (FileHistory) on $left.DeviceId == $right.DeviceId and $left.OnDiskImagePath == $right.FilePath
| where isnotempty(FileEventTime) and FileEventTime between (CronProcTime - 14d .. CronProcTime + 1h)
| project-away FilePath;
let ActualExecJoin =
SuspiciousCronProcs
| where ActualExecutedBinary startswith "/"
| join kind=leftouter (FileHistory) on $left.DeviceId == $right.DeviceId and $left.ActualExecutedBinary == $right.FilePath
| where isnotempty(FileEventTime) and FileEventTime between (CronProcTime - 14d .. CronProcTime + 1h)
| project-away FilePath;
union Base, OnDiskJoin, ActualExecJoin
| order by CronProcTime desc, FileEventTime asc
pass5756.55s0.4008
gpt-5-mini-high
no answer
no query generatedfail50.00s0.0233
gpt-5-mini-low
/tmp/crond/crond
// Investigate fake cron-like processes on Linux and find the actual filename used by the fake cron binary
let lookback = 14d;
let legit_paths = dynamic(["/usr/sbin/cron","/usr/bin/cron","/sbin/cron","/bin/cron"]);

// Candidate process events that mention cron in file name or command line
let SuspiciousProcs =
DeviceProcessEvents
| where TimeGenerated >= ago(lookback)
// Best-effort Linux filter: unix-like FolderPath or DeviceName containing linux
| where isnotempty(FolderPath) and FolderPath contains "/" or tolower(DeviceName) has "linux"
| where tolower(FileName) has "cron" or tolower(ProcessCommandLine) has "cron" or tolower(ProcessCommandLine) has "crond"
| extend observed_name = FileName, observed_cmd = ProcessCommandLine,
         observed_path = iif(isnotempty(FolderPath) and isnotempty(FileName), strcat(FolderPath, "/", FileName), tostring(FileName))
// exclude processes running from known legit cron paths
| where not(
    tolower(observed_path) startswith tolower(legit_paths[0])
    or tolower(observed_path) startswith tolower(legit_paths[1])
    or tolower(observed_path) startswith tolower(legit_paths[2])
    or tolower(observed_path) startswith tolower(legit_paths[3])
)
| project ProcTime=TimeGenerated, DeviceName, ProcessId, observed_name, observed_cmd, observed_path, InitiatingProcessFileName, InitiatingProcessCommandLine, SHA256, MD5;

// File events that could indicate creation/deployment of the fake cron binary
let FileCreates =
DeviceFileEvents
| where TimeGenerated >= ago(lookback)
| where ActionType has_any ("Create","Created","Copy","Copied","Move","Moved","Write","Written")
| where tolower(FileName) has "cron" or tolower(FolderPath) has "cron" or tolower(PreviousFileName) has "cron" or tolower(PreviousFolderPath) has "cron"
| project FileTime=TimeGenerated, FileDeviceName=DeviceName, FileName, FolderPath, PreviousFileName, PreviousFolderPath, MD5, SHA256, FileOriginUrl, FileOriginIP, ActionType;

// Join processes to file create events on device and within a time window (1 hour before/after process start)
SuspiciousProcs
| join kind=leftouter (
    FileCreates
) on $left.DeviceName == $right.FileDeviceName
| where FileTime between (ProcTime - 1h .. ProcTime + 1h) or isnull(FileTime)
| extend creation_time = coalesce(FileTime, ProcTime)
| project creation_time, DeviceName, ProcessId, observed_name, observed_path, observed_cmd, FileName, FolderPath, PreviousFileName, PreviousFolderPath, ActionType, MD5 = coalesce(MD5, SHA256), SHA256, FileOriginUrl, FileOriginIP
| distinct DeviceName, ProcessId, observed_name, observed_path, observed_cmd, FileName, FolderPath, PreviousFileName, PreviousFolderPath, ActionType, MD5, SHA256, FileOriginUrl, FileOriginIP, creation_time
| sort by creation_time desc
| take 500
pass457.10s0.0140
gpt-5-mini-medium
no answer
no query generatedfail50.00s0.0160
gpt-5-nano-high
/tmp/crond/crond
let TimeRange = 14d;
DeviceProcessEvents
| where InitiatingProcessCreationTime >= ago(TimeRange)
| where (tolower(InitiatingProcessFileName) contains "cron" or tolower(InitiatingProcessCommandLine) contains "cron" or tolower(FileName) contains "cron" or tolower(InitiatingProcessFolderPath) contains "cron")
| extend InitiatingPath = strcat(InitiatingProcessFolderPath, "/", InitiatingProcessFileName)
| join kind=leftouter (
    DeviceFileEvents
    | project InitiatingProcessId, FileName, FolderPath, PreviousFileName, PreviousFolderPath
) on InitiatingProcessId
| project TimeGenerated = InitiatingProcessCreationTime, DeviceName, DeviceId, InitiatingProcessId, InitiatingProcessFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine, InitiatingPath, FileName, FolderPath, PreviousFileName, PreviousFolderPath
| sort by TimeGenerated desc
| take 200
pass275.33s0.0056
gpt-5-nano-medium
crond
DeviceProcessEvents
| where TimeGenerated >= ago(24h)
| where (tolower(InitiatingProcessFileName) contains "cron" or tolower(FileName) contains "cron" or tolower(ProcessCommandLine) contains "cron")
| where not (tolower(InitiatingProcessFolderPath) contains "/usr/bin" or tolower(InitiatingProcessFolderPath) contains "/usr/sbin" or tolower(InitiatingProcessFolderPath) contains "/bin" or tolower(InitiatingProcessFolderPath) contains "/sbin")
| project TimeGenerated, InitiatingProcessCreationTime, InitiatingProcessFileName, InitiatingProcessFolderPath, ProcessCommandLine, FileName, FolderPath, DeviceName, DeviceId, InitiatingProcessId, InitiatingProcessMD5, InitiatingProcessSHA256
pass138.32s0.0029
grok-3-beta
crond
DeviceProcessEvents
| where FileName contains "cron"
| where FolderPath !startswith "/usr/sbin/" and FolderPath !startswith "/usr/bin/"
| project DeviceName, FileName, FolderPath, ProcessCreationTime, ProcessCommandLine, SHA1, SHA256, Timestamp
| order by Timestamp desc
pass215.41s0.0381
grok-3-mini-beta
cron
let linuxDevices = DeviceInfo | where OSPlatform == "Linux" | distinct DeviceId;
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where FileName =~ "cron"
| where DeviceId in (linuxDevices)
| project TimeGenerated, DeviceName, DeviceId, FileName, FolderPath, ProcessCommandLine
| order by TimeGenerated desc
fail119.44s0.0021
o1-high
crond
DeviceInfo
| where OSPlatform == "Linux"
| distinct DeviceId
| join kind=inner (
    DeviceProcessEvents
    | where ActionType == "ProcessCreated"
    // Catch partial matches on the name "cron"
    | where FileName contains "cron"
    // Exclude typical cron binaries/paths
    | where FolderPath !startswith "/usr/bin"
      and FolderPath !startswith "/usr/sbin"
      and FolderPath !startswith "/bin"
      and FolderPath !startswith "/sbin"
    | project TimeGenerated, DeviceId, DeviceName, AccountName, FolderPath, FileName,
        ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
) on DeviceId
| project TimeGenerated, DeviceName, AccountName, FolderPath, FileName,
    ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by TimeGenerated desc
pass3109.09s0.6143
o1-low
no answer
no query generatedfail50.00s1.1339
o3-high
no answer
no query generatedfail50.00s0.1020
o3-mini-high
crond
DeviceProcessEvents
| where ActionType == "ProcessCreated"
// Look for processes with 'cron' in the name
| where FileName contains "cron"
// Exclude typical cron daemon location; adjust the path condition as needed
| where FolderPath !contains "/usr/sbin"
| extend ExecutablePath = strcat(FolderPath, "/", FileName)
| project TimeGenerated, DeviceName, FileName, FolderPath, ExecutablePath, ProcessCommandLine, InitiatingProcessCommandLine
| sort by TimeGenerated desc
pass114.60s0.0136
o3-mini-low
crond
DeviceProcessEvents
| where FileName contains "cron"
// Filter out known legitimate cron daemon location
| where FolderPath !startswith "/usr/sbin/"
// Optionally, you can add additional filters for Linux environment if available
| project TimeGenerated, DeviceName, FileName, FolderPath, ProcessCommandLine
| sort by TimeGenerated desc
pass121.77s0.0118
o4-mini-high
no answer
no query generatedfail50.00s0.0422
o4-mini-low
no answer
no query generatedfail50.00s0.0526