Question Analysis
Windows process creation logs show a PowerShell-driven file transfer to an FTP service. Which executable was leveraged to perform this exfiltration?
b854eb97-bf9b-45ab-a1b5-b94e4880c56b
Question ID
16/23
Models Correct
1
Valid Answer
70%
Success Rate
Reference Answer
Human-validated correct answer for this question
rclone.exe
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 | rclone.exe | DeviceProcessEvents
| where InitiatingProcessFileName =~ "powershell.exe"
| where ProcessCommandLine has "ftp"
| distinct FileName | Correct | 1 | 7.19s | 0.0026 |
gpt-35-turbo | rclone.exe | DeviceProcessEvents
| where ProcessCommandLine contains 'powershell' and ProcessCommandLine contains 'ftp'
| project DeviceName, ProcessId, ProcessCommandLine | Correct | 1 | 2.31s | 0.0024 |
gpt-4-turbo-2024-04-09 | rclone.exe | DeviceProcessEvents
| where InitiatingProcessFileName == 'powershell.exe' and ProcessCommandLine has 'ftp'
| project DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLine, TimeGenerated | Correct | 1 | 9.39s | 0.0541 |
gpt-4.1 | rclone.exe | DeviceProcessEvents
| where InitiatingProcessFileName =~ "powershell.exe" or InitiatingProcessCommandLine has "powershell"
| where ProcessCommandLine has_any ("ftp", "put", "ftp:")
| where FileName !~ "powershell.exe"
| project TimeGenerated, DeviceName, AccountName, ParentProcess=InitiatingProcessFileName, ParentCommand=InitiatingProcessCommandLine, ExfilExecutable=FileName, ExfilCommand=ProcessCommandLine
| summarize ExfilCount=count() by ExfilExecutable, ExfilCommand
| sort by ExfilCount desc | Correct | 2 | 11.56s | 0.0223 |
gpt-4.1-finetuned | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0445 |
gpt-4.1-mini | rclone.exe | DeviceProcessEvents
| where InitiatingProcessFileName == "powershell.exe"
| where ProcessCommandLine has_any ("ftp", "-ftp", "ftp://", "ftp.")
| project TimeGenerated, DeviceName, AccountName, InitiatingProcessFileName, ProcessFileName = FileName, ProcessCommandLine
| distinct ProcessFileName, ProcessCommandLine | Correct | 1 | 6.22s | 0.0023 |
gpt-4.1-nano | rclone.exe | DeviceProcessEvents
| where ProcessCommandLine contains 'powershell' and ProcessCommandLine contains 'ftp'
| project InitiatingProcessFileName, ProcessCommandLine, InitiatingProcessCreationTime, DeviceName | Correct | 1 | 1.84s | 0.0005 |
gpt-4o | rclone.exe | let PowerShell_FTP_Events = DeviceProcessEvents
| where InitiatingProcessFileName =~ 'powershell.exe' and InitiatingProcessCommandLine contains 'ftp'
| project Timestamp, InitiatingProcessCommandLine, InitiatingProcessFileName, DeviceName, AccountName;
PowerShell_FTP_Events | Correct | 3 | 23.44s | 0.0350 |
gpt-5-high | rclone.exe | let ps_bins = dynamic(["powershell.exe","pwsh.exe","powershell_ise.exe"]);
let ftp_tools = dynamic(["ftp.exe","winscp.exe","winscp.com","psftp.exe","curl.exe","wget.exe","bitsadmin.exe","certutil.exe","tftp.exe","rclone.exe"]);
let ftp_markers = dynamic(["ftp://","ftps://","WebRequestMethods+Ftp","FtpWebRequest"," -Method Ftp"," -Method ftp","Invoke-WebRequest","Start-BitsTransfer"]);
DeviceProcessEvents
| where InitiatingProcessFileName in (ps_bins)
| where FileName in (ftp_tools)
or ProcessCommandLine has_any (ftp_markers)
or InitiatingProcessCommandLine has_any (ftp_markers)
| summarize FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), EventCount=count(), sample_child_cmd=any(ProcessCommandLine), sample_parent_cmd=any(InitiatingProcessCommandLine)
by Executable=tolower(FileName)
| order by EventCount desc, LastSeen desc | Correct | 2 | 177.34s | 0.0970 |
gpt-5-mini-high | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0257 |
gpt-5-mini-low | rclone.exe | // Detect PowerShell-driven FTP exfiltration and identify the executable used for exfiltration
let ftp_regex = "(?i)(ftp://|\\bftp\\b|ftps://|\\bSTOR\\b|\\bPORT\\b|Invoke-WebRequest|Invoke-RestMethod|WebClient|UploadFile\\(|System\\.Net\\.FtpWebRequest|ftp\\.exe|\\bcurl\\b|\\bwget\\b|\\bbitsadmin\\b|\\bcertutil\\b)";
// 1) PowerShell processes that reference FTP in their commandline
let ps_direct = DeviceProcessEvents
| where FileName has_cs "powershell" or ProcessCommandLine has_cs "powershell" or ProcessCommandLine has_cs "pwsh"
| where tostring(ProcessCommandLine) matches regex ftp_regex
| project TimeGenerated, DeviceName, AccountName, ExfiltratingExecutable = tolower(FileName), ProcessId, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessId;
// 2) Child processes spawned by PowerShell that look like FTP/upload tools
let child_procs = DeviceProcessEvents
| where isnotempty(InitiatingProcessFileName) and (tolower(InitiatingProcessFileName) has "powershell" or tolower(InitiatingProcessCommandLine) has "powershell" or tolower(InitiatingProcessCommandLine) has "pwsh")
| where tolower(FileName) has_any ("ftp","curl","wget","bitsadmin","certutil","ftp.exe") or tostring(ProcessCommandLine) matches regex ftp_regex
| project TimeGenerated, DeviceName, AccountName, ExfiltratingExecutable = tolower(FileName), ProcessId, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessId;
// 3) Network events likely indicating FTP (port 21 or ftp:// URLs)
let network_confirm = DeviceNetworkEvents
| where RemotePort == 21 or tostring(RemoteUrl) has "ftp://" or tostring(RemoteUrl) has ":21"
| project NetTime = TimeGenerated, NetDeviceName = DeviceName, NetInitiatingProcessId = InitiatingProcessId, NetInitiatingProcessFileName = InitiatingProcessFileName, RemoteIP = RemoteIP, RemotePort = RemotePort, RemoteUrl = RemoteUrl;
// Combine detections and validate with network events. Since join with OR is not allowed, perform two joins and union results.
(ps_direct
| union child_procs)
| as detections
| join kind=leftouter (network_confirm) on $left.ProcessId == $right.NetInitiatingProcessId
| project TimeGenerated, DeviceName, AccountName, ExfiltratingExecutable, ProcessId, ProcessCommandLine, InitiatingProcessFileName, NetInitiatingProcessFileName, RemoteIP, RemotePort, RemoteUrl, NetTime
| union (
(ps_direct
| union child_procs)
| join kind=leftouter (network_confirm) on $left.InitiatingProcessId == $right.NetInitiatingProcessId
| project TimeGenerated, DeviceName, AccountName, ExfiltratingExecutable, ProcessId, ProcessCommandLine, InitiatingProcessFileName, NetInitiatingProcessFileName, RemoteIP, RemotePort, RemoteUrl, NetTime
)
| summarize Attempts = count(), ExampleCommands = make_set(ProcessCommandLine, 5), Initiators = make_set(InitiatingProcessFileName, 5), RemoteEndpoints = make_set(coalesce(tostring(RemoteUrl), strcat(RemoteIP, ":", tostring(RemotePort))), 10) by ExfiltratingExecutable
| order by Attempts desc
| take 50 | Correct | 4 | 81.69s | 0.0198 |
gpt-5-mini-medium | rclone.exe | let ftp_ports = dynamic([21, 990, 2121, 8021]);
// Candidate PowerShell process creations invoking FTP-related commands
DeviceProcessEvents
| where FileName =~ 'powershell.exe' or FileName =~ 'pwsh.exe'
| where ProcessCommandLine has_any ('ftp','WebClient','FtpWebRequest','-Uri','-OutFile','Invoke-WebRequest','Start-BitsTransfer')
| project TimeGenerated, DeviceName, ProcessId, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
| join kind=leftouter (
// Network events from same process or initiated by same process
DeviceNetworkEvents
| where RemotePort in (21, 990, 2121, 8021) or RemoteUrl has 'ftp' or RemoteUrl has 'ftps'
| project NetworkTime=TimeGenerated, DeviceName, InitiatingProcessId, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteIP, RemotePort, RemoteUrl
) on DeviceName
| where isnotempty(ProcessId) and (ProcessId == InitiatingProcessId or InitiatingProcessFileName has 'powershell' or InitiatingProcessCommandLine has 'ftp')
| summarize NetworkEvents = make_set(pack('NetworkTime',NetworkTime,'RemoteIP',RemoteIP,'RemotePort',RemotePort,'RemoteUrl',RemoteUrl), 50), min(TimeGenerated), max(TimeGenerated) by DeviceName, ProcessId, FileName, ProcessCommandLine
| extend StartTime = todatetime(min_TimeGenerated), EndTime = todatetime(max_TimeGenerated)
| project StartTime, EndTime, DeviceName, ExfiltratingExecutable = FileName, ProcessId, ProcessCommandLine, NetworkEvents
| order by StartTime desc
| take 50 | Correct | 1 | 15.12s | 0.0046 |
gpt-5-nano-high | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0115 |
gpt-5-nano-medium | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0087 |
grok-3-beta | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0923 |
grok-3-mini-beta | rclone.exe | DeviceProcessEvents
| where InitiatingProcessFileName =~ 'powershell.exe'
| where ProcessCommandLine has "ftp" or ProcessCommandLine has "21"
| distinct FileName | Correct | 2 | 26.93s | 0.0029 |
o1-high | rclone.exe | DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where InitiatingProcessFileName =~ "powershell.exe"
| where ProcessCommandLine has_any ("ftp", "ftp://", "FtpWebRequest")
| project TimeGenerated, DeviceName, FileName, FolderPath, ProcessCommandLine
| order by TimeGenerated desc | Correct | 1 | 25.88s | 0.1952 |
o1-low | rclone.exe | DeviceProcessEvents
| where ActionType == "ProcessCreated"
| where InitiatingProcessFileName =~ "powershell.exe"
| where ProcessCommandLine has "ftp"
| project TimeGenerated, DeviceName, InitiatingProcessFileName, ProcessCommandLine, FileName, FolderPath
| order by TimeGenerated desc | Correct | 1 | 20.68s | 0.1803 |
o3-high | rclone.exe | // -----------------------------------------------------------------------------
// What executable did PowerShell use to transfer data to an FTP service?
// -----------------------------------------------------------------------------
// Query logic
// 1. Look for processes that were spawned by PowerShell and whose command line
// shows typical FTP keywords ( ftp / ftps / tftp ).
// 2. Look for network connections to an FTP service (TCP/21 or ftp:// URL)
// where the *connecting* process – or its parent – is PowerShell.
// 3. Union both evidence sets and summarise so we can clearly see which
// executable(s) were leveraged for the exfiltration, on which host and
// when it was first & last observed.
//
// NOTE – The time-picker in the hunting portal controls the global time range.
// If you want a fixed window instead, uncomment the first two lines
// and adjust the value in the *ago()* operator.
// -----------------------------------------------------------------------------
// let TimeWindow = 7d; // <- uncomment / change if needed
// | where TimeGenerated >= ago(TimeWindow)
// ---------------------------------------
// 1. Process-creation evidence
// ---------------------------------------
let procEvidence =
DeviceProcessEvents
// | where TimeGenerated >= ago(TimeWindow) // (handled by portal)
| where ActionType == "ProcessCreated"
| where InitiatingProcessFileName =~ "powershell.exe"
| where FileName != "powershell.exe" // exclude the parent itself
| where ProcessCommandLine has_any ("ftp ", "ftp://", "ftps://", "tftp ")
| project DeviceId,
DeviceName,
TimeGenerated,
ExfilExecutable = FileName,
ExfilCommand = ProcessCommandLine;
// ---------------------------------------
// 2. Network evidence (FTP traffic)
// ---------------------------------------
let netEvidence =
DeviceNetworkEvents
// | where TimeGenerated >= ago(TimeWindow)
| where RemotePort == 21 or RemoteUrl startswith "ftp://" or RemoteUrl startswith_cs "ftp."
| where InitiatingProcessParentFileName =~ "powershell.exe" // PowerShell launched it
or InitiatingProcessFileName =~ "powershell.exe" // or is PowerShell itself
| project DeviceId,
DeviceName,
TimeGenerated,
ExfilExecutable = InitiatingProcessFileName,
ExfilCommand = InitiatingProcessCommandLine;
// ---------------------------------------
// 3. Merge & answer
// ---------------------------------------
procEvidence
| union netEvidence
| summarize FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
ExecCount = count()
by DeviceName, ExfilExecutable, ExfilCommand
| sort by ExecCount desc, FirstSeen asc
| project Host = DeviceName,
Executable = ExfilExecutable,
ExampleCmdLine = ExfilCommand,
Executions = ExecCount,
FirstSeen,
LastSeen | Correct | 4 | 151.84s | 0.0962 |
o3-mini-high | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0515 |
o3-mini-low | rclone.exe | union withsource=TableName DeviceProcessEvents, DeviceEvents
| extend ParentProc = tolower(InitiatingProcessFileName), ChildProc = tolower(FileName)
| where ParentProc == "powershell.exe"
| where (tostring(ProcessCommandLine) contains "ftp" or tostring(InitiatingProcessCommandLine) contains "ftp")
| where ChildProc != "powershell.exe"
| project TimeGenerated, DeviceName, ProcessId, FileName, InitiatingProcessFileName, ProcessCommandLine, InitiatingProcessCommandLine
| sort by TimeGenerated asc | Correct | 5 | 149.76s | 0.0520 |
o4-mini-high | rclone.exe | DeviceProcessEvents
| where InitiatingProcessFileName in ("powershell.exe", "pwsh.exe")
| where ProcessCommandLine has "ftp"
| project TimeGenerated, DeviceName, InitiatingProcessCommandLine, ExfiltrationProcess = FileName, ProcessCommandLine
| summarize Count = count() by ExfiltrationProcess, ProcessCommandLine
| order by Count desc | Correct | 3 | 81.96s | 0.0248 |
o4-mini-low | No answer provided | No query generated | Incorrect | 5 | 0.00s | 0.0413 |