// question

In a Linux environment, an elevated process was used to execute a command that read /etc/shadow and redirected its output to a file. Identify what file name was employed to store these results.

Reference KQL answer and model-by-model comparison.

3723ab77-c546-403c-8fb4-bb577033b235
question id
6/23
models correct
1
valid answer
26%
success rate
// reference answer

Human-validated correct answer for this question.

T1003.008.txt
// model comparison
ModelAnswerKQL queryStatusTriesTimeCost
gemini-2.5-flash-preview-04-17
no answer
no query generatedfail50.00s0.0292
gpt-35-turbo
no answer
no query generatedfail50.00s0.0109
gpt-4-turbo-2024-04-09
no answer
no query generatedfail50.00s0.2304
gpt-4.1
no answer
no query generatedfail50.00s0.0514
gpt-4.1-finetuned
no answer
no query generatedfail50.00s0.0521
gpt-4.1-mini
no answer
no query generatedfail50.00s0.0079
gpt-4.1-nano
no answer
no query generatedfail50.00s0.0015
gpt-4o
no answer
no query generatedfail50.00s0.0539
gpt-5-high
T1003.008.txt
let ShadowRedirects = 
DeviceProcessEvents
| join kind=inner (DeviceInfo | project DeviceId, OSPlatform) on DeviceId
| where OSPlatform =~ "Linux"
| where ActionType == "ProcessCreated"
| where ProcessCommandLine has "/etc/shadow" and (ProcessCommandLine contains '>' or ProcessCommandLine has 'tee')
// Extract redirection targets: >, >>, 1>, 1>> with optional quotes
| extend redirect_dq = extract(@'(?:(?:^|[\s;|&]))(?:\d?>{1,2})\s*"(.*?)"', 1, ProcessCommandLine)
| extend redirect_sq = extract(@'(?:(?:^|[\s;|&]))(?:\d?>{1,2})\s*''([^'']+)''', 1, ProcessCommandLine)
| extend redirect_uq = extract(@'(?:(?:^|[\s;|&]))(?:\d?>{1,2})\s*([^\s;|&]+)', 1, ProcessCommandLine)
// Extract tee target (first non-option arg after tee)
| extend tee_dq = extract(@'\btee\b\s+(?:-[A-Za-z-]+\s+)*"(.*?)"', 1, ProcessCommandLine)
| extend tee_sq = extract(@'\btee\b\s+(?:-[A-Za-z-]+\s+)*''([^'']+)''', 1, ProcessCommandLine)
| extend tee_uq = extract(@'\btee\b\s+(?:-[A-Za-z-]+\s+)*([^\s;|&]+)', 1, ProcessCommandLine)
| extend OutputPath = coalesce(redirect_dq, redirect_sq, redirect_uq, tee_dq, tee_sq, tee_uq)
| where isnotempty(OutputPath)
// Elevated process heuristics
| where tolower(AccountName) == "root"
    or tolower(InitiatingProcessAccountName) == "root"
    or tostring(ProcessTokenElevation) =~ "Elevated"
    or tostring(InitiatingProcessTokenElevation) =~ "Elevated"
    or ProcessCommandLine has "sudo "
    or ProcessCommandLine has "su -c"
| extend OutputFileName = tostring(extract(@'([^/\\]+)$', 1, OutputPath))
| project TimeGenerated, DeviceId, DeviceName, AccountName, InitiatingProcessAccountName, ProcessCommandLine, OutputPath, OutputFileName;
// Report the file name(s) used to store results
ShadowRedirects
| summarize Events=count(), Devices=dcount(DeviceId), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated) by OutputFileName, OutputPath
| order by LastSeen desc
pass2159.15s0.1139
gpt-5-mini-high
no answer
no query generatedfail50.00s0.0190
gpt-5-mini-low
no answer
no query generatedfail50.00s0.0213
gpt-5-mini-medium
redirected
let shadow_patterns = dynamic(["/etc/shadow","etc/shadow","shadow"]);
// Find process events where the initiating process command line reads /etc/shadow and uses redirection
DeviceProcessEvents
| where TimeGenerated between (startofday(ago(30d)) .. now())
| where isnotempty(InitiatingProcessCommandLine) or isnotempty(ProcessCommandLine)
| extend cmd = coalesce(InitiatingProcessCommandLine, ProcessCommandLine)
| where cmd has "/etc/shadow" or cmd has "etc/shadow"
| where cmd matches regex @"[>]{1,2}\s*[^\s]+$" or cmd contains ">" or cmd contains ">>"
| extend redirected = extract(@"[>]{1,2}\s*([^\s]+)$", 1, cmd)
| extend redirected = trim('\"''', redirected)
| extend InitiatingAccount = strcat(InitiatingProcessAccountDomain, "\\", InitiatingProcessAccountName)
| project TimeGenerated, DeviceName, InitiatingAccount, InitiatingProcessFileName, InitiatingProcessId, InitiatingProcessCommandLine, ProcessCommandLine, redirected
| where isnotempty(redirected)
| summarize any(InitiatingProcessFileName), any(DeviceName), any(InitiatingAccount), any(InitiatingProcessId), make_set(redirected) by redirected
| order by tostring(redirected) asc

