Potential PowerShell Pass-the-Hash/Relay Script
Detects PowerShell scripts associated with NTLM relay or pass-the-hash tooling and SMB/NTLM negotiation artifacts. Attackers use relay and PtH techniques to authenticate without passwords and pivot to other systems.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2024/03/27"
3integration = ["windows"]
4maturity = "production"
5updated_date = "2026/04/27"
6
7[rule]
8author = ["Elastic"]
9description = """
10Detects PowerShell scripts associated with NTLM relay or pass-the-hash tooling and SMB/NTLM negotiation
11artifacts. Attackers use relay and PtH techniques to authenticate without passwords and pivot to other systems.
12"""
13from = "now-9m"
14index = ["logs-windows.powershell*", "winlogbeat-*"]
15language = "kuery"
16license = "Elastic License v2"
17name = "Potential PowerShell Pass-the-Hash/Relay Script"
18references = [
19 "https://github.com/Kevin-Robertson/Invoke-TheHash/blob/master/Invoke-WMIExec.ps1",
20 "https://github.com/Kevin-Robertson/Invoke-TheHash/blob/master/Invoke-SMBExec.ps1",
21 "https://github.com/dafthack/Check-LocalAdminHash/blob/master/Check-LocalAdminHash.ps1",
22 "https://github.com/nettitude/PoshC2/blob/master/resources/modules/Invoke-Tater.ps1",
23 "https://github.com/Kevin-Robertson/Inveigh/blob/master/Inveigh.ps1",
24]
25risk_score = 73
26rule_id = "951779c2-82ad-4a6c-82b8-296c1f691449"
27severity = "high"
28tags = [
29 "Domain: Endpoint",
30 "OS: Windows",
31 "Use Case: Threat Detection",
32 "Tactic: Credential Access",
33 "Resources: Investigation Guide",
34 "Data Source: PowerShell Logs",
35]
36timestamp_override = "event.ingested"
37type = "query"
38
39query = '''
40event.category:process and host.os.type:windows and
41 powershell.file.script_block_text : (
42 ("NTLMSSPNegotiate" and ("NegotiateSMB" or "NegotiateSMB2")) or
43 "4E544C4D53535000" or
44 "0x4e,0x54,0x4c,0x4d,0x53,0x53,0x50" or
45 "0x4e,0x54,0x20,0x4c,0x4d" or
46 "0x53,0x4d,0x42,0x20,0x32" or
47 "0x81,0xbb,0x7a,0x36,0x44,0x98,0xf1,0x35,0xad,0x32,0x98,0xf0,0x38"
48 ) and
49 not file.directory : "C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\Downloads"
50'''
51
52note = """## Triage and analysis
53
54### Investigating Potential PowerShell Pass-the-Hash/Relay Script
55
56#### Possible investigation steps
57
58- Does the visible script content implement relay-listener behavior, pass-the-hash execution, target validation, or more than one?
59 - Focus: `powershell.file.script_block_text` and any file-backed `file.path`.
60 - Implication: escalate when the fragment builds NTLMSSP/SMB messages, starts HTTP/SMB/proxy listeners, forwards authentication, references WMI/SMB/WinRM helpers, or pairs byte arrays with target selection; lower suspicion only for parser or lab text with no targeting, listener, credential, or execution logic.
61
62- Does full script reconstruction reveal target lists, credential material, service names, or listener settings the matching fragment did not show?
63 - Why: script block logging often splits relay mode, target configuration, and execution helpers into separate fragments.
64 - Focus: `powershell.file.script_block_id`, `powershell.sequence`, `powershell.total`, and reconstructed `powershell.file.script_block_text` on `host.id`; reassemble by `powershell.sequence` and treat missing fragments as unresolved. $investigate_0
65 - Implication: escalate on remote targets, password hashes, "TargetList", "SMBRelayTarget", "wpad.dat", "WPAD", listener ports, service names, execution helpers, or fan-out logic; lower suspicion only for research or validation code with no credential material, targets, listener, or execution path.
66
67- Which recovered PowerShell process explains launch context and downstream pivots?
68 - Focus: If endpoint process telemetry exists, recover the matching process via `host.id + process.pid` before interpreting `process.*` or `process.parent.*`; if absent, keep launch context unresolved. Record `process.command_line`, `process.parent.executable`, `process.Ext.session_info.logon_type`, `process.Ext.authentication_id`, and `process.entity_id`. $investigate_1
69 - Implication: escalate when the recovered launch shows encoded commands, remote-administration launchers, Office or browser parents, elevated context, or service/network logon sessions that do not fit the user; do not infer legitimacy from `process.pid` alone.
70
71- Do authentication events show local operator context or relay/PtH follow-on?
72 - Focus: same-`host.id`/`user.id` Windows Security events for `event.code` 4624, 4625, or 4648; review `source.ip`, `winlog.event_data.AuthenticationPackageName`, and `winlog.logon.type`. $investigate_2
73 - Hint: bridge recovered `process.Ext.authentication_id` to `winlog.event_data.TargetLogonId` only for the local session; prove relay/PtH with same-host inbound NTLM without `user.id`, target-host 4624/4625, or DC-side 4776 for reconstructed targets or sources.
74 - Implication: escalate when local, target-host, or DC authentication shows unexpected type 3 NTLM, repeated failures, privileged sessions, or explicit-credential use tied to reconstructed targets; missing authentication telemetry is unresolved, not benign.
75
76- Do network events show outbound relay or hash-validation activity to targets named in the script?
77 - Why: relay code often resolves targets, then reaches SMB, RPC, WinRM, or HTTP destinations; listener-only capture may not.
78 - Focus: If endpoint network telemetry exists, scope same-host events to `host.id`, `process.pid`, and the alert window, or use reconstructed targets when process identity is unavailable; separate DNS (`dns.question.name`, `dns.resolved_ip`) from connections (`destination.ip`, `destination.port`). $investigate_3
79 - Implication: escalate when the host fans out to named targets or reaches SMB, RPC, WinRM, or relay ports (80, 443, 445) outside the declared test scope; listener scripts stay suspicious with little outbound traffic when reconstruction shows "SMBRelayTarget", "wpad.dat", or similar relay-ready settings. Missing network telemetry is unresolved, not benign.
80
81- If local evidence remains suspicious or incomplete, do related alerts widen the user or host scope?
82 - Focus: related alerts for `user.id`; if quiet, compare `host.id` for adjacent relay, pass-the-hash, remote-service, persistence, or post-compromise alerts.
83 - $investigate_4
84 - $investigate_5
85 - Implication: broaden when local evidence stays suspicious or unresolved and related alerts show connected relay, listener-only capture, hash-validation fan-out, or lateral-movement behavior; keep local when surrounding alerts are absent or confined to the same declared test scope.
86
87- Weigh script intent, reconstruction, launch context, authentication follow-on, network contact, and related-alert scope: escalate when they align on unauthorized relay or pass-the-hash activity; close only when reconstructed content, launch, source, and available auth or network evidence support one controlled workflow with no contradictions; preserve and escalate if evidence is mixed or incomplete.
88
89### False positive analysis
90
91- Controlled testing, incident-response, or protocol-research workflows can trigger this rule when reconstructed `powershell.file.script_block_text` names only recognized targets or stays limited to parser/validation routines, recovered launch context matches the operator workflow, and authentication or network telemetry shows no live relay, listener, or execution outside scope. If engagement or change records exist, require alignment; otherwise, confirm recurring `user.id`, `host.id`, source pattern, recovered launch pattern, and target or port pattern across prior alerts from this rule. Do not close if hashes, listener ports, or follow-on authentication diverge.
92- Before creating an exception, validate recurring `user.id`, `host.id`, recovered launch pattern, source pattern, and target set across prior alerts. Build the exception from that minimum workflow. Avoid exceptions on byte sequences alone, `user.name` alone, or host alone.
93
94### Response and remediation
95
96- If confirmed benign, reverse any temporary containment and document the script content, recovered launch chain, source path pattern, target set, and session origin or logon-type pattern that proved the lab, response, or troubleshooting workflow. Create an exception only if the same workflow recurs across prior alerts from this rule.
97- If suspicious but unconfirmed, preserve the reconstructed `powershell.file.script_block_text`, `powershell.file.script_block_id`, fragment ordering metadata, recovered process and parent details, named targets, listener ports, service names, UNC paths, and related authentication or network evidence before destructive actions.
98- Apply reversible containment first, such as host isolation if tolerable or temporary controls on exposed accounts and named targets. Avoid terminating processes or deleting artifacts until possible credential misuse and lateral movement scope is clearer.
99- If confirmed malicious, isolate the endpoint when possible; otherwise escalate with the recorded `host.id`, recovered process identifiers, source IP values, named targets, and authentication evidence. Rotate or invalidate impacted credentials, review named systems for successful SMB/WMI/WinRM/service activity, restrict exposed NTLM pathways where supported, then remove only the scripts, services, scheduled tasks, persistence, or staging artifacts found during the investigation.
100- Retain PowerShell Script Block Logging plus supporting endpoint, authentication, and network telemetry. Document adjacent variants such as listener-only capture, hash-validation fan-out, or non-PowerShell relay/pass-the-hash alerts for detection follow-up.
101"""
102
103setup = """## Setup
104
105PowerShell Script Block Logging must be enabled to generate the events used by this rule (e.g., 4104).
106Setup instructions: https://ela.st/powershell-logging-setup
107"""
108
109[rule.investigation_fields]
110field_names = [
111 "@timestamp",
112 "user.name",
113 "user.id",
114 "user.domain",
115 "powershell.file.script_block_text",
116 "powershell.file.script_block_id",
117 "powershell.sequence",
118 "powershell.total",
119 "file.path",
120 "file.directory",
121 "file.name",
122 "process.pid",
123 "host.name",
124 "host.id",
125 "powershell.file.script_block_length"
126]
127
128[transform]
129
130[[transform.investigate]]
131label = "All PowerShell 4104 fragments for this script on this host"
132description = ""
133providers = [
134 [
135 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
136 { excluded = false, field = "powershell.file.script_block_id", queryType = "phrase", value = "{{powershell.file.script_block_id}}", valueType = "string" },
137 { excluded = false, field = "event.code", queryType = "phrase", value = "4104", valueType = "string" }
138 ]
139]
140relativeFrom = "now-1h"
141relativeTo = "now"
142
143[[transform.investigate]]
144label = "Process events for the PowerShell instance"
145description = ""
146providers = [
147 [
148 { excluded = false, field = "process.pid", queryType = "phrase", value = "{{process.pid}}", valueType = "string" },
149 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
150 { excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" }
151 ]
152]
153relativeFrom = "now-1h"
154relativeTo = "now"
155
156[[transform.investigate]]
157label = "Windows Security authentication events for the user"
158description = ""
159providers = [
160 [
161 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
162 { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" },
163 { excluded = false, field = "event.code", queryType = "phrase", value = "4624", valueType = "string" }
164 ],
165 [
166 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
167 { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" },
168 { excluded = false, field = "event.code", queryType = "phrase", value = "4625", valueType = "string" }
169 ],
170 [
171 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
172 { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" },
173 { excluded = false, field = "event.code", queryType = "phrase", value = "4648", valueType = "string" }
174 ]
175]
176relativeFrom = "now-24h"
177relativeTo = "now"
178
179[[transform.investigate]]
180label = "Network events for the PowerShell process"
181description = ""
182providers = [
183 [
184 { excluded = false, field = "process.pid", queryType = "phrase", value = "{{process.pid}}", valueType = "string" },
185 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
186 { excluded = false, field = "event.category", queryType = "phrase", value = "network", valueType = "string" }
187 ]
188]
189relativeFrom = "now-1h"
190relativeTo = "now"
191
192[[transform.investigate]]
193label = "Alerts associated with the user"
194description = ""
195providers = [
196 [
197 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
198 { excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
199 ]
200]
201relativeFrom = "now-48h/h"
202relativeTo = "now"
203
204[[transform.investigate]]
205label = "Alerts associated with the host"
206description = ""
207providers = [
208 [
209 { excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
210 { excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
211 ]
212]
213relativeFrom = "now-48h/h"
214relativeTo = "now"
215
216[[rule.threat]]
217framework = "MITRE ATT&CK"
218
219[[rule.threat.technique]]
220id = "T1557"
221name = "Adversary-in-the-Middle"
222reference = "https://attack.mitre.org/techniques/T1557/"
223
224[[rule.threat.technique.subtechnique]]
225id = "T1557.001"
226name = "LLMNR/NBT-NS Poisoning and SMB Relay"
227reference = "https://attack.mitre.org/techniques/T1557/001/"
228
229[rule.threat.tactic]
230id = "TA0006"
231name = "Credential Access"
232reference = "https://attack.mitre.org/tactics/TA0006/"
233
234[[rule.threat]]
235framework = "MITRE ATT&CK"
236
237[[rule.threat.technique]]
238id = "T1059"
239name = "Command and Scripting Interpreter"
240reference = "https://attack.mitre.org/techniques/T1059/"
241
242[[rule.threat.technique.subtechnique]]
243id = "T1059.001"
244name = "PowerShell"
245reference = "https://attack.mitre.org/techniques/T1059/001/"
246
247[rule.threat.tactic]
248id = "TA0002"
249name = "Execution"
250reference = "https://attack.mitre.org/tactics/TA0002/"
251
252[[rule.threat]]
253framework = "MITRE ATT&CK"
254
255[[rule.threat.technique]]
256id = "T1550"
257name = "Use Alternate Authentication Material"
258reference = "https://attack.mitre.org/techniques/T1550/"
259
260[[rule.threat.technique.subtechnique]]
261id = "T1550.002"
262name = "Pass the Hash"
263reference = "https://attack.mitre.org/techniques/T1550/002/"
264
265[rule.threat.tactic]
266id = "TA0008"
267name = "Lateral Movement"
268reference = "https://attack.mitre.org/tactics/TA0008/"
Triage and analysis
Investigating Potential PowerShell Pass-the-Hash/Relay Script
Possible investigation steps
-
Does the visible script content implement relay-listener behavior, pass-the-hash execution, target validation, or more than one?
- Focus:
powershell.file.script_block_textand any file-backedfile.path. - Implication: escalate when the fragment builds NTLMSSP/SMB messages, starts HTTP/SMB/proxy listeners, forwards authentication, references WMI/SMB/WinRM helpers, or pairs byte arrays with target selection; lower suspicion only for parser or lab text with no targeting, listener, credential, or execution logic.
- Focus:
-
Does full script reconstruction reveal target lists, credential material, service names, or listener settings the matching fragment did not show?
- Why: script block logging often splits relay mode, target configuration, and execution helpers into separate fragments.
- Focus:
powershell.file.script_block_id,powershell.sequence,powershell.total, and reconstructedpowershell.file.script_block_textonhost.id; reassemble bypowershell.sequenceand treat missing fragments as unresolved. $investigate_0 - Implication: escalate on remote targets, password hashes, "TargetList", "SMBRelayTarget", "wpad.dat", "WPAD", listener ports, service names, execution helpers, or fan-out logic; lower suspicion only for research or validation code with no credential material, targets, listener, or execution path.
-
Which recovered PowerShell process explains launch context and downstream pivots?
- Focus: If endpoint process telemetry exists, recover the matching process via
host.id + process.pidbefore interpretingprocess.*orprocess.parent.*; if absent, keep launch context unresolved. Recordprocess.command_line,process.parent.executable,process.Ext.session_info.logon_type,process.Ext.authentication_id, andprocess.entity_id. $investigate_1 - Implication: escalate when the recovered launch shows encoded commands, remote-administration launchers, Office or browser parents, elevated context, or service/network logon sessions that do not fit the user; do not infer legitimacy from
process.pidalone.
- Focus: If endpoint process telemetry exists, recover the matching process via
-
Do authentication events show local operator context or relay/PtH follow-on?
- Focus: same-
host.id/user.idWindows Security events forevent.code4624, 4625, or 4648; reviewsource.ip,winlog.event_data.AuthenticationPackageName, andwinlog.logon.type. $investigate_2 - Hint: bridge recovered
process.Ext.authentication_idtowinlog.event_data.TargetLogonIdonly for the local session; prove relay/PtH with same-host inbound NTLM withoutuser.id, target-host 4624/4625, or DC-side 4776 for reconstructed targets or sources. - Implication: escalate when local, target-host, or DC authentication shows unexpected type 3 NTLM, repeated failures, privileged sessions, or explicit-credential use tied to reconstructed targets; missing authentication telemetry is unresolved, not benign.
- Focus: same-
-
Do network events show outbound relay or hash-validation activity to targets named in the script?
- Why: relay code often resolves targets, then reaches SMB, RPC, WinRM, or HTTP destinations; listener-only capture may not.
- Focus: If endpoint network telemetry exists, scope same-host events to
host.id,process.pid, and the alert window, or use reconstructed targets when process identity is unavailable; separate DNS (dns.question.name,dns.resolved_ip) from connections (destination.ip,destination.port). $investigate_3 - Implication: escalate when the host fans out to named targets or reaches SMB, RPC, WinRM, or relay ports (80, 443, 445) outside the declared test scope; listener scripts stay suspicious with little outbound traffic when reconstruction shows "SMBRelayTarget", "wpad.dat", or similar relay-ready settings. Missing network telemetry is unresolved, not benign.
-
If local evidence remains suspicious or incomplete, do related alerts widen the user or host scope?
- Focus: related alerts for
user.id; if quiet, comparehost.idfor adjacent relay, pass-the-hash, remote-service, persistence, or post-compromise alerts.- $investigate_4
- $investigate_5
- Implication: broaden when local evidence stays suspicious or unresolved and related alerts show connected relay, listener-only capture, hash-validation fan-out, or lateral-movement behavior; keep local when surrounding alerts are absent or confined to the same declared test scope.
- Focus: related alerts for
-
Weigh script intent, reconstruction, launch context, authentication follow-on, network contact, and related-alert scope: escalate when they align on unauthorized relay or pass-the-hash activity; close only when reconstructed content, launch, source, and available auth or network evidence support one controlled workflow with no contradictions; preserve and escalate if evidence is mixed or incomplete.
False positive analysis
- Controlled testing, incident-response, or protocol-research workflows can trigger this rule when reconstructed
powershell.file.script_block_textnames only recognized targets or stays limited to parser/validation routines, recovered launch context matches the operator workflow, and authentication or network telemetry shows no live relay, listener, or execution outside scope. If engagement or change records exist, require alignment; otherwise, confirm recurringuser.id,host.id, source pattern, recovered launch pattern, and target or port pattern across prior alerts from this rule. Do not close if hashes, listener ports, or follow-on authentication diverge. - Before creating an exception, validate recurring
user.id,host.id, recovered launch pattern, source pattern, and target set across prior alerts. Build the exception from that minimum workflow. Avoid exceptions on byte sequences alone,user.namealone, or host alone.
Response and remediation
- If confirmed benign, reverse any temporary containment and document the script content, recovered launch chain, source path pattern, target set, and session origin or logon-type pattern that proved the lab, response, or troubleshooting workflow. Create an exception only if the same workflow recurs across prior alerts from this rule.
- If suspicious but unconfirmed, preserve the reconstructed
powershell.file.script_block_text,powershell.file.script_block_id, fragment ordering metadata, recovered process and parent details, named targets, listener ports, service names, UNC paths, and related authentication or network evidence before destructive actions. - Apply reversible containment first, such as host isolation if tolerable or temporary controls on exposed accounts and named targets. Avoid terminating processes or deleting artifacts until possible credential misuse and lateral movement scope is clearer.
- If confirmed malicious, isolate the endpoint when possible; otherwise escalate with the recorded
host.id, recovered process identifiers, source IP values, named targets, and authentication evidence. Rotate or invalidate impacted credentials, review named systems for successful SMB/WMI/WinRM/service activity, restrict exposed NTLM pathways where supported, then remove only the scripts, services, scheduled tasks, persistence, or staging artifacts found during the investigation. - Retain PowerShell Script Block Logging plus supporting endpoint, authentication, and network telemetry. Document adjacent variants such as listener-only capture, hash-validation fan-out, or non-PowerShell relay/pass-the-hash alerts for detection follow-up.
References
Related rules
- PowerShell Invoke-NinjaCopy script
- PowerShell Kerberos Ticket Dump
- PowerShell Kerberos Ticket Request
- PowerShell MiniDump Script
- Potential Invoke-Mimikatz PowerShell Script