// question
A Windows host logs show PowerShell fetching and executing a remote script to gain SeDebugPrivilege token duplication. Which Empire module was invoked?
Reference KQL answer and model-by-model comparison.
34f0a430-9d04-4d98-bcb5-1989f14719f0
question id
6/23
models correct
1
valid answer
26%
success rate
// reference answer
Human-validated correct answer for this question.
Get-System
// model comparison
| Model | Answer | KQL query | Status | Tries | Time | Cost |
|---|---|---|---|---|---|---|
| gemini-2.5-flash-preview-04-17 | Get-System | DeviceProcessEvents
| where FileName in~ ('powershell.exe', 'pwsh.exe')
| where ActionType == 'ProcessCreated'
| where ProcessCommandLine has_any ('iex', 'Invoke-Expression') and ProcessCommandLine has_any ('DownloadString', 'Invoke-WebRequest', 'http://', 'https://')
| project Timestamp, DeviceName, AccountName, InitiatingProcessCommandLine, ProcessCommandLine, ReportId | pass | 1 | 20.51s | 0.0098 |
| gpt-35-turbo | no answer | no query generated | fail | 5 | 0.00s | 0.0115 |
| gpt-4-turbo-2024-04-09 | no answer | no query generated | fail | 5 | 0.00s | 0.2320 |
| gpt-4.1 | Get-System | DeviceProcessEvents
| where FileName =~ "powershell.exe"
| where ProcessCommandLine has_any ("SeDebugPrivilege", "token", "Invoke-TokenManipulation", "Invoke-Token")
| where ProcessCommandLine has_any ("http://", "https://") // Indicates remote script fetch
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, ProcessCommandLine, FileName, FolderPath
| top 20 by TimeGenerated desc | pass | 1 | 5.32s | 0.0118 |
| gpt-4.1-finetuned | no answer | no query generated | fail | 5 | 0.00s | 0.0420 |
| gpt-4.1-mini | no answer | no query generated | fail | 5 | 0.00s | 0.0079 |
| gpt-4.1-nano | no answer | no query generated | fail | 5 | 0.00s | 0.0017 |
| gpt-4o | no answer | no query generated | fail | 5 | 0.00s | 0.0556 |
| gpt-5-high | Get-System | // Detect the Empire module used to gain SeDebugPrivilege via token duplication
// Time range is set by the query invocation context
// 1) PowerShell process events (attempt to decode -EncodedCommand)
let ps_proc =
DeviceProcessEvents
| where FileName in~ ("powershell.exe", "pwsh.exe", "powershell_ise.exe")
| extend RawCmd = tostring(ProcessCommandLine)
// Extract possible -EncodedCommand payload (quoted or unquoted)
| extend Enc1 = extract(@'(?i)(?:^|\s)(?:-|/)(?:e|enc|encodedcommand)\s+"([^"]+)"', 1, RawCmd)
| extend Enc2 = extract(@"(?i)(?:^|\s)(?:-|/)(?:e|enc|encodedcommand)\s+'([^']+)'", 1, RawCmd)
| extend Enc3 = extract(@'(?i)(?:^|\s)(?:-|/)(?:e|enc|encodedcommand)\s+([A-Za-z0-9+/=]{8,})', 1, RawCmd)
| extend Enc = coalesce(Enc1, Enc2, Enc3)
| extend Decoded = iff(isnotempty(Enc), base64_decode_tostring(replace_string(Enc, " ", "")), "")
| extend FullText = trim(' ', strcat(RawCmd, ' ', Decoded))
| extend FullText_l = tolower(FullText)
// Remote fetch indicators (relaxed) + execution
| where FullText_l has_any ("downloadstring","invoke-webrequest","iwr","start-bitstransfer","bitsadmin","system.net.webclient","new-object net.webclient","curl","wget")
| where FullText_l has_any ("invoke-expression","iex","|iex"," | iex",".downloadstring(")
// Token duplication / SeDebugPrivilege / Empire module cues
| where FullText_l has_any ("invoke-tokenmanipulation","get-system","getsystem","sedebugprivilege","duplicatetoken","duplicate token","impersonat")
| extend EmpireModule = case(
FullText_l matches regex @"\binvoke[-_ ]?tokenmanipulation\b", "Invoke-TokenManipulation",
FullText_l matches regex @"\bget[-_ ]?system\b", "Get-System",
FullText_l has "sedebugprivilege" and FullText_l has_any ("duplicatetoken","duplicate token","impersonat"), "Invoke-TokenManipulation",
"Unknown"
)
| project TimeGenerated, DeviceId, DeviceName, AccountName, ProcessId, FullText, EmpireModule;
// 2) PowerShell command/script logging (ScriptBlock, etc.)
let ps_logs =
DeviceEvents
| where ActionType in~ ("PowerShellCommand","PowerShellScript","PowerShellScriptBlockLogging","PowerShellSuspiciousCommand")
| extend PsText = coalesce(
tostring(AdditionalFields.ScriptBlockText),
tostring(AdditionalFields.Command),
tostring(AdditionalFields.ScriptContent),
tostring(AdditionalFields.ScriptName),
tostring(AdditionalFields.Payload)
)
| where isnotempty(PsText)
| extend Text_l = tolower(PsText)
| where Text_l has_any ("downloadstring","invoke-webrequest","iwr","start-bitstransfer","bitsadmin","system.net.webclient","new-object net.webclient","curl","wget")
| where Text_l has_any ("invoke-expression","iex","|iex"," | iex",".downloadstring(")
| where Text_l has_any ("invoke-tokenmanipulation","get-system","getsystem","sedebugprivilege","duplicatetoken","duplicate token","impersonat")
| extend EmpireModule = case(
Text_l matches regex @"\binvoke[-_ ]?tokenmanipulation\b", "Invoke-TokenManipulation",
Text_l matches regex @"\bget[-_ ]?system\b", "Get-System",
Text_l has "sedebugprivilege" and Text_l has_any ("duplicatetoken","duplicate token","impersonat"), "Invoke-TokenManipulation",
"Unknown"
)
| project TimeGenerated, DeviceId, DeviceName, AccountName, ProcessId=tolong(AdditionalFields.ProcessId), FullText=PsText, EmpireModule;
// 3) Combine and answer: which Empire module(s) were invoked
union isfuzzy=true ps_proc, ps_logs
| where EmpireModule != "Unknown"
| summarize
FirstSeen=min(TimeGenerated),
LastSeen=max(TimeGenerated),
Devices=make_set(DeviceName, 10),
Samples=make_set(substring(FullText, 0, 220), 5)
by EmpireModule
| order by LastSeen desc | pass | 5 | 668.71s | 0.3114 |
| gpt-5-mini-high | Get-System | // Find PowerShell commands that fetch/execute remote scripts and reference SeDebug/token behavior, extract Invoke-* names (likely Empire module names)
let hits =
(
union isfuzzy=true
(
DeviceProcessEvents
| project TimeGenerated, DeviceName, ProcessId, CommandLine = ProcessCommandLine, InitiatingCommandLine = InitiatingProcessCommandLine, InitiatingFileName = InitiatingProcessFileName, RemoteUrl = ""
),
(
DeviceEvents
| project TimeGenerated, DeviceName, ProcessId = ProcessId, CommandLine = ProcessCommandLine, InitiatingCommandLine = InitiatingProcessCommandLine, InitiatingFileName = InitiatingProcessFileName, RemoteUrl = FileOriginUrl
)
)
| where tolower(CommandLine) has "powershell"
// indicators of remote fetch/execute
| where tolower(CommandLine) has_any ("iex", "invoke-expression", "invoke-webrequest", "invoke-restmethod", "downloadstring", "downloadfile", "-encodedcommand", "iwr ", "irm ")
// indicators of token/SeDebug usage or explicit Invoke-Module names
| where tolower(CommandLine) has_any ("sedebug", "sedebugprivilege", "se_debug", "token", "invoke-")
| extend Modules = extract_all(@"(?i)(Invoke-[A-Za-z0-9_]+)", CommandLine)
| mv-expand Modules
| extend Module = tostring(Modules)
;
// Summary of candidate modules (likely Empire module names)
hits
| summarize Count = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by Module
| order by Count desc
// Recent sample events for analyst review (top 50)
| union (
hits
| top 50 by TimeGenerated desc
| project TimeGenerated, DeviceName, ProcessId, Module, CommandLine, InitiatingCommandLine, InitiatingFileName, RemoteUrl
)
| pass | 1 | 35.67s | 0.0088 |
| gpt-5-mini-low | no answer | no query generated | fail | 5 | 0.00s | 0.0173 |
| gpt-5-mini-medium | no answer | no query generated | fail | 5 | 0.00s | 0.0322 |
| gpt-5-nano-high | Get-System | let psRemoteEvents =
DeviceProcessEvents
| where InitiatingProcessFileName in ("powershell.exe","pwsh.exe")
| where (InitiatingProcessCommandLine contains "IEX" or InitiatingProcessCommandLine contains "Invoke-Expression" or InitiatingProcessCommandLine contains "DownloadString" or InitiatingProcessCommandLine contains "Invoke-WebRequest" or InitiatingProcessCommandLine contains "New-Object System.Net.WebClient")
| join kind=inner (
DeviceNetworkEvents
| where isnotempty(RemoteUrl)
| extend NetTimeGenerated = TimeGenerated
| project InitiatingProcessId, RemoteUrlUsed = RemoteUrl, NetTimeGenerated
) on InitiatingProcessId
| extend RemoteUrlUsed = RemoteUrlUsed
| extend EmpireModuleCandidate = coalesce(tostring(extract(@"([^/?#]+)\\.ps1$", 1, RemoteUrlUsed)), tostring(extract(@"([^/?#]+)$", 1, RemoteUrlUsed)))
| where isnotempty(EmpireModuleCandidate)
| project TimeGenerated = NetTimeGenerated, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteUrlUsed, EmpireModuleCandidate;
psRemoteEvents | pass | 3 | 68.28s | 0.0056 |
| gpt-5-nano-medium | no answer | no query generated | fail | 5 | 0.00s | 0.0088 |
| grok-3-beta | no answer | no query generated | fail | 5 | 0.00s | 0.1036 |
| grok-3-mini-beta | no answer | no query generated | fail | 5 | 0.00s | 0.0078 |
| o1-high | no answer | no query generated | fail | 5 | 0.00s | 0.8012 |
| o1-low | Get-System | DeviceProcessEvents
| where FileName in~ ("powershell.exe", "powershell_ise.exe")
// Filter for PowerShell processes.
| where isnotempty(ProcessCommandLine)
// Ensure we have a command line to investigate.
| where ProcessCommandLine has_any ("IEX", "Invoke-Expression", "SeDebugPrivilege", "Invoke-TokenManipulation", "empire")
// Look for script loading, token manipulation, or Empire references.
| parse kind=regex ProcessCommandLine with * "powershell/" ModuleName " " *
// Attempt to parse out the Empire module name from the command.
| project TimeGenerated, DeviceName, AccountName, ProcessCommandLine, ModuleName
| order by TimeGenerated desc | pass | 1 | 38.59s | 0.2849 |
| o3-high | no answer | no query generated | fail | 5 | 0.00s | 0.0938 |
| o3-mini-high | no answer | no query generated | fail | 5 | 0.00s | 0.0395 |
| o3-mini-low | no answer | no query generated | fail | 5 | 0.00s | 0.0432 |
| o4-mini-high | WinPwn | DeviceProcessEvents | where FileName =~ "powershell.exe" | where ProcessCommandLine contains "DownloadString" and ProcessCommandLine contains "IEX" | extend EmpireModuleWithExt = extract(@"\/([^\/]+\.ps1)", 1, ProcessCommandLine) | extend EmpireModule = replace(@"\.ps1$", "", EmpireModuleWithExt) | project TimeGenerated, DeviceName, InitiatingProcessAccountName, ProcessCommandLine, EmpireModule | fail | 2 | 63.39s | 0.0218 |
| o4-mini-low | Invoke-Seatbelt | DeviceProcessEvents | where ProcessCommandLine matches regex "(?i)powershell.*DownloadString.*Invoke-[A-Za-z-]+" // Extract the Empire module name (Invoke-…) | extend EmpireModule = extract(@"(Invoke-[A-Za-z-]+)", 1, ProcessCommandLine) | project TimeGenerated, DeviceName, ProcessCommandLine, EmpireModule | summarize Count = count() by EmpireModule, DeviceName | order by Count desc | fail | 1 | 26.97s | 0.0067 |