// question

On Linux, review file events for changes in the system-wide shell profile directory. Determine the name of the script file in /etc/profile.d that shows evidence of an unauthorized append.

Reference KQL answer and model-by-model comparison.

8fe2ccfd-f079-4c03-b1a9-bd9b362b67d4
question id
7/23
models correct
1
valid answer
30%
success rate
// reference answer

Human-validated correct answer for this question.

bash_completion.sh
// model comparison
ModelAnswerKQL queryStatusTriesTimeCost
gemini-2.5-flash-preview-04-17
no answer
no query generatedfail50.00s0.0189
gpt-35-turbo
no answer
no query generatedfail50.00s0.0108
gpt-4-turbo-2024-04-09
no answer
no query generatedfail50.00s0.2259
gpt-4.1
bash_completion.sh
DeviceFileEvents
| where FolderPath startswith "/etc/profile.d"
| where ActionType in~ ("FileModified", "FileCreated", "FileAppended")
| extend operationType = tostring(parse_json(tostring(AdditionalFields))["operationType"])
| where isempty(operationType) or operationType has_any("append", "Appended", "APPEND")
| project TimeGenerated, DeviceName, FileName, FolderPath, InitiatingProcessAccountName, InitiatingProcessCommandLine, ActionType, operationType
| order by TimeGenerated desc
pass213.00s0.0228
gpt-4.1-finetuned
no answer
no query generatedfail50.00s0.0423
gpt-4.1-mini
no answer
no query generatedfail50.00s0.0073
gpt-4.1-nano
no answer
no query generatedfail50.00s0.0013
gpt-4o
no answer
no query generatedfail50.00s0.0534
gpt-5-high
bash_completion.sh
let profileDir = "/etc/profile.d/";
DeviceFileEvents
| join kind=inner (
    DeviceInfo
    | where OSPlatform == "Linux"
    | project DeviceId
) on DeviceId
| where FolderPath startswith profileDir
| where ActionType in ("FileCreated", "FileModified", "FileRenamed", "FileContentModified")
| where InitiatingProcessCommandLine has ">>" 
    or InitiatingProcessCommandLine has "tee -a"
    or tostring(AdditionalFields) contains "O_APPEND"
| project TimeGenerated, DeviceName, FolderPath, FileName, ActionType,
          InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by TimeGenerated desc
| summarize Latest=max(TimeGenerated), SampleCommands=make_set(InitiatingProcessCommandLine, 5) by FileName, FolderPath
| order by Latest desc
pass170.41s0.0464
gpt-5-mini-high
no answer
no query generatedfail50.00s0.0215
gpt-5-mini-low
bash_completion.sh
let targetDir = '/etc/profile.d';

// File-level events touching /etc/profile.d
let fileEvents = DeviceFileEvents
| where isnotempty(FolderPath)
| where FolderPath has targetDir
| where tolower(coalesce(ActionType,'')) has_any('modify','write','append','create','change','overwrite')
    or FileName endswith '.sh'
    or tostring(AdditionalFields) contains 'append'
| extend FullPath = replace_string(strcat(FolderPath, '/', FileName), '//', '/')
| project TimeGenerated, DeviceName, FullPath, FolderPath, FileName, ActionType, FileSize, PreviousFileName, PreviousFolderPath, AdditionalFields, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessAccountName, Source = 'fileEvent';

// Process events that indicate appending/redirecting into /etc/profile.d
let procAppendIndicators = DeviceProcessEvents
| where isnotempty(ProcessCommandLine)
| where tolower(ProcessCommandLine) contains '>>' or tolower(ProcessCommandLine) contains 'tee -a' or ProcessCommandLine matches regex '(>/etc/profile.d/|>>/etc/profile.d/|tee\\s+-a\\s+/etc/profile.d/|echo\\s+.*>>\\s*/etc/profile.d/)'
| extend FileMention = extract('/etc/profile.d/([^\\s/]+)', 1, ProcessCommandLine)
| extend FullPath = iif(isnotempty(FileMention), strcat('/etc/profile.d/', FileMention), '')
| project TimeGenerated, DeviceName, FullPath, ProcessCommandLine, ProcessId, ProcessFileName = FileName, InitiatingProcessAccountName = AccountName, Source = 'procEvent';

// Combine and summarize suspicious script names
fileEvents
| union procAppendIndicators
| extend SuspectReason = case(
    tostring(AdditionalFields) contains 'append', 'AdditionalFields indicates append',
    tolower(coalesce(InitiatingProcessCommandLine, ProcessCommandLine, '')) contains '>>' or tolower(coalesce(InitiatingProcessCommandLine, ProcessCommandLine, '')) contains 'tee -a', 'Process command line shows append/tee -a',
    tolower(coalesce(ActionType,'')) contains 'create', 'Created',
    'File modified or accessed')
