// question

On a Windows device, review the process execution logs to find instances where a built-in listing tool was piped into a string filter. Identify the process name that the attacker was searching for.

Reference KQL answer and model-by-model comparison.

11ba69ee-902e-4a0f-b3b6-418aed7d7ddb
question id
8/23
models correct
1
valid answer
35%
success rate
// reference answer

Human-validated correct answer for this question.

lsass
// model comparison
ModelAnswerKQL queryStatusTriesTimeCost
gemini-2.5-flash-preview-04-17
lsass
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where ProcessCommandLine contains "|" and (ProcessCommandLine contains "findstr" or ProcessCommandLine contains "find.exe" or ProcessCommandLine contains "Select-String")
| project TimeGenerated, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine
pass114.76s0.0082
gpt-35-turbo
vssadmin.exe
DeviceProcessEvents
| where ProcessCommandLine contains ' | findstr '
| project ExtractedProcessName = tostring(split(ProcessCommandLine, ' | findstr ')[0])
fail13.10s0.0026
gpt-4-turbo-2024-04-09
cmd.exe
DeviceProcessEvents
| where ActionType == 'ProcessCreated' and (InitiatingProcessCommandLine has 'dir' and InitiatingProcessCommandLine has 'findstr')
| extend SearchedProcess = extract('findstr ["](.+?)["]', 1, InitiatingProcessCommandLine)
| project DeviceName, InitiatingProcessCommandLine, SearchedProcess
fail444.45s0.2099
gpt-4.1
no answer
no query generatedfail50.00s0.0457
gpt-4.1-finetuned
no answer
no query generatedfail50.00s0.0581
gpt-4.1-mini
no answer
no query generatedfail50.00s0.0101
gpt-4.1-nano
no answer
no query generatedfail50.00s0.0013
gpt-4o
no answer
no query generatedfail50.00s0.0635
gpt-5-high
lsass
let listing_and_filter = @'(?i)\b(tasklist|wmic\s+process|get-process|gps|get-ciminstance\s+win32_process|gwmi\s+win32_process)\b.*\|\s*(findstr|select-string|sls)\b';
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where ProcessCommandLine has "|"
| where ProcessCommandLine matches regex listing_and_filter
// Identify filter tool and listing tool
| extend _cmd = tostring(ProcessCommandLine)
| extend FilterTool = case(indexof(tolower(_cmd), "findstr") >= 0, "findstr",
                           indexof(tolower(_cmd), "select-string") >= 0 or indexof(tolower(_cmd), " sls ") >= 0, "Select-String",
                           "Unknown")
| extend ListingTool = case(indexof(tolower(_cmd), "tasklist") >= 0, "tasklist",
                            _cmd matches regex @'(?i)\bwmic\s+process\b', "wmic process",
                            _cmd matches regex @'(?i)\bget-process\b|\bgps\b', "Get-Process",
                            _cmd matches regex @'(?i)\b(get-ciminstance|gcim)\s+win32_process\b|\bgwmi\b.*win32_process\b', "WMI/CIM process query",
                            "Other")
