Question Analysis
On Windows devices, hunt for PowerShell activity where a remote script is fetched and executed to perform LLMNR/NBNS spoofing. Which cmdlet kicked off the listener?
deecd55f-afe0-4a62-9fba-4d1ba2deb321
Question ID
11/23
Models Correct
1
Valid Answer
48%
Success Rate
Reference Answer
Human-validated correct answer for this question
Invoke-Inveigh
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 | Invoke-Inveigh | DeviceProcessEvents
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has "LLMNR" or ProcessCommandLine has "NBNS" or ProcessCommandLine has "spoof" or ProcessCommandLine has "listener" or ProcessCommandLine has "Responder"
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessCommandLine | Correct | 1 | 17.93s | 0.0095 |
gpt-35-turbo | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0114 |
gpt-4-turbo-2024-04-09 | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.2498 |
gpt-4.1 | Inveigh | DeviceProcessEvents
| where FileName =~ "powershell.exe" or FileName =~ "pwsh.exe"
| where ProcessCommandLine has_any ("Invoke-WebRequest", "IEX", "Invoke-Expression", "wget", "curl")
| where ProcessCommandLine has_any ("responder", "inveigh", "NBNS", "LLMNR", "-NBNS", "-LLMNR")
| extend ListenerCmdlet = case(
ProcessCommandLine has "Inveigh", "Inveigh",
ProcessCommandLine has "Responder", "Responder",
ProcessCommandLine has "NBNS", "NBNS",
ProcessCommandLine has "LLMNR", "LLMNR",
"Unknown"
)
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, ListenerCmdlet | Correct | 1 | 7.04s | 0.0128 |
gpt-4.1-finetuned | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0718 |
gpt-4.1-mini | Invoke-Inveigh | DeviceProcessEvents
| where FileName =~ "powershell.exe" or FileName =~ "pwsh.exe"
// Looking for command lines that download and execute remote scripts, commonly using 'Invoke-WebRequest', 'IEX', or 'Invoke-Expression'
| where ProcessCommandLine has_any ("Invoke-WebRequest", "IEX", "Invoke-Expression", "DownloadString", "DownloadFile", "curl", "wget")
// Look further for indications related to LLMNR/NBNS spoofing in command line
| where ProcessCommandLine has_any ("LLMNR", "NBNS", "NetBIOS", "spoof", "spoofer", "Responder", "Impacket", "Invoke-DNSResponse", "nbtstat")
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine
| top 10 by TimeGenerated desc | Correct | 1 | 4.20s | 0.0024 |
gpt-4.1-nano | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0019 |
gpt-4o | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0563 |
gpt-5-high | Invoke-Inveigh | let psExecs = dynamic(["powershell.exe","pwsh.exe"]);
let fetchApis = dynamic([
"invoke-webrequest","invoke-restmethod","new-object net.webclient","downloadstring","downloadfile",
"[system.net.webclient]","start-bitstransfer","iwr","irm","wget","curl","iex","invoke-expression"
]);
let urlTokens = dynamic(["http://","https://"]);
// PowerShell processes
let psProcs = DeviceProcessEvents
| where FileName in~ (psExecs)
| project DeviceId, DeviceName, ProcessId, ProcessCreationTime, ProcessCommandLine, AccountDomain, AccountName;
// HTTP/S from those PowerShell processes (remote fetch evidence)
let psNet = DeviceNetworkEvents
| where InitiatingProcessFileName in~ (psExecs)
| where isnotempty(RemoteUrl) or RemotePort in (80,443,8080,8443)
| summarize NetFirst=min(TimeGenerated), NetLast=max(TimeGenerated),
RemoteUrls=make_set(RemoteUrl, 100), RemoteIPs=make_set(RemoteIP, 100)
by DeviceId, ProcId=tolong(InitiatingProcessId);
// PowerShell command/scriptblock content
let psContent = DeviceEvents
| where ActionType in~ ("PowerShellCommand","PowerShellScriptBlockLogging")
| extend PSContent = tostring(iff(ActionType == "PowerShellScriptBlockLogging", AdditionalFields.ScriptBlockText, AdditionalFields.Command))
| where isnotempty(PSContent)
| project DeviceId, PSTime=TimeGenerated, PSProcId=coalesce(tolong(ProcessId), tolong(InitiatingProcessId)), PSContent;
// Fetch indicators seen in PS content
let fetchEvidenceFromPSContent = psContent
| where tolower(PSContent) has_any (fetchApis) or PSContent has_any (urlTokens)
| summarize PSFetchFirst=min(PSTime), PSFetchLast=max(PSTime), PSFetchSamples=make_set(substring(PSContent,0,200), 20)
by DeviceId, PSProcId;
// Listener activity (Inveigh / LLMNR/NBNS spoofing) from PS content
let listenersFromPS = psContent
| where tolower(PSContent) has "inveigh" or (tolower(PSContent) has "llmnr" and tolower(PSContent) has "nbns")
| extend ListenerCmdlet = extract(@"(?i)\b((?:Invoke|Start)-(?:Inveigh(?:Relay)?))\b", 1, PSContent)
| extend ListenerCmdlet = iif(isempty(ListenerCmdlet) and PSContent matches regex @"(?i)\bInveigh\b", "Invoke-Inveigh", ListenerCmdlet)
| project DeviceId, PSProcId, PSTime, PSContent, ListenerCmdlet;
// Fallback: listener evidence directly from PS process command line (if PS content not available)
let listenersFromProcCL = DeviceProcessEvents
| where FileName in~ (psExecs)
| where ProcessCommandLine matches regex @"(?i)\b(?:Invoke|Start)-(?:Inveigh(?:Relay)?)\b"
or (tolower(ProcessCommandLine) has "inveigh" and (tolower(ProcessCommandLine) has "llmnr" or tolower(ProcessCommandLine) has "nbns"))
| extend ListenerCmdlet = extract(@"(?i)\b((?:Invoke|Start)-(?:Inveigh(?:Relay)?))\b", 1, ProcessCommandLine)
| project DeviceId, PSProcId=ProcessId, PSTime=ProcessCreationTime, PSContent=ProcessCommandLine, ListenerCmdlet;
let listeners = union listenersFromPS, listenersFromProcCL;
psProcs
| extend User = strcat(AccountDomain, "\\", AccountName),
HasFetchCL = (tolower(ProcessCommandLine) has_any (fetchApis) and ProcessCommandLine has_any (urlTokens))
| join kind=leftouter (psNet) on DeviceId, $left.ProcessId == $right.ProcId
| join kind=leftouter (fetchEvidenceFromPSContent) on DeviceId, $left.ProcessId == $right.PSProcId
| extend HasFetch = HasFetchCL or isnotempty(RemoteUrls) or isnotempty(PSFetchSamples)
| where HasFetch
| join kind=inner (listeners) on DeviceId, $left.ProcessId == $right.PSProcId
| where PSTime between (ProcessCreationTime .. ProcessCreationTime + 6h)
| project ListenerTime=PSTime, DeviceName, User,
ListenerCmdlet=iff(isempty(ListenerCmdlet), "Unknown (see PSContent)", ListenerCmdlet),
PSContentSnippet = substring(PSContent, 0, 400),
ProcessCreationTime, ProcessCommandLine,
FetchEvidence = case(HasFetchCL and isnotempty(RemoteUrls), "CmdLine+HTTP",
HasFetchCL, "CmdLine",
isnotempty(RemoteUrls), "HTTP",
isnotempty(PSFetchSamples), "PSContent",
"Unknown"),
RemoteUrls, RemoteIPs, PSFetchSamples
| order by ListenerTime desc | Correct | 3 | 399.42s | 0.1821 |
gpt-5-mini-high | Invoke-Inveigh | union DeviceProcessEvents, DeviceEvents, DeviceFileEvents
| extend Context = coalesce(ProcessCommandLine, InitiatingProcessCommandLine, tostring(AdditionalFields), FileOriginUrl, RemoteUrl, FileOriginReferrerUrl)
| where isnotempty(Context)
// focus on PowerShell (classic/pwsh)
| where tolower(Context) contains "powershell" or tolower(Context) contains "pwsh"
// look for remote fetch/execute patterns commonly used to fetch & run scripts
| where (
tolower(Context) contains "iwr" or
tolower(Context) contains "invoke-webrequest" or
tolower(Context) contains "invoke-restmethod" or
tolower(Context) contains "start-bitstransfer" or
tolower(Context) contains "new-object net.webclient" or
tolower(Context) contains "downloadstring" or
tolower(Context) contains "downloadfile" or
tolower(Context) contains "iex" or
tolower(Context) contains "invoke-expression" or
tolower(Context) contains "curl" or
tolower(Context) contains "wget" or
tolower(Context) contains "-encodedcommand" or
tolower(Context) contains "-enc"
)
// and LLMNR/NBNS/spoofing tool keywords
| where (
tolower(Context) contains "inveigh" or
tolower(Context) contains "llmnr" or
tolower(Context) contains "nbns" or
tolower(Context) contains "responder" or
tolower(Context) contains "nbtsspoof" or
tolower(Context) contains "spoofer" or
tolower(Context) contains "inveighrelay"
)
// try to extract the cmdlet that likely kicks off the listener (Invoke-*, Start-*, Inveigh/Responder)
| extend Cmdlet = extract(@"(?i)\b(Invoke-[A-Za-z0-9_]+|Start-[A-Za-z0-9_]+|Invoke-Inveigh|Invoke-InveighRelay|Inveigh|Responder|Start-Inveigh)\b", 1, Context)
// simple download URL grab (starts at "http" and reads up to 400 chars)
| extend httpIndex = indexof(Context, "http")
| extend DownloadUrl = iff(httpIndex >= 0, substring(Context, httpIndex, 400), "")
| project TimeGenerated, DeviceName, FileName, ProcessId, InitiatingProcessId, InitiatingProcessFileName, InitiatingProcessCommandLine, ProcessCommandLine, Cmdlet, DownloadUrl, FileOriginUrl, RemoteUrl, SourceSystem, Context
| where isnotempty(Cmdlet) or isnotempty(DownloadUrl)
| sort by TimeGenerated desc
| take 200 | Correct | 3 | 74.00s | 0.0196 |
gpt-5-mini-low | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0216 |
gpt-5-mini-medium | Invoke-Inveigh | // Hunt PowerShell fetching remote scripts that then perform LLMNR/NBNS spoofing and identify which cmdlet started the listener
let fetchMethods = dynamic(["Invoke-WebRequest","Invoke-RestMethod","iwr","wget","Start-BitsTransfer","IEX","Invoke-Expression","DownloadString","DownloadFile","WebClient","System.Net.WebClient","New-Object","curl"]);
let spoofIndicators = dynamic(["responder","inveigh","llmnr","nbns","nbt","mdns","multicastdns","spoof","llmnrsp","nbtname","nbnsr"]);
// PowerShell processes that may have fetched remote content or contain spoofing indicators
let PowerShellFetch = DeviceProcessEvents
| where FileName has_any ("powershell.exe","pwsh.exe")
| extend CmdLine = tostring(ProcessCommandLine)
| where CmdLine has_any (fetchMethods) or CmdLine has_any (spoofIndicators) or CmdLine matches regex "(?i)\biex\b" or CmdLine matches regex "(?i)\binvoke-expression\b"
| extend FetchMethodsFound = extract_all(@"(?i)\b(Invoke-WebRequest|Invoke-RestMethod|iwr|wget|Start-BitsTransfer|IEX|Invoke-Expression|DownloadString|DownloadFile|New-Object|System\.Net\.WebClient|curl)\b", CmdLine)
// Extract candidate listener-related cmdlets (Start-*, New-*, Invoke-*) and common listener names like Start-Responder, Start-InveighListener, Start-Listener
| extend ListenerCmdlets = extract_all(@"(?i)\b(Start|New|Invoke)-[A-Za-z0-9_-]+\b", CmdLine)
| extend ListenerCandidates = iff(array_length(ListenerCmdlets) > 0, strcat_array(ListenerCmdlets, ", "), "")
| project TimeGenerated, DeviceName, DeviceId, AccountName=InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, ProcessId, CmdLine, FetchMethodsFound, ListenerCandidates;
// Network activity on LLMNR(5355) and NBNS/NetBIOS(137) UDP ports
let NetLLMNR_NBNS = DeviceNetworkEvents
| where Protocol has "UDP"
| where LocalPort in (137, 5355)
| project NetTime = TimeGenerated, DeviceName, NetLocalPort = LocalPort, Protocol, NetInitiatingCmdLine = InitiatingProcessCommandLine, NetInitiatingFile = InitiatingProcessFileName;
// Correlate PowerShell fetches with LLMNR/NBNS network activity in a 5 minute window and summarize
PowerShellFetch
| join kind=leftouter NetLLMNR_NBNS on DeviceName
| where isnull(NetTime) or abs(datetime_diff('second', TimeGenerated, NetTime)) < 300
| summarize FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), Occurrences = count(), Devices = make_set(DeviceName), SamplePowerShellCmdLines = make_set(CmdLine, 10), SampleInitiatingProcessFiles = make_set(InitiatingProcessFileName, 10), SampleInitiatingCmds = make_set(InitiatingProcessCommandLine, 10), FetchMethods = make_set(FetchMethodsFound), ListenerCandidates = make_set(ListenerCandidates), NetworkPorts = make_set(NetLocalPort) by InitiatingProcessFileName, InitiatingProcessCommandLine
| order by FirstSeen desc
| project FirstSeen, LastSeen, Occurrences, InitiatingProcessFileName, InitiatingProcessCommandLine, Devices, ListenerCandidates, FetchMethods, SamplePowerShellCmdLines, SampleInitiatingProcessFiles, SampleInitiatingCmds, NetworkPorts | Correct | 3 | 66.31s | 0.0184 |
gpt-5-nano-high | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0089 |
gpt-5-nano-medium | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0122 |
grok-3-beta | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.1244 |
grok-3-mini-beta | Invoke-Inveigh | DeviceProcessEvents
| where FileName == 'powershell.exe'
| where ProcessCommandLine has_any ('Invoke-WebRequest', 'IWR', 'download', 'LLMNR', 'NBNS', 'spoofing')
| project DeviceName, AccountName, ProcessCommandLine, Timestamp
| summarize arg_max(Timestamp, *) by ProcessCommandLine
| project ProcessCommandLine | Correct | 1 | 14.75s | 0.0022 |
o1-high | Invoke-Inveigh | DeviceProcessEvents
| where (FileName == "powershell.exe" or FileName == "pwsh.exe")
// Look for commands that reference a remote HTTP source
| where ProcessCommandLine has_any ("http://", "https://")
// Identify the download or web request methods
| where ProcessCommandLine has_any ("Invoke-WebRequest", "Invoke-RestMethod", "iwr", "irm", "New-Object Net.WebClient", "wget")
// Look for signs of LLMNR/NBNS spoofing or references to Responder
| where ProcessCommandLine has_any ("LLMNR", "NBNS", "Responder", "spoofing")
// Extract which cmdlet actually started the listener
| extend SuspectedCmdlet = extract(@"(Invoke-WebRequest|Invoke-RestMethod|iwr|irm|New-Object\s+[Nn]et\.WebClient|wget|Start-Process|netsh)",1,ProcessCommandLine)
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, InitiatingProcessCommandLine, SuspectedCmdlet
| order by TimeGenerated desc | Correct | 1 | 45.83s | 0.3035 |
o1-low | IEX | DeviceProcessEvents
| where FileName in~ ("powershell.exe", "pwsh.exe", "powershell_ise.exe")
| where isnotempty(ProcessCommandLine)
// Identify references to remote script fetching and LLMNR/NBNS spoofing
| where ProcessCommandLine has_any ("IEX", "Invoke-WebRequest", "Invoke-Expression", "Net.WebClient", "DownloadString", "Inveigh", "Responder")
| where ProcessCommandLine has_any ("LLMNR", "NBNS")
// Extract the cmdlet that might have kicked off the listener
| extend ListenerCmdlet = extract(@"(?i)(Start-Inveigh|Invoke-Inveigh|Invoke-Expression|Invoke-WebRequest|IEX|Net\\.WebClient|DownloadString)", 1, ProcessCommandLine)
| project TimeGenerated, DeviceName, FileName, ProcessCommandLine, ListenerCmdlet
| order by TimeGenerated desc | Incorrect | 5 | 123.03s | 0.8322 |
o3-high | Invoke-Inveigh | // Hunt for PowerShell-delivered LLMNR / NBNS spoofing listeners
// Time range is taken from the query run-pane – nothing is hard-coded here
// 1. Look for a PowerShell process that downloads / fetches a remote script
// 2. Correlate that process (or its child) starting a listener such as Inveigh / Responder
// 3. Surface which cmdlet actually enabled the listener
let TimeWindow = 1h; // Listener must appear within 1-hour of the download (tune as required)
let RemoteScriptSigns = dynamic(
["invoke-webrequest", "invoke-restmethod", "downloadstring",
"new-object net.webclient", "start-bitstransfer", "curl", "wget"]);
let ListenerSigns = dynamic(
["invoke-inveigh", "start-inveigh", "inveigh", "responder", "-llmnr", "-nbns"]);
// ---- Phase-1 : PowerShell that fetches a remote script -------------------------------------
let RemoteFetch = DeviceProcessEvents
| where FileName in~ ("powershell.exe", "pwsh.exe", "powershell_ise.exe")
| extend CmdLower = tolower(ProcessCommandLine)
| where CmdLower has_any (RemoteScriptSigns)
| project
DeviceId,
DeviceName,
FetchTime = TimeGenerated,
FetchProcessId = ProcessId,
FetchSessionId = CreatedProcessSessionId,
FetchLogonId = LogonId,
FetchCmd = ProcessCommandLine,
FetchAccount = strcat(AccountDomain, "\\", AccountName);
// ---- Phase-2 : PowerShell that starts LLMNR/NBNS spoofing listener --------------------------
let ListenerStart = DeviceProcessEvents
| where FileName in~ ("powershell.exe", "pwsh.exe", "powershell_ise.exe")
| extend CmdLower = tolower(ProcessCommandLine)
| where CmdLower has_any (ListenerSigns)
| extend ListenerCmdlet = case(
CmdLower has "start-inveigh", "Start-Inveigh",
CmdLower has "invoke-inveigh", "Invoke-Inveigh",
CmdLower matches regex @"\\binveigh\\b", "Inveigh",
CmdLower contains "responder", "Responder",
"Unknown")
| project
DeviceId,
DeviceName,
ListenerTime = TimeGenerated,
ListenerProcessId = ProcessId,
ListenerInitiatingProcessId= InitiatingProcessId,
ListenerSessionId = CreatedProcessSessionId,
ListenerLogonId = LogonId,
ListenerCmd = ProcessCommandLine,
ListenerCmdlet,
ListenerAccount = strcat(AccountDomain, "\\", AccountName);
// ---- Correlate the two phases --------------------------------------------------------------
RemoteFetch
| join kind=inner (ListenerStart) on DeviceId
| where ListenerTime between (FetchTime .. FetchTime + TimeWindow)
and (
ListenerProcessId == FetchProcessId // same process
or ListenerInitiatingProcessId == FetchProcessId // child proc started by downloader
or ListenerSessionId == FetchSessionId // same PowerShell run-space
or ListenerLogonId == FetchLogonId // fall-back correlation
)
| project
DeviceName,
FetchTime,
ListenerTime,
TimeDelta = ListenerTime - FetchTime,
FetchCmd,
ListenerCmd,
ListenerCmdlet,
FetchAccount,
ListenerAccount,
DeviceId,
FetchProcessId,
ListenerProcessId,
ListenerInitiatingProcessId
| order by FetchTime desc | Correct | 3 | 123.23s | 0.0865 |
o3-mini-high | set-itemproperty | DeviceProcessEvents
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has "DownloadString" and ProcessCommandLine has "IEX"
| extend ListenerCmdlet = extract(@"(?i)(\w+-\w+)\s+.*", 1, ProcessCommandLine)
| project TimeGenerated, DeviceName, ProcessCommandLine, ListenerCmdlet
| sort by TimeGenerated desc | Incorrect | 1 | 26.79s | 0.0193 |
o3-mini-low | Invoke-Inveigh | DeviceProcessEvents
| where FileName =~ "powershell.exe"
// Look for remote execution (script fetched via http(s)) and signs of LLMNR/NBNS spoofing
| where ProcessCommandLine has_any ("http://", "https://")
and (ProcessCommandLine has "LLMNR" or ProcessCommandLine has "NBNS" or ProcessCommandLine has "spoof")
// Extract the first PowerShell cmdlet that appears in the command line (e.g. Invoke-Expression, Invoke-WebRequest, etc.)
| extend ListenerCmdlet = extract("(?i)(Invoke-[a-zA-Z]+)", 1, ProcessCommandLine)
| where isnotempty(ListenerCmdlet)
| summarize Count = count() by ListenerCmdlet, bin(TimeGenerated, 1h)
| sort by TimeGenerated desc | Correct | 1 | 26.09s | 0.0144 |
o4-mini-high | Invoke-Inveigh | DeviceProcessEvents
// Time range is applied externally by the hunting dashboard or query tool
| where FileName in ("powershell.exe", "pwsh.exe")
// Identify remote fetch and execution patterns
| where ProcessCommandLine has_any ("Invoke-WebRequest", "iwr", "DownloadString", "New-Object Net.WebClient", "Invoke-Expression", "iex")
// Narrow to LLMNR/NBNS spoofing indicators
| where ProcessCommandLine matches regex @"(?i)\b(?:llmnr|nbns|spoof)\b"
// Extract the spoofing-related cmdlet (e.g., Invoke-LlmnrSpoofing, Start-NbnsSpoofing)
| extend SpoofingCmdlet = extract(@"(?i)\b((?:Invoke|Start)-[A-Za-z0-9]+)\b", 1, ProcessCommandLine)
| where isnotempty(SpoofingCmdlet)
// Summarize which cmdlet kicked off the listener
| summarize Occurrences = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), ExampleCommand = any(ProcessCommandLine) by SpoofingCmdlet
| order by Occurrences desc | Correct | 5 | 181.57s | 0.0542 |
o4-mini-low | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0507 |