Detection rules › Sigma
Powershell Token Obfuscation - Powershell
Detects TOKEN OBFUSCATION technique from Invoke-Obfuscation in Powershell scripts. Use this rule as a threat-hunting baseline to find obfuscated scripts in your environment. Once tested and tuned, consider deploying a production detection rule based on this hunting rule.
Known false positives
- Edge case might be possible with heavy use of string formatting or obfuscation in legitimate scripts.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Stealth |
Telemetry coverage
| Provider | Record / event type |
|---|---|
| PowerShell | Event ID 4104: Creating Scriptblock text (MessageNumber of MessageTotal). |
Rule body
title: Powershell Token Obfuscation - Powershell
id: f3a98ce4-6164-4dd4-867c-4d83de7eca51
related:
- id: deb9b646-a508-44ee-b7c9-d8965921c6b6
type: similar
status: test
description: |
Detects TOKEN OBFUSCATION technique from Invoke-Obfuscation in Powershell scripts.
Use this rule as a threat-hunting baseline to find obfuscated scripts in your environment.
Once tested and tuned, consider deploying a production detection rule based on this hunting rule.
references:
- https://github.com/danielbohannon/Invoke-Obfuscation
author: frack113
date: 2022-12-27
modified: 2025-10-19
tags:
- attack.stealth
- attack.t1027.009
- detection.threat-hunting
logsource:
product: windows
category: ps_script
definition: 'Requirements: Script Block Logging must be enabled'
detection:
selection:
# Examples:
# IN`V`o`Ke-eXp`ResSIOn (Ne`W-ob`ject Net.WebClient).DownloadString
# &('In'+'voke-Expressi'+'o'+'n') (.('New-Ob'+'jec'+'t') Net.WebClient).DownloadString
# &("{2}{3}{0}{4}{1}"-f 'e','Expression','I','nvok','-') (&("{0}{1}{2}"-f'N','ew-O','bject') Net.WebClient).DownloadString
- ScriptBlockText|re: '\w+`(\w+|-|.)`[\w+|\s]'
# - ScriptBlockText|re: '\((\'(\w|-|\.)+\'\+)+\'(\w|-|\.)+\'\)' TODO: fixme
- ScriptBlockText|re: '"(\{\d\}){2,}"\s*-f' # trigger on at least two placeholders. One might be used for legitimate string formatting
# ${e`Nv:pATh}
- ScriptBlockText|re: '(?i)\$\{`?e`?n`?v`?:`?p`?a`?t`?h`?\}'
filter_envpath:
ScriptBlockText|contains: '${env:path}' # TODO: Fix this. See https://github.com/SigmaHQ/sigma/pull/4964
filter_chocolatey:
ScriptBlockText|contains:
- 'it will return true or false instead' # Chocolatey install script https://github.com/chocolatey/chocolatey
- 'The function also prevents `Get-ItemProperty` from failing' # https://docs.chocolatey.org/en-us/create/functions/get-uninstallregistrykey
filter_exchange:
Path|startswith: 'C:\Program Files\Microsoft\Exchange Server\'
Path|endswith: '\bin\servicecontrol.ps1'
ScriptBlockText|contains: '`r`n'
condition: selection and not 1 of filter_*
falsepositives:
- Edge case might be possible with heavy use of string formatting or obfuscation in legitimate scripts.
level: medium
Stages and Predicates
Stage 0: condition
selection and not 1 of filter_*Stage 1: selection
selection:
- ScriptBlockText|re: '\w+`(\w+|-|.)`[\w+|\s]'
- ScriptBlockText|re: '"(\{\d\}){2,}"\s*-f'
- ScriptBlockText|re: '(?i)\$\{`?e`?n`?v`?:`?p`?a`?t`?h`?\}'
Stage 2: not filter_*
filter_envpath:
ScriptBlockText|contains: '${env:path}'
filter_chocolatey:
ScriptBlockText|contains:
- 'it will return true or false instead'
- 'The function also prevents `Get-ItemProperty` from failing'
filter_exchange:
Path|startswith: 'C:\Program Files\Microsoft\Exchange Server\'
Path|endswith: '\bin\servicecontrol.ps1'
ScriptBlockText|contains: '`r`n'
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
Path | ends_with | \bin\servicecontrol.ps1 | excludes:Path field:"Path" value:"\bin\servicecontrol.ps1" |
Path | starts_with | C:\Program Files\Microsoft\Exchange Server\ | excludes:Path field:"Path" value:"C:\Program Files\Microsoft\Exchange Server\" |
ScriptBlockText | match | `r`n | excludes:ScriptBlockText field:"ScriptBlockText" value:"`r`n" |
ScriptBlockText | match | ${env:path} | excludes:ScriptBlockText field:"ScriptBlockText" value:"${env:path}" |
ScriptBlockText | match | The function also prevents `Get-ItemProperty` from failing | excludes:ScriptBlockText field:"ScriptBlockText" value:"The function also prevents `Get-ItemProperty` from failing" |
ScriptBlockText | match | it will return true or false instead | excludes:ScriptBlockText field:"ScriptBlockText" value:"it will return true or false instead" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ScriptBlockText | regex_match |
| field:"ScriptBlockText" kind:regex_match |