// Extract the searched term after findstr / Select-String
| extend SearchedRaw = coalesce(
    extract(@'(?i)findstr(?:\s+/[a-z-]+\s*)*\s+/c:\s*"([^"]+)"', 1, _cmd),
    extract(@'(?i)findstr(?:\s+/[a-z-]+\s*)*\s*"([^"]+)"', 1, _cmd),
    extract(@'(?i)findstr(?:\s+/[a-z-]+\s*)*\s+([^\s\|]+)', 1, _cmd),
    extract(@'(?i)(?:select-string|sls)(?:\s+-[a-z-]+\s+\S+)*\s+-pattern\s*"([^"]+)"', 1, _cmd),
    extract(@'(?i)(?:select-string|sls)(?:\s+-[a-z-]+\s+\S+)*\s+-pattern\s+([^\s\|]+)', 1, _cmd),
    extract(@'(?i)(?:select-string|sls)(?:\s+-[a-z-]+\s+\S+)*\s+"([^"]+)"', 1, _cmd),
    extract(@'(?i)(?:select-string|sls)(?:\s+-[a-z-]+\s+\S+)*\s+([^\s\|]+)', 1, _cmd)
)
| extend SearchedProcess = tostring(SearchedRaw)
| where isnotempty(SearchedProcess)
// Normalize: last token, lowercase, trim quotes/space, drop .exe
| extend SearchedProcess = tolower(coalesce(extract(@'([^\\/:]+)$', 1, SearchedProcess), SearchedProcess))
| extend SearchedProcess = trim(' "', SearchedProcess)
| extend SearchedProcess = replace_regex(SearchedProcess, @'\.exe$', '')
| project TimeGenerated, DeviceName, AccountDomain, AccountName, FileName, ListingTool, FilterTool, SearchedProcess, ProcessCommandLine
| summarize EventCount = count(), Examples = make_set(ProcessCommandLine, 3) by DeviceName, AccountName, ListingTool, FilterTool, SearchedProcess
| order by EventCount desc, DeviceName asc
pass1148.97s0.0672
gpt-5-mini-high
no answer
no query generatedfail50.00s0.0285
gpt-5-mini-low
no answer
no query generatedfail50.00s0.0205
gpt-5-mini-medium
.docx
union DeviceProcessEvents, DeviceEvents
| where isnotempty(ProcessCommandLine)
| extend cmd = tostring(ProcessCommandLine)
// only commands that include a listing tool piped into a string filter
| where cmd matches regex "(?i)\\b(?:dir|get-childitem|ls|tree|attrib)\\b.*\\|.*\\b(?:find|findstr|select-string|select|where-object|where)\\b"
// extract for find/findstr (cmd.exe) - capture next token that is not a pipe or whitespace
| extend searched_find = extract("(?i)\\b(?:find|findstr)\\b(?:\\s+/\\w+)*\\s+['\"]?([^'\"\\|\\s]+)['\"]?", 1, cmd)
// extract for Select-String - look for -Pattern or first quoted arg
| extend searched_selectstring = extract("(?i)\\bselect-string\\b(?:[\\s\\S]*?)(?:-pattern\\s+)?['\"]?([^'\"\\|]+)['\"]?", 1, cmd)
// extract for Where-Object / Where - look for -match, -like, -eq
| extend searched_where = extract("(?i)\\bwhere(?:-object)?\\b[\\s\\S]*?(?:-match|-like|-eq)\\s+['\"]?([^'\"\\|]+)['\"]?", 1, cmd)
// extract for Select (PowerShell) - try to capture property or quoted expression
| extend searched_select = extract("(?i)\\bselect\\b[\\s\\S]*?(?:-expandproperty|-property)?\\s*['\"]?([^'\"\\|\\s]+)['\"]?", 1, cmd)
| extend SearchedForRaw = coalesce(searched_find, searched_selectstring, searched_where, searched_select)
| extend SearchedFor = tostring(trim(' "\'', SearchedForRaw))
| where isnotempty(SearchedFor)
| extend InitiatingProc = coalesce(InitiatingProcessFileName, FileName, InitiatingProcessCommandLine)
| summarize Occurrences = count(), Examples = make_set(cmd, 5), Devices = make_set(DeviceName, 5), InitiatingProcesses = make_set(InitiatingProc, 5), Accounts = make_set(AccountName, 5) by SearchedFor
| order by Occurrences desc
| project SearchedFor, Occurrences, Examples, Devices, InitiatingProcesses, Accounts
| take 100
fail589.81s0.0220
gpt-5-nano-high
no answer
no query generatedfail50.00s0.0116
gpt-5-nano-medium
no answer
no query generatedfail50.00s0.0109
grok-3-beta
no answer
no query generatedfail50.00s0.0951
grok-3-mini-beta
lsass
DeviceProcessEvents
| where ProcessCommandLine contains '| findstr'
| extend searchedFor = extract(@'findstr "(.*?)"', 1, ProcessCommandLine)
| project TimeGenerated, DeviceName, ProcessCommandLine, searchedFor
| order by TimeGenerated desc
pass115.30s0.0017
o1-high
lsass
DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where FileName in~ ("cmd.exe", "powershell.exe")
| where ProcessCommandLine has_any ("tasklist", "net", "wmic", "dir", "sc")
| where ProcessCommandLine has_any ("| find", "| findstr")
| extend AttackerSearch = extract(@'\|(?:\s*)find(?:str)?\s+(?:"([^"]+)"|(\S+))', 1, ProcessCommandLine)
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, ProcessCommandLine, AttackerSearch
| order by TimeGenerated desc
pass141.22s0.1809
o1-low
no answer
no query generatedfail50.00s0.8842
o3-high
lsass
// 1) Define typical listing and string-filtering tools
let listingTools  = dynamic(["tasklist","tasklist.exe","netstat","netstat.exe","wmic","wmic.exe","dir","get-process","gps","ps"]);
let stringFilters = dynamic(["findstr","find","select-string"]);
DeviceProcessEvents
// 2) Look for a pipe and the presence of both a listing tool and a string-filtering tool
| where ProcessCommandLine contains "|"
| where tolower(ProcessCommandLine) has_any(listingTools) and tolower(ProcessCommandLine) has_any(stringFilters)
// 3) Normalise and prepare for parsing
| extend CmdLower = tolower(ProcessCommandLine)
| extend AfterPipe = trim(' ', tostring(split(CmdLower, '|')[1]))
// 4) Extract the searched-for term depending on which filter command is used
| extend SearchTerm = case(
        AfterPipe startswith "findstr", extract("findstr(?:\\s+/[^\\s]+)*\\s+\"?'?([^\\s\"']+)", 1, AfterPipe),
        AfterPipe startswith "find",    extract("find(?:\\s+/[^\\s]+)*\\s+\"?'?([^\\s\"']+)",    1, AfterPipe),
        AfterPipe startswith "select-string", extract("select-string(?:\\s+[^\\s]+)*\\s+\"?'?([^\\s\"']+)", 1, AfterPipe),
        "")
