← Back to Explore
elastichighTTP
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.
Detection Query
event.category:process and host.os.type:windows and
powershell.file.script_block_text : (
("NTLMSSPNegotiate" and ("NegotiateSMB" or "NegotiateSMB2")) or
"4E544C4D53535000" or
"0x4e,0x54,0x4c,0x4d,0x53,0x53,0x50" or
"0x4e,0x54,0x20,0x4c,0x4d" or
"0x53,0x4d,0x42,0x20,0x32" or
"0x81,0xbb,0x7a,0x36,0x44,0x98,0xf1,0x35,0xad,0x32,0x98,0xf0,0x38"
) and
not file.directory : "C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\Downloads"
Author
Elastic
Created
2024/03/27
Data Sources
PowerShell Logslogs-windows.powershell*winlogbeat-*
References
- https://github.com/Kevin-Robertson/Invoke-TheHash/blob/master/Invoke-WMIExec.ps1
- https://github.com/Kevin-Robertson/Invoke-TheHash/blob/master/Invoke-SMBExec.ps1
- https://github.com/dafthack/Check-LocalAdminHash/blob/master/Check-LocalAdminHash.ps1
- https://github.com/nettitude/PoshC2/blob/master/resources/modules/Invoke-Tater.ps1
- https://github.com/Kevin-Robertson/Inveigh/blob/master/Inveigh.ps1
Tags
Domain: EndpointOS: WindowsUse Case: Threat DetectionTactic: Credential AccessResources: Investigation GuideData Source: PowerShell Logs
Raw Content
[metadata]
creation_date = "2024/03/27"
integration = ["windows"]
maturity = "production"
updated_date = "2026/04/27"
[rule]
author = ["Elastic"]
description = """
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.
"""
from = "now-9m"
index = ["logs-windows.powershell*", "winlogbeat-*"]
language = "kuery"
license = "Elastic License v2"
name = "Potential PowerShell Pass-the-Hash/Relay Script"
references = [
"https://github.com/Kevin-Robertson/Invoke-TheHash/blob/master/Invoke-WMIExec.ps1",
"https://github.com/Kevin-Robertson/Invoke-TheHash/blob/master/Invoke-SMBExec.ps1",
"https://github.com/dafthack/Check-LocalAdminHash/blob/master/Check-LocalAdminHash.ps1",
"https://github.com/nettitude/PoshC2/blob/master/resources/modules/Invoke-Tater.ps1",
"https://github.com/Kevin-Robertson/Inveigh/blob/master/Inveigh.ps1",
]
risk_score = 73
rule_id = "951779c2-82ad-4a6c-82b8-296c1f691449"
severity = "high"
tags = [
"Domain: Endpoint",
"OS: Windows",
"Use Case: Threat Detection",
"Tactic: Credential Access",
"Resources: Investigation Guide",
"Data Source: PowerShell Logs",
]
timestamp_override = "event.ingested"
type = "query"
query = '''
event.category:process and host.os.type:windows and
powershell.file.script_block_text : (
("NTLMSSPNegotiate" and ("NegotiateSMB" or "NegotiateSMB2")) or
"4E544C4D53535000" or
"0x4e,0x54,0x4c,0x4d,0x53,0x53,0x50" or
"0x4e,0x54,0x20,0x4c,0x4d" or
"0x53,0x4d,0x42,0x20,0x32" or
"0x81,0xbb,0x7a,0x36,0x44,0x98,0xf1,0x35,0xad,0x32,0x98,0xf0,0x38"
) and
not file.directory : "C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\Downloads"
'''
note = """## 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_text` and any file-backed `file.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.
- 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 reconstructed `powershell.file.script_block_text` on `host.id`; reassemble by `powershell.sequence` and 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.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
- 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.
- Do authentication events show local operator context or relay/PtH follow-on?
- 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
- 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.
- 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.
- 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, compare `host.id` for 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.
- 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_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.
- 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.
### 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.
"""
setup = """## Setup
PowerShell Script Block Logging must be enabled to generate the events used by this rule (e.g., 4104).
Setup instructions: https://ela.st/powershell-logging-setup
"""
[rule.investigation_fields]
field_names = [
"@timestamp",
"user.name",
"user.id",
"user.domain",
"powershell.file.script_block_text",
"powershell.file.script_block_id",
"powershell.sequence",
"powershell.total",
"file.path",
"file.directory",
"file.name",
"process.pid",
"host.name",
"host.id",
"powershell.file.script_block_length"
]
[transform]
[[transform.investigate]]
label = "All PowerShell 4104 fragments for this script on this host"
description = ""
providers = [
[
{ excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
{ excluded = false, field = "powershell.file.script_block_id", queryType = "phrase", value = "{{powershell.file.script_block_id}}", valueType = "string" },
{ excluded = false, field = "event.code", queryType = "phrase", value = "4104", valueType = "string" }
]
]
relativeFrom = "now-1h"
relativeTo = "now"
[[transform.investigate]]
label = "Process events for the PowerShell instance"
description = ""
providers = [
[
{ excluded = false, field = "process.pid", queryType = "phrase", value = "{{process.pid}}", valueType = "string" },
{ excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
{ excluded = false, field = "event.category", queryType = "phrase", value = "process", valueType = "string" }
]
]
relativeFrom = "now-1h"
relativeTo = "now"
[[transform.investigate]]
label = "Windows Security authentication events for the user"
description = ""
providers = [
[
{ excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
{ excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" },
{ excluded = false, field = "event.code", queryType = "phrase", value = "4624", valueType = "string" }
],
[
{ excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
{ excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" },
{ excluded = false, field = "event.code", queryType = "phrase", value = "4625", valueType = "string" }
],
[
{ excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
{ excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" },
{ excluded = false, field = "event.code", queryType = "phrase", value = "4648", valueType = "string" }
]
]
relativeFrom = "now-24h"
relativeTo = "now"
[[transform.investigate]]
label = "Network events for the PowerShell process"
description = ""
providers = [
[
{ excluded = false, field = "process.pid", queryType = "phrase", value = "{{process.pid}}", valueType = "string" },
{ excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" },
{ excluded = false, field = "event.category", queryType = "phrase", value = "network", valueType = "string" }
]
]
relativeFrom = "now-1h"
relativeTo = "now"
[[transform.investigate]]
label = "Alerts associated with the user"
description = ""
providers = [
[
{ excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
{ excluded = false, field = "user.id", queryType = "phrase", value = "{{user.id}}", valueType = "string" }
]
]
relativeFrom = "now-48h/h"
relativeTo = "now"
[[transform.investigate]]
label = "Alerts associated with the host"
description = ""
providers = [
[
{ excluded = false, field = "event.kind", queryType = "phrase", value = "signal", valueType = "string" },
{ excluded = false, field = "host.id", queryType = "phrase", value = "{{host.id}}", valueType = "string" }
]
]
relativeFrom = "now-48h/h"
relativeTo = "now"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1557"
name = "Adversary-in-the-Middle"
reference = "https://attack.mitre.org/techniques/T1557/"
[[rule.threat.technique.subtechnique]]
id = "T1557.001"
name = "LLMNR/NBT-NS Poisoning and SMB Relay"
reference = "https://attack.mitre.org/techniques/T1557/001/"
[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1059"
name = "Command and Scripting Interpreter"
reference = "https://attack.mitre.org/techniques/T1059/"
[[rule.threat.technique.subtechnique]]
id = "T1059.001"
name = "PowerShell"
reference = "https://attack.mitre.org/techniques/T1059/001/"
[rule.threat.tactic]
id = "TA0002"
name = "Execution"
reference = "https://attack.mitre.org/tactics/TA0002/"
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1550"
name = "Use Alternate Authentication Material"
reference = "https://attack.mitre.org/techniques/T1550/"
[[rule.threat.technique.subtechnique]]
id = "T1550.002"
name = "Pass the Hash"
reference = "https://attack.mitre.org/techniques/T1550/002/"
[rule.threat.tactic]
id = "TA0008"
name = "Lateral Movement"
reference = "https://attack.mitre.org/tactics/TA0008/"