Potential PowerShell Obfuscation via Invalid Escape Sequences
Detects PowerShell scripts with repeated invalid backtick escapes between word characters (letters, digits, underscore, or dash), splitting tokens while preserving execution. Attackers use this obfuscation to fragment keywords and evade pattern-based detection and AMSI.
Rule type: esql
Rule indices:
Rule Severity: medium
Risk Score: 47
Runs every:
Searches indices from: now-9m
Maximum alerts per execution: 100
References:
Tags:
- Domain: Endpoint
- OS: Windows
- Use Case: Threat Detection
- Tactic: Defense Evasion
- Data Source: PowerShell Logs
- Resources: Investigation Guide
Version: 9
Rule authors:
- Elastic
Rule license: Elastic License v2
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
Disclaimer: This guide was created by humans with the assistance of generative AI. While its contents have been manually curated to include the most valuable information, always validate assumptions and adjust procedures to match your internal runbooks and incident triage and response policies.
This rule flags PowerShell script block content that repeatedly inserts invalid backtick escape sequences within otherwise contiguous word characters. This can fragment tokens (cmdlets, parameters, variable names, strings) while preserving execution and readability to the interpreter, which can hinder content inspection and pattern-based detections.
Analyst goals:
- Reconstruct complete script block content when split across multiple events.
- Normalize the content (remove or correct invalid escapes) to reveal the underlying logic.
- Determine execution context (host, user, script origin) and correlate with adjacent activity to assess intent and impact.
user.name,user.domain,user.id: Account execution context for correlation, prioritization, and scoping.host.name,host.id: Host execution context for correlation, prioritization, and scoping.file.path,file.directory,file.name: File-origin context when the script block is sourced from an on-disk file.powershell.file.script_block_text: Script block content that matched the detection logic.powershell.file.script_block_id,powershell.sequence,powershell.total: Script block metadata to pivot to other fragments or reconstruct full script content when split across multiple events.Esql.script_block_tmp: Transformed script block where detection patterns replace original content with a marker to support scoring/counting and quickly spot match locations.Esql.script_block_pattern_count: Count of matches for the detection pattern(s) observed in the script block content.powershell.file.script_block_entropy_bits: Shannon entropy of the script block. Higher values may indicate obfuscation.powershell.file.script_block_surprisal_stdev: Standard deviation of surprisal across the script block. Low values indicate uniform randomness. High values indicate mixed patterns and variability.powershell.file.script_block_unique_symbols: Count of distinct characters present in the script block.powershell.file.script_block_length: Script block length (size) context.
Establish timeline and ownership:
- Anchor the activity using
@timestamp, then recordhost.name,host.id, andagent.id. - Identify the execution context with
user.name,user.domain, anduser.id. Note whether the account is expected to run PowerShell on this host and whether the host is commonly used for scripting.
- Anchor the activity using
Assess the likelihood of intentional obfuscation:
- Review
Esql.script_block_pattern_countto understand how heavily the content is fragmented. Higher counts generally increase confidence that this is deliberate obfuscation rather than incidental escaping. - Use
powershell.file.script_block_lengthas size context and reviewpowershell.file.script_block_entropy_bits,powershell.file.script_block_unique_symbols, andpowershell.file.script_block_surprisal_stdevto characterize the content (simple text vs. mixed/randomized payloads). - Compare
Esql.script_block_tmptopowershell.file.script_block_textto understand where obfuscation is concentrated (localized string vs. widespread token fragmentation).
- Review
Reconstruct complete content when split across events:
- If
powershell.totalis greater than 1, pivot onpowershell.file.script_block_idand rebuild the script by ordering segments onpowershell.sequence. - Validate the reconstructed set is complete (sequence 1 through
powershell.total). Missing segments should be treated as an investigative gap and may require additional scoping.
- If
Determine script origin and delivery:
- If
file.path,file.directory, andfile.nameare present, treat the script block as file-associated. Evaluate whether the location and naming are consistent with approved scripts or expected tooling for the endpoint. - If file fields are absent, treat the script as inline or dynamically generated content and prioritize correlation by
host.id,user.id, and time.
- If
Normalize and interpret the script content safely:
- In a controlled analysis workflow, normalize the script by removing or correcting invalid backtick insertions so that split tokens become readable. Keep both the original and normalized versions for reporting.
- Review the normalized text for behaviors that indicate malicious intent (secondary payload retrieval, dynamic execution, decoding/decompression, data collection, persistence logic, or remote interaction).
- Extract and document indicators present in the content (network destinations, file paths/names, unique strings, or embedded encoded blobs) for scoping.
Correlate within PowerShell telemetry:
- Pivot on
host.idanduser.idto identify additionalpowershell.file.script_block_textevents shortly before and after the alert time to capture staging, follow-on commands, and potential cleanup. - Check for the same
powershell.file.script_block_idappearing across hosts, or for repeated normalized strings, to identify automation reuse or broader activity.
- Pivot on
Correlate with adjacent endpoint activity (if available in your environment):
- Review process execution around
@timestamponhost.nameto identify the PowerShell host process and its parent, then assess whether the launch chain aligns with expected activity for the user and endpoint. - Review network activity around the alert time for connections that align with indicators extracted from the script content.
- Review file and registry activity around the same time window for artifacts consistent with the script (new or modified scripts, dropped files, or persistence-related changes).
- Review authentication activity associated with
user.idaround the alert time for suspicious logons or remote access that may align with script execution.
- Review process execution around
Scope impact:
- Search for other alerts/events with similar obfuscation characteristics on the same host and for the same user to determine whether this is a one-off execution or a repeated pattern.
- If multiple hosts are involved, prioritize investigation for critical assets and accounts with elevated privileges.
- Legitimate scripts can contain backticks for formatting, string construction, or content generation; however, repeated invalid escape sequences embedded inside alphanumeric tokens are uncommon. Validate whether the execution context (
host.id,user.id) aligns with known administrative or developer activity. - Some commercial or internal tools intentionally obfuscate PowerShell to protect intellectual property. Confirm whether the script origin (
file.pathwhen present), account context, and prevalence across the environment match an approved application or workflow. - Copy/paste artifacts and encoding transformations can introduce unexpected characters. When suspected, compare the normalized content to known-good scripts and assess whether the obfuscation is systematic (repeating across many tokens) versus localized.
If the activity is confirmed or strongly suspected malicious:
- Contain affected host(s) to prevent further execution and lateral movement.
- Preserve evidence: reconstructed
powershell.file.script_block_text,powershell.file.script_block_id,powershell.sequence,powershell.total, and alert-derived fields (Esql.script_block_tmp,Esql.script_block_pattern_count, and the script block metrics). - If
file.pathis present, collect and quarantine the referenced script and review the surrounding directory for related artifacts. - Use indicators extracted from normalized content to scope related activity across endpoints (pivot on
host.id,user.id,file.path, and unique strings from the script). - Coordinate credential remediation for affected accounts when remote execution, credential material, or post-exploitation behavior is suspected.
If the activity is benign but requires reduction:
- Document the legitimate source (expected hosts/users and
file.pathwhen applicable). - Apply narrowly scoped tuning using stable attributes available in the alert (such as
host.id,user.id, andfile.path) and continue monitoring for deviations in script content and execution context.
- Document the legitimate source (expected hosts/users and
from logs-windows.powershell_operational* metadata _id, _version, _index
| where event.code == "4104" and powershell.file.script_block_text like "*`*"
// replace the patterns we are looking for with the 🔥 emoji to enable counting them
// The emoji is used because it's unlikely to appear in scripts and has a consistent character length of 1
| eval Esql.script_block_tmp = replace(powershell.file.script_block_text, """[A-Za-z0-9_-]`(?![rntb]|\r|\n|\d)[A-Za-z0-9_-]""", "🔥")
// count how many patterns were detected by calculating the number of 🔥 characters inserted
| eval Esql.script_block_pattern_count = length(Esql.script_block_tmp) - length(replace(Esql.script_block_tmp, "🔥", ""))
// keep the fields relevant to the query, although this is not needed as the alert is populated using _id
| keep
Esql.script_block_pattern_count,
Esql.script_block_tmp,
powershell.file.*,
file.name,
file.directory,
file.path,
powershell.sequence,
powershell.total,
_id,
_version,
_index,
host.name,
host.id,
agent.id,
user.id
// Filter for scripts that match the pattern at least 20 times
| where Esql.script_block_pattern_count >= 20
| where file.name not like "TSS_*.psm1"
// ESQL requires this condition, otherwise it only returns matches where file.name exists.
or file.name is null
// VSCode Shell integration
| where not powershell.file.script_block_text like "*$([char]0x1b)]633*"
| where not file.directory == "C:\\Program Files\\MVPSI\\JAMS\\Agent\\Temp"
// ESQL requires this condition, otherwise it only returns matches where file.directory exists.
or file.directory is null
Framework: MITRE ATT&CK
Tactic:
- Name: Defense Evasion
- Id: TA0005
- Reference URL: https://attack.mitre.org/tactics/TA0005/
Technique:
- Name: Obfuscated Files or Information
- Id: T1027
- Reference URL: https://attack.mitre.org/techniques/T1027/
Technique:
- Name: Deobfuscate/Decode Files or Information
- Id: T1140
- Reference URL: https://attack.mitre.org/techniques/T1140/
Framework: MITRE ATT&CK
Tactic:
- Name: Execution
- Id: TA0002
- Reference URL: https://attack.mitre.org/tactics/TA0002/
Technique:
- Name: Command and Scripting Interpreter
- Id: T1059
- Reference URL: https://attack.mitre.org/techniques/T1059/
Sub Technique:
- Name: PowerShell
- Id: T1059.001
- Reference URL: https://attack.mitre.org/techniques/T1059/001/