| where isnotempty(SearchTerm)
// 5) Summarise and present the results
| summarize Executions = count(), Devices = dcount(DeviceId), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SearchTerm
| order by Executions desc
pass274.27s0.0395
o3-mini-high
lsass
DeviceProcessEvents
| where InitiatingProcessCommandLine has "tasklist" and InitiatingProcessCommandLine has "|"
| where InitiatingProcessCommandLine has_any ("find", "findstr")
| extend SearchedProcess = extract(@"(?i)\|\s*(?:findstr|find)\s+(?:/i\s+)?([^\s]+)", 1, InitiatingProcessCommandLine)
| project TimeGenerated, DeviceName, InitiatingProcessCommandLine, SearchedProcess
// Timerange will be set in function call.
pass112.84s0.0099
o3-mini-low
cmd.exe
DeviceProcessEvents
| where isnotempty(InitiatingProcessCommandLine)
| where InitiatingProcessCommandLine contains "dir" and (InitiatingProcessCommandLine contains "| find " or InitiatingProcessCommandLine contains "| findstr ")
| extend SearchedProcess = extract('(?i)\\|\\s*(?:findstr|find)\\s+"([^"]+)"', 1, InitiatingProcessCommandLine)
| project TimeGenerated, DeviceName, InitiatingProcessFileName, ProcessCommandLine = InitiatingProcessCommandLine, SearchedProcess
| order by TimeGenerated desc
fail5126.47s0.0583
o4-mini-high
lsass
DeviceProcessEvents
// Look for any command line containing a pipe
| where ProcessCommandLine contains "|"

// Ensure a built-in listing tool is used before the pipe
| where ProcessCommandLine matches regex "(?i)\\b(?:dir|ls|Get-ChildItem|tasklist|wmic)\\b\\s*\\|"

// Ensure a string filter is called after the pipe
| where ProcessCommandLine matches regex "(?i)\\|\\s*(?:findstr|grep)\\b"

// Extract the term passed to findstr or grep (first non-quoted token)
| extend SearchedTerm = extract("(?i)(?:findstr|grep)\\s+['\\\"]?([^'\\\"]+)", 1, ProcessCommandLine)
| where isnotempty(SearchedTerm)

// Summarize by the searched term, showing count and example devices/accounts
| summarize EventCount = count(), AffectedDevices = make_set(DeviceName, 10), AffectedUsers = make_set(InitiatingProcessAccountName, 10) by SearchedTerm
| project SearchedTerm, EventCount, AffectedDevices, AffectedUsers
| order by EventCount desc
pass276.77s0.0275
o4-mini-low
lsass
DeviceProcessEvents
| where ActionType == "ProcessCreated"
// Identify invocations of built-in listing tools piped into findstr
| where ProcessCommandLine has "|" and ProcessCommandLine has "findstr"
| where ProcessCommandLine has_any ("dir","tasklist")

// Extract the search term passed to findstr
| extend SearchTerm = extract(@"findstr\s+""?([^""\s]+)""?", 1, ProcessCommandLine)
| where isnotempty(SearchTerm)

// Select relevant details and count occurrences
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, SearchTerm, ProcessCommandLine
| summarize Occurrences = count() by SearchTerm
| sort by Occurrences desc
pass3110.85s0.0379