// Additionally, search DeviceFileEvents for writes that could be the target file

| union (
    DeviceFileEvents
    | where TimeGenerated between (startofday(ago(30d)) .. now())
    | where ActionType in ("FileCreated", "FileModified", "FileWritten", "FileCreatedByProcess") or FileName has_any ("shadow", "shadow_export")
    | extend fullpath = strcat(FolderPath, "/", FileName)
    | project TimeGenerated, DeviceName, InitiatingProcessAccountName, InitiatingProcessCommandLine, fullpath
)

| summarize by redirected
fail126.76s0.0030
gpt-5-nano-high
no answer
no query generatedfail50.00s0.0081
gpt-5-nano-medium
no answer
no query generatedfail50.00s0.0070
grok-3-beta
no answer
no query generatedfail50.00s0.0985
grok-3-mini-beta
no answer
no query generatedfail50.00s0.0078
o1-high
no answer
no query generatedfail50.00s0.7707
o1-low
no answer
no query generatedfail50.00s1.1187
o3-high
/tmp/T1003.008.txt
let LinuxDevices = DeviceInfo
| where OSPlatform startswith "Linux"
| distinct DeviceId;
DeviceProcessEvents
| where DeviceId in (LinuxDevices)
// Command reads /etc/shadow and uses a redirection operator
| where ProcessCommandLine has "/etc/shadow" and ProcessCommandLine contains ">"
// Running with elevated privileges
| extend IsElevated = iff(tolower(AccountName) == "root" or
                          tolower(InitiatingProcessAccountName) == "root" or
                          tostring(ProcessTokenElevation) contains "Elevated" or
                          tostring(ProcessTokenElevation) contains "Root", true, false)
| where IsElevated
// Extract the file name/path that receives the redirected output
| extend RedirectedFile = trim('"\'"', tostring(extract(@"(?:>>?)\s*([^\s]+)", 1, ProcessCommandLine)))
| where isnotempty(RedirectedFile)
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, RedirectedFile
| order by TimeGenerated desc
pass390.28s0.0558
o3-mini-high
T1003.008.txt
DeviceProcessEvents
| where ProcessCommandLine contains "/etc/shadow" and ProcessCommandLine contains ">"
| extend output_file = extract(@">\s*(\S+)", 1, ProcessCommandLine)
| project TimeGenerated, DeviceName, ProcessCommandLine, output_file
| order by TimeGenerated desc
pass117.91s0.0127
o3-mini-low
/tmp/T1003.008.txt
DeviceProcessEvents
| where InitiatingProcessCommandLine has "/etc/shadow"
| where InitiatingProcessCommandLine contains ">"
| extend output_file = extract(@">\s*([^\s]+)", 1, InitiatingProcessCommandLine)
| where isnotempty(output_file)
| project TimeGenerated, DeviceName, InitiatingProcessCommandLine, output_file
| distinct output_file
pass161.90s0.0122
o4-mini-high
/tmp/T1003.008.txt;
DeviceProcessEvents
// Only processes run by root
| where AccountName == "root"
// Look for reading /etc/shadow and using shell redirection (> or >>)
| where ProcessCommandLine has "/etc/shadow" and ProcessCommandLine matches regex @"\>{1,2}"
// Extract the path/file following the redirection operator
| extend OutputFile = extract(@"\>{1,2}\s*(\S+)", 1, ProcessCommandLine)
| where isnotempty(OutputFile)
// Show relevant fields
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, OutputFile
// Summarize to see unique files and their timelines
| summarize FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), Occurrences = count() by OutputFile, DeviceName, AccountName
| order by LastSeen desc
pass261.35s0.0192
o4-mini-low
/tmp/T1003.008.txt
DeviceProcessEvents
| where ProcessCommandLine contains "/etc/shadow"
| where ProcessCommandLine matches regex @">\s*\S+"
| where InitiatingProcessAccountName == "root"
| extend OutputFile = extract(@">\s*(\S+)", 1, ProcessCommandLine)
| where isnotempty(OutputFile)
| distinct OutputFile
pass136.91s0.0127