| extend ScriptName = tostring(coalesce(FileName, extract('/etc/profile.d/([^/\\s]+)',1,FullPath)))
| where isnotempty(ScriptName)
| summarize Count = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), Devices = make_set(DeviceName, 50), Commands = make_set(coalesce(InitiatingProcessCommandLine, ProcessCommandLine), 50), Reasons = make_set(SuspectReason, 10) by ScriptName, FullPath
| order by Count desc
| take 50
pass377.76s0.0177
gpt-5-mini-medium
bash_completion.sh
union DeviceFileEvents, DeviceEvents
| where FolderPath has "/etc/profile.d"
// Narrow to likely shell/profile scripts
| where FileName endswith ".sh" or FileName contains "profile" or FileName contains ".bash"
| extend FullPath = strcat(FolderPath, iff(FolderPath endswith "/", "", "/"), FileName)
// normalize command/source fields across tables
| extend initiating_cmd = coalesce(InitiatingProcessCommandLine, ProcessCommandLine, AdditionalFields.CommandLine, tostring(AdditionalFields.CommandLine), "")
| extend initiator = coalesce(InitiatingProcessFileName, InitiatingProcessFileName, "(unknown)")
// look for evidence of append operations or commands that append content
| where initiating_cmd contains ">>" or initiating_cmd contains "tee -a" or initiating_cmd matches regex @"\becho\b.*>>" or initiating_cmd matches regex @"\bprintf\b.*>>" or initiating_cmd matches regex @"\btee\b.*-a"
| project TimeGenerated, DeviceName, initiator, InitiatingProcessAccountName, FileName, FullPath, ActionType, initiating_cmd, PreviousFileName, MD5, SHA256
| summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), Count=count(), SampleCommand=any(initiating_cmd), InitiatingProcesses=make_set(initiator, 5) by FileName, FullPath, DeviceName, MD5, SHA256
| sort by LastSeen desc, Count desc
| take 50
pass124.43s0.0059
gpt-5-nano-high
no answer
no query generatedfail50.00s0.0074
gpt-5-nano-medium
no answer
no query generatedfail50.00s0.0077
grok-3-beta
bash_completion.sh
DeviceFileEvents
| where FolderPath contains "/etc/profile.d"
| where ActionType in ("FileModified", "FileCreated")
| join kind=inner (
    DeviceInfo
    | where OSPlatform == "Linux"
) on DeviceId
| project Timestamp, DeviceName, FileName, FolderPath, ActionType, InitiatingProcessFileName, InitiatingProcessAccountName, InitiatingProcessCommandLine
| order by Timestamp desc
pass110.79s0.0270
grok-3-mini-beta
bash_completion.sh
DeviceInfo
| where OSPlatform == 'Linux'
| project DeviceId, DeviceName
| join kind=inner (
    DeviceFileEvents
    | where FolderPath startswith '/etc/profile.d/'
    | where ActionType has_any ('FileModified', 'FileCreated')  // Targeting common actions for modifications or creations that could involve appends
    | where InitiatingProcessCommandLine contains '>>' or InitiatingProcessCommandLine contains 'echo'  // Filtering for command lines that suggest appending content
    | project DeviceId, FileName, ActionType, Timestamp, InitiatingProcessCommandLine
) on DeviceId
| summarize arg_max(Timestamp, *) by DeviceId, FileName
| project DeviceId, DeviceName, FileName, ActionType, Timestamp, InitiatingProcessCommandLine
| order by Timestamp desc
pass454.15s0.0060
o1-high
no answer
no query generatedfail50.00s0.7645
o1-low
bash_completion.sh
DeviceInfo
| where OSPlatform =~ "Linux"
| distinct DeviceId, DeviceName
| join kind=inner (
    DeviceFileEvents
    // Look for events within /etc/profile.d directory
    | where FolderPath startswith "/etc/profile.d"
    // Filter by file actions that may signify a file write or append
    | where ActionType in ("FileModified", "FileCreated", "FileAppended") or AdditionalFields has "append"
) on DeviceId
| project TimeGenerated,
          DeviceName,
          FolderPath,
          FileName,
          ActionType,
          InitiatingProcessAccountName,
          InitiatingProcessCommandLine,
          AdditionalFields
| order by TimeGenerated desc
pass480.37s0.6488
o3-high
no answer
no query generatedfail50.00s0.0828
o3-mini-high
no answer
no query generatedfail50.00s0.0423
o3-mini-low
no answer
no query generatedfail50.00s0.0375
o4-mini-high
no answer
no query generatedfail50.00s0.0404
o4-mini-low
no answer
no query generatedfail50.00s0.0408