Potential PowerShell Obfuscation via String Reordering
Identifies PowerShell scripts that use string reordering and runtime reconstruction techniques as a form of obfuscation. These methods are designed to evade static analysis and bypass security protections such as the Antimalware Scan Interface (AMSI).
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2025/04/03"
3integration = ["windows"]
4maturity = "production"
5updated_date = "2025/06/10"
6
7[rule]
8author = ["Elastic"]
9description = """
10Identifies PowerShell scripts that use string reordering and runtime reconstruction techniques as a form of obfuscation.
11These methods are designed to evade static analysis and bypass security protections such as the Antimalware Scan
12Interface (AMSI).
13"""
14from = "now-9m"
15language = "esql"
16license = "Elastic License v2"
17name = "Potential PowerShell Obfuscation via String Reordering"
18risk_score = 21
19rule_id = "e903ce9a-5ce6-4246-bb14-75ed3ec2edf5"
20setup = """## Setup
21
22The 'PowerShell Script Block Logging' logging policy must be enabled.
23Steps to implement the logging policy with Advanced Audit Configuration:
Computer Configuration > Administrative Templates > Windows PowerShell > Turn on PowerShell Script Block Logging (Enable)
1
2Steps to implement the logging policy via registry:
reg add "hklm\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1
1"""
2severity = "low"
3tags = [
4 "Domain: Endpoint",
5 "OS: Windows",
6 "Use Case: Threat Detection",
7 "Tactic: Defense Evasion",
8 "Data Source: PowerShell Logs",
9]
10timestamp_override = "event.ingested"
11type = "esql"
12
13query = '''
14FROM logs-windows.powershell_operational* metadata _id, _version, _index
15| WHERE event.code == "4104"
16
17// Look for scripts with more than 500 chars that contain a related keyword
18| EVAL script_len = LENGTH(powershell.file.script_block_text)
19| WHERE script_len > 500
20| WHERE powershell.file.script_block_text LIKE "*{0}*"
21
22// Replace string format expressions with 🔥 to enable counting the occurrence of the patterns we are looking for
23// The emoji is used because it's unlikely to appear in scripts and has a consistent character length of 1
24| EVAL replaced_with_fire = REPLACE(powershell.file.script_block_text, """((\{\d+\}){2,}["']\s?-f|::Format[^\{]+(\{\d+\}){2,})""", "🔥")
25
26// Count how many patterns were detected by calculating the number of 🔥 characters inserted
27| EVAL count = LENGTH(replaced_with_fire) - LENGTH(REPLACE(replaced_with_fire, "🔥", ""))
28
29// Keep the fields relevant to the query, although this is not needed as the alert is populated using _id
30| KEEP count, replaced_with_fire, powershell.file.script_block_text, powershell.file.script_block_id, file.path, powershell.sequence, powershell.total, _id, _index, host.name, agent.id, user.id
31| WHERE count > 3
32
33// Exclude Noisy Patterns
34
35// Icinga Framework
36| WHERE (file.name NOT LIKE "framework_cache.psm1" or file.name IS NULL)
37| WHERE NOT
38 // https://wtfbins.wtf/17
39 (
40 (powershell.file.script_block_text LIKE "*sentinelbreakpoints*" OR
41 powershell.file.script_block_text LIKE "*:::::\\\\windows\\\\sentinel*")
42 AND
43 (powershell.file.script_block_text LIKE "*$local:Bypassed*" OR
44 powershell.file.script_block_text LIKE "*origPSExecutionPolicyPreference*")
45 )
46'''
47
48
49[[rule.threat]]
50framework = "MITRE ATT&CK"
51[[rule.threat.technique]]
52id = "T1027"
53name = "Obfuscated Files or Information"
54reference = "https://attack.mitre.org/techniques/T1027/"
55
56[[rule.threat.technique]]
57id = "T1140"
58name = "Deobfuscate/Decode Files or Information"
59reference = "https://attack.mitre.org/techniques/T1140/"
60
61
62[rule.threat.tactic]
63id = "TA0005"
64name = "Defense Evasion"
65reference = "https://attack.mitre.org/tactics/TA0005/"
66[[rule.threat]]
67framework = "MITRE ATT&CK"
68[[rule.threat.technique]]
69id = "T1059"
70name = "Command and Scripting Interpreter"
71reference = "https://attack.mitre.org/techniques/T1059/"
72[[rule.threat.technique.subtechnique]]
73id = "T1059.001"
74name = "PowerShell"
75reference = "https://attack.mitre.org/techniques/T1059/001/"
76
77
78
79[rule.threat.tactic]
80id = "TA0002"
81name = "Execution"
82reference = "https://attack.mitre.org/tactics/TA0002/"
Related rules
- Potential PowerShell Obfuscation via High Numeric Character Proportion
- Potential PowerShell Obfuscation via Invalid Escape Sequences
- Potential PowerShell Obfuscation via Special Character Overuse
- Potential PowerShell Obfuscation via String Concatenation
- Potential Dynamic IEX Reconstruction via Environment Variables