Question Analysis
On a Linux system, analyze the process logs for suspicious command line activity that includes a sequence of commands indicating a pipe-to-shell operation. Identify the tool that was used to execute this piped command, paying special attention to its use in downloading and running script content.
fca246a8-a585-4f28-a2df-6495973976a1
Question ID
3/23
Models Correct
1
Valid Answer
13%
Success Rate
Reference Answer
Human-validated correct answer for this question
bash
Model Performance Comparison
See how different AI models performed on this question
Model | Answer | KQL Query | Status | Attempts | Time | Cost |
---|---|---|---|---|---|---|
gemini-2.5-flash-preview-04-17 | bash | DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where ProcessCommandLine matches regex @".*\|\s*(bash|sh|python|pwsh)"
| project Timestamp, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, AccountName, ReportId | Correct | 1 | 37.41s | 0.0233 |
gpt-35-turbo | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0118 |
gpt-4-turbo-2024-04-09 | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.2314 |
gpt-4.1 | curl | DeviceProcessEvents
| where ProcessCommandLine contains '|'
| where ProcessCommandLine matches regex @"\|\s*(sh|bash|zsh|/bin/sh|/bin/bash|/bin/zsh)"
| extend download_tool = case(ProcessCommandLine has "curl", "curl", ProcessCommandLine has "wget", "wget", ProcessCommandLine has "python", "python", "other")
| extend script_url = extract("(https?://[^ |;]+)", 1, ProcessCommandLine)
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, download_tool, script_url, InitiatingProcessCommandLine, InitiatingProcessFileName, FolderPath | Incorrect | 2 | 22.32s | 0.0456 |
gpt-4.1-finetuned | python3 | let whitelisted_tools = dynamic(["at", "batch", "bc", "bash", "curl", "ftp", "ksh", "mksh", "openssl", "php", "nc", "ncat", "netcat", "paste", "perl", "ps", "python2", "python3", "rpm", "sh", "sort", "ssh", "telnet", "timeout", "vi", "watch", "zsh"]);
DeviceProcessEvents
| where ProcessCommandLine contains "|" and ProcessCommandLine contains "%"
| extend pattern = extract(@"([a-zA-Z]+)\s*\|\s*\%*", 1, ProcessCommandLine)
| where isnotnull(pattern) and pattern !in (whitelisted_tools)
| summarize count() by DeviceName, SHA256, ProcessCommandLine, pattern, AccountName
| sort by count_ desc
| extend AccountName = tostring(split(AccountName, "@", 0)[0])
| extend UPNSuffix = tostring(split(AccountName, "@", 1)[1])
| Incorrect | 2 | 22.14s | 0.0266 |
gpt-4.1-mini | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0064 |
gpt-4.1-nano | unknown | DeviceProcessEvents
| where FileName in~ ('bash', 'sh', 'dash')
| where ProcessCommandLine contains '| sh' or ProcessCommandLine contains '| bash' or ProcessCommandLine contains '|python' or ProcessCommandLine contains '|curl' or ProcessCommandLine contains '|wget'
| extend toolUsed = case(
ProcessCommandLine contains '| curl', 'curl',
ProcessCommandLine contains '| wget', 'wget',
ProcessCommandLine contains '| python', 'python',
'unknown')
| project ProcessId, ProcessCommandLine, toolUsed, InitiatingProcessFileName, InitiatingProcessCreationTime, DeviceName | Incorrect | 1 | 3.76s | 0.0010 |
gpt-4o | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0653 |
gpt-5-high | sh | let LinuxDevices = DeviceInfo
| where OSPlatform =~ "Linux"
| distinct DeviceId;
let SuspiciousPipeToShell =
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where DeviceId in (LinuxDevices)
| where isnotempty(ProcessCommandLine)
| extend cmd_l = tolower(ProcessCommandLine)
| where cmd_l contains "|"
| extend parts = split(cmd_l, "|")
| extend rhs = trim(" ", tostring(parts[array_length(parts)-1])),
lhs = trim(" ", tostring(parts[0]))
| extend rhs_first = tostring(split(rhs, " ")[0]),
rhs_second = tostring(split(rhs, " ")[1])
| extend rhs_first_base = tostring(split(rhs_first, "/")[array_length(split(rhs_first, "/"))-1])
// Identify the shell used to execute the piped content
| extend ToolUsedToExecute = case(
rhs_first_base == "busybox" and rhs_second in ("sh","ash"), strcat("busybox ", rhs_second),
rhs_first_base in ("sh","bash","zsh","ksh","dash","ash","/bin/sh","/bin/bash","/usr/bin/sh","/usr/bin/bash"), rhs_first_base,
""
)
| where ToolUsedToExecute != ""
// Identify the downloader on the left side of the pipe
| extend DownloaderTool = case(
lhs contains "curl", "curl",
lhs contains "wget", "wget",
lhs contains "aria2c", "aria2c",
lhs contains "lwp-download", "lwp-download",
lhs contains "fetch", "fetch",
lhs contains "tftp", "tftp",
lhs contains " ncat", "ncat",
lhs contains " nc ", "nc",
lhs contains "openssl", "openssl",
lhs contains "python", "python",
lhs contains "perl", "perl",
lhs contains "php", "php",
lhs contains " ftp ", "ftp",
""
)
| where DownloaderTool != ""
// Extract a URL token if present (no regex needed)
| extend tokens = split(cmd_l, " ")
| mv-apply token = tokens on (
where token startswith "http://" or token startswith "https://" or token startswith "ftp://"
| summarize ScriptUrl = any(token)
)
// Supportive indicators
| extend HasBase64Decode = iif(cmd_l contains "base64 -d" or cmd_l contains "base64 --decode" or cmd_l contains "openssl base64 -d", true, false)
| extend WgetStdout = iif(lhs contains "wget" and (lhs contains "-qO-" or lhs contains "-O-" or lhs contains "-O -" or lhs contains "-q -O -"), true, false)
| extend FromStdOut = case(
DownloaderTool == "wget", WgetStdout,
DownloaderTool == "curl", true,
DownloaderTool in ("nc","ncat","openssl","python","perl","php","aria2c","fetch","lwp-download","tftp","ftp"), true,
false
)
| extend PipeSnippet = strcat(lhs, " | ", rhs_first, iif(isnotempty(rhs_second), strcat(" ", rhs_second), ""))
| project TimeGenerated, DeviceId, DeviceName, AccountName, FileName, FolderPath, ProcessId, ProcessCommandLine,
PipeSnippet, ToolUsedToExecute, DownloaderTool, ScriptUrl, FromStdOut, HasBase64Decode,
InitiatingProcessFileName, InitiatingProcessCommandLine, ReportId
| order by TimeGenerated desc;
// Detailed results
SuspiciousPipeToShell | Correct | 3 | 333.78s | 0.2063 |
gpt-5-mini-high | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0198 |
gpt-5-mini-low | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0206 |
gpt-5-mini-medium | curl | let tools = "curl|wget|fetch|aria2c|ftp|tftp|busybox|python|perl|nc|socat|bash";
let shells = "sh|bash|ash|zsh|ksh|/bin/sh|/bin/bash";
let pipePattern = strcat("(?i)\\b(", tools, ")\\b[\\s\\S]{0,500}?\\|\\s*(", shells, ")\\b");
// Combine process and device events where a command line is available
(DeviceProcessEvents
| where isnotempty(ProcessCommandLine)
| extend CommandLine = tostring(ProcessCommandLine)
| project TimeGenerated, SourceTable = "DeviceProcessEvents", DeviceName, DeviceId, AccountName, InitiatingProcessAccountName, ProcessId, ProcessCreationTime, CommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
)
| union (
DeviceEvents
| where isnotempty(ProcessCommandLine)
| extend CommandLine = tostring(ProcessCommandLine)
| project TimeGenerated, SourceTable = "DeviceEvents", DeviceName, DeviceId, AccountName = coalesce(AccountName, InitiatingProcessAccountName), InitiatingProcessAccountName, ProcessId = InitiatingProcessId, ProcessCreationTime = InitiatingProcessCreationTime, CommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
)
| extend cmd_lc = tolower(CommandLine)
// Pre-filter to reduce noise: look for download/tool keywords or obvious pipe-to-shell hints
| where cmd_lc matches regex strcat("(?i).*(", tools, ").*") or cmd_lc contains "|sh" or cmd_lc contains "| bash" or cmd_lc contains "|/bin/sh" or cmd_lc contains "|/bin/bash"
// Detect explicit pipe-to-shell patterns and capture downloader and target shell
| extend pipe_match = extract(pipePattern, 0, cmd_lc)
| extend detected_tool_pipe = extract(pipePattern, 1, cmd_lc)
| extend pipe_shell = extract(pipePattern, 2, cmd_lc)
| extend is_pipe = strlen(pipe_match) > 0
// Detect subshell or backtick usage that contains a download tool (e.g. sh -c "$(curl ...)")
| extend contains_dollar_paren = cmd_lc contains "$("
| extend contains_backtick = cmd_lc contains "`"
| extend detected_tool_subshell = extract(strcat("(?i)\\b(", tools, ")\\b"), 1, cmd_lc)
| extend is_subshell = (contains_dollar_paren or contains_backtick) and strlen(detected_tool_subshell) > 0
// Consolidate detected tool
| extend detected_tool = iff(is_pipe, detected_tool_pipe, iff(is_subshell, detected_tool_subshell, ""))
// Keep only rows with evidence
| where is_pipe or is_subshell or detected_tool != ""
| project TimeGenerated, SourceTable, DeviceName, DeviceId, AccountName, InitiatingProcessAccountName, ProcessId, ProcessCreationTime, CommandLine, detected_tool, pipe_shell, is_pipe, is_subshell, InitiatingProcessFileName, InitiatingProcessCommandLine
// Summarize
| summarize FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), Count = count(), Examples = make_list(CommandLine, 5) by DeviceName, DeviceId, AccountName, detected_tool, pipe_shell, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by LastSeen desc
| take 200 | Incorrect | 4 | 93.14s | 0.0341 |
gpt-5-nano-high | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0106 |
gpt-5-nano-medium | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0089 |
grok-3-beta | curl | DeviceProcessEvents
| where ProcessCommandLine contains '|' and ProcessCommandLine matches regex @'(sh|bash|zsh|ksh|tcsh|dash)\s'
| where ProcessCommandLine contains 'curl' or ProcessCommandLine contains 'wget' or ProcessCommandLine contains 'http'
| join kind=inner (
DeviceInfo
| where OSPlatform == 'Linux'
) on DeviceId
| project DeviceName, FileName, ProcessCommandLine, ProcessCreationTime, InitiatingProcessFileName, InitiatingProcessCommandLine
| order by ProcessCreationTime desc | Incorrect | 2 | 24.25s | 0.0759 |
grok-3-mini-beta | bash | DeviceInfo
| where OSPlatform == 'Linux'
| join kind=inner (DeviceProcessEvents) on DeviceId
| where ProcessCommandLine contains '|' and (ProcessCommandLine contains 'curl' or ProcessCommandLine contains 'wget') and (ProcessCommandLine contains 'bash' or ProcessCommandLine contains 'sh')
| project TimeGenerated, DeviceId, DeviceName, ProcessCommandLine, InitiatingProcessFileName
| summarize arg_max(TimeGenerated, *) by DeviceId, ProcessCommandLine
| order by TimeGenerated desc | Correct | 2 | 27.78s | 0.0034 |
o1-high | curl | DeviceInfo
| where OSPlatform == "Linux"
| join kind=inner (
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where ProcessCommandLine has "|" // check for pipe in command line
| where ProcessCommandLine has_any ("curl", "wget") // check for download tools
| where ProcessCommandLine has_any ("bash", "sh", "zsh", "python", "perl") // check for shell execution
) on DeviceId
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessCommandLine, FolderPath, FileName, SHA256, OSPlatform
| order by TimeGenerated desc | Incorrect | 2 | 89.71s | 0.7373 |
o1-low | curl | let LinuxDevices = DeviceInfo
| where OSPlatform == "Linux"
| distinct DeviceId;
DeviceProcessEvents
| where DeviceId in (LinuxDevices)
| where tolower(ProcessCommandLine) has "|" // searching for pipe
| where tolower(ProcessCommandLine) has_any ("bash", "sh") // searching for piping to a shell
| where tolower(ProcessCommandLine) has_any ("curl", "wget", "python", "nc")
| extend ToolUsed = extract(@"(curl|wget|python|nc)", 1, tolower(ProcessCommandLine))
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, ToolUsed, InitiatingProcessCommandLine
| order by TimeGenerated desc
| Incorrect | 1 | 29.60s | 0.2759 |
o3-high | curl | //---------------------------------------------------------------------
// Linux – downloader | shell pipe-execution hunting query
//---------------------------------------------------------------------
// Time range is controlled by the portal; keep a safety filter as well
let lookBack = 14d; // change if you run the query standalone
// 1. Build the regular expressions (case-insensitive)
let downloader_regex = @"(curl|wget|python[0-9]*|perl|php|nc|ncat|openssl|busybox|ftp)";
let shell_regex = @"(bash|sh|zsh|ksh|dash)";
let pipe_to_shell_re = strcat(@"(?i)\b", downloader_regex, @"\b.*\|.*\b", shell_regex, @"\b");
// 2. Identify Linux devices
let LinuxDevices = DeviceInfo
| where OSPlatform =~ "Linux"
| project DeviceId;
// 3. Find suspicious processes that match the pipe-to-shell pattern
let SuspiciousProc = DeviceProcessEvents
| where TimeGenerated >= ago(lookBack)
| where DeviceId in (LinuxDevices)
| where ProcessCommandLine has "|" // quick pre-filter
| where ProcessCommandLine matches regex pipe_to_shell_re // precise pattern
| extend DownloaderTool = tolower(extract(downloader_regex, 1, ProcessCommandLine)),
TargetShell = tolower(extract(shell_regex, 1, ProcessCommandLine))
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessId, ProcessCommandLine,
DownloaderTool, TargetShell,
InitiatingProcessParentFileName, InitiatingProcessParentId, DeviceId;
// 4. Optional: bring in network traffic from the very same process
SuspiciousProc
| join kind=leftouter (
DeviceNetworkEvents
| where TimeGenerated >= ago(lookBack)
| project DeviceId, InitiatingProcessId, RemoteUrl, RemoteIP, RemotePort, Protocol, NetEventTime = TimeGenerated
) on $left.DeviceId == $right.DeviceId and $left.ProcessId == $right.InitiatingProcessId
| project TimeGenerated, NetEventTime,
DeviceName, AccountName, DownloaderTool, TargetShell,
ProcessCommandLine,
RemoteUrl, RemoteIP, RemotePort, Protocol,
FileName, ProcessId, InitiatingProcessParentFileName, InitiatingProcessParentId
| order by TimeGenerated desc | Incorrect | 2 | 81.31s | 0.0553 |
o3-mini-high | curl | DeviceProcessEvents
| extend cmd = iif(isnotempty(ProcessCommandLine), ProcessCommandLine, InitiatingProcessCommandLine)
| where isnotempty(cmd)
| where tolower(cmd) matches regex ".*(curl|wget).*\\|\\s*(sh|bash).*"
| extend downloadTool = tolower(extract("(?i)(curl|wget)", 1, cmd))
| project TimeGenerated, DeviceName, cmd, downloadTool
| sort by TimeGenerated desc | Incorrect | 3 | 47.94s | 0.0297 |
o3-mini-low | curl | DeviceProcessEvents
| where isnotempty(InitiatingProcessCommandLine)
| where InitiatingProcessCommandLine has "|" and (InitiatingProcessCommandLine has "curl" or InitiatingProcessCommandLine has "wget")
| extend DownloadTool = case(InitiatingProcessCommandLine contains "curl", "curl",
InitiatingProcessCommandLine contains "wget", "wget",
"unknown")
| project TimeGenerated, DeviceName, InitiatingProcessCommandLine, DownloadTool
| sort by TimeGenerated desc
| Incorrect | 1 | 23.41s | 0.0106 |
o4-mini-high | curl | // Timerange is applied externally by the UI
DeviceInfo
| where OSPlatform has "Linux"
| project DeviceId, OSPlatform
| join kind=inner (
DeviceProcessEvents
// look for a pipeline to a shell with a download tool
| where ProcessCommandLine has "|"
| where ProcessCommandLine matches regex @"(?i)\b(?:curl|wget|fetch|perl|python)\b.*\|\s*(?:bash|sh)\b"
) on DeviceId
| extend
Downloader = extract(@"(?i)\b(curl|wget|fetch|perl|python)\b", 1, ProcessCommandLine),
Shell = extract(@"(?i)\|\s*(bash|sh)\b", 1, ProcessCommandLine),
URL = extract(@"(?i)(?:curl|wget|fetch)\s+.*?(https?://\S+)", 1, ProcessCommandLine)
| project
TimeGenerated,
DeviceName,
OSPlatform,
AccountName = InitiatingProcessAccountName,
ProcessFileName = FileName,
ProcessCommandLine,
Downloader,
Shell,
URL
| sort by TimeGenerated desc | Incorrect | 4 | 133.12s | 0.0525 |
o4-mini-low | curl | let LinuxDevices = DeviceInfo
| where OSPlatform == "Linux"
| distinct DeviceId;
DeviceProcessEvents
| where DeviceId in (LinuxDevices)
// Note: the TimeGenerated filter is set via the external time range picker
| where ProcessCommandLine matches regex "(?i)\\b(?:curl|wget|fetch)\\b.*\\|\\s*(?:bash|sh|zsh)\\b"
| extend
DownloaderTool = tostring(extract("(?i)\\b(curl|wget|fetch)\\b", 1, ProcessCommandLine)),
ShellUsed = tostring(extract("\\|\\s*(bash|sh|zsh)\\b", 1, ProcessCommandLine))
| project
TimeGenerated,
DeviceName,
AccountName = InitiatingProcessAccountName,
DownloaderTool,
ShellUsed,
ProcessCommandLine,
InitiatingProcessFileName,
ProcessId
| order by TimeGenerated desc | Incorrect | 2 | 66.20s | 0.0235 |