Potential PowerShell Obfuscation via High Special Character Proportion

edit
A newer version is available. Check out the latest documentation.

Potential PowerShell Obfuscation via High Special Character Proportion

edit

Identifies PowerShell scripts with an abnormally high proportion of non-alphanumeric characters, often resulting from encoding, string mangling, or dynamic code generation.

Rule type: esql

Rule indices: None

Severity: low

Risk score: 21

Runs every: 5m

Searches indices from: now-9m (Date Math format, see also Additional look-back time)

Maximum alerts per execution: 100

References: None

Tags:

  • Domain: Endpoint
  • OS: Windows
  • Use Case: Threat Detection
  • Tactic: Defense Evasion
  • Data Source: PowerShell Logs
  • Rule Type: BBR

Version: 1

Rule authors:

  • Elastic

Rule license: Elastic License v2

Setup

edit

Setup

The PowerShell Script Block Logging logging policy must be enabled. Steps to implement the logging policy with Advanced Audit Configuration:

Computer Configuration >
Administrative Templates >
Windows PowerShell >
Turn on PowerShell Script Block Logging (Enable)

Steps to implement the logging policy via registry:

reg add "hklm\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1

Rule query

edit
FROM logs-windows.powershell_operational* metadata _id, _version, _index
| WHERE event.code == "4104"

// Look for scripts with more than 1000 chars that contain a related keyword
| EVAL script_len = LENGTH(powershell.file.script_block_text)
| WHERE script_len > 1000

// Replace string format expressions with 🔥 to enable counting the occurrence of the patterns we are looking for
// The emoji is used because it's unlikely to appear in scripts and has a consistent character length of 1
// Excludes spaces, #, = and - as they are heavily used in scripts for formatting
| EVAL replaced_with_fire = REPLACE(powershell.file.script_block_text, """[^0-9A-Za-z\s#=-]""", "🔥")

// Count the occurrence of special chars and their proportion to the total chars in the script
| EVAL special_count = script_len - LENGTH(REPLACE(replaced_with_fire, "🔥", ""))
| EVAL proportion = special_count::double / script_len::double

// Keep the fields relevant to the query, although this is not needed as the alert is populated using _id
| KEEP special_count, script_len, proportion, 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

// Filter for scripts with a 25%+ proportion of special chars
| WHERE proportion > 0.25

Framework: MITRE ATT&CKTM