The Incident Responder's Dilemma
You're in the thick of an incident response. An alert fires: a scheduled task with an unusual parent process, and a command line that screams malicious intent. It looks something like this:
powershell.exe -nop -w hidden -enc JABjACAAPQAg...
This is a common pattern. The attacker uses PowerShell's -EncodedCommand (or -enc) flag to obfuscate their payload. The standard procedure is to grab that Base64 string, decode it, and examine the script. You paste it into your favorite decoder, expecting clear text, but instead, you get something nonsensical:
$ c = " h t t p : / / ...
The output is a mess. A space, or more accurately, a null byte, appears between every single character. Your first thought might be that the payload is corrupted, or perhaps the Base64 string itself is malformed. This is a common trap. The problem isn't with the Base64 encoding; it's with the decoding step.
Understanding PowerShell's Encoding
PowerShell's -EncodedCommand flag expects the input string to be encoded using UTF-16LE (16-bit little-endian Unicode) before it's Base64 encoded. When you decode the Base64 string, you're getting the raw UTF-16LE bytes. If your decoding tool or your manual approach assumes a different encoding, like ASCII or UTF-8, it will misinterpret these bytes. Each character in the original script, which is likely a single byte in ASCII or UTF-8, is represented by two bytes in UTF-16LE (a character byte followed by a null byte for little-endian).
Think of it like trying to read a book written in English, but you're only looking at every other page, assuming the skipped pages contain essential information. In this case, the 'skipped' pages are the null bytes that UTF-16LE inserts after each character when interpreted as a simpler encoding.
The command line we saw earlier, powershell.exe -nop -w hidden -enc JABjACAAPQAg..., contains a Base64 encoded string. When this string is Base64 decoded, it yields the raw bytes of the script. If that script was originally written in a standard encoding like ASCII or UTF-8 and then passed to PowerShell's -EncodedCommand, PowerShell itself would have converted it to UTF-16LE before Base64 encoding it. However, attackers often craft their payloads directly with UTF-16LE in mind, or their tools may default to it. The crucial point for an incident responder is that the *output* of decoding the Base64 string is *not* a plain text string in your local system's default encoding. It's raw UTF-16LE data.
The Correct Decoding Process
To correctly decode a PowerShell -EncodedCommand payload, you must perform two steps:
- Base64 Decode: Take the string provided after
-encand decode it from Base64. This will give you a byte array. - UTF-16LE Decode: Interpret that byte array as a UTF-16LE encoded string.
Many command-line tools and even some GUI decoders will automatically attempt to interpret the resulting bytes using a default encoding (often UTF-8 or ASCII). This is where the error occurs. You need to explicitly tell your decoding tool or script that the input is UTF-16LE.
For example, if you are using Python, the process would look like this:
import base64
encoded_string = "JABjACAAPQAg..." # Your Base64 blob here
# Decode Base64 to bytes
decoded_bytes = base64.b64decode(encoded_string)
# Decode bytes as UTF-16LE string
decoded_script = decoded_bytes.decode('utf-16le')
print(decoded_script)
On Linux or macOS, you can often use the iconv command or similar tools. If you're using a PowerShell console itself, you can decode it like this:
$encodedCommand = "JABjACAAPQAg..."
$bytes = [System.Convert]::FromBase64String($encodedCommand)
$decodedCommand = [System.Text.Encoding]::Unicode.GetString($bytes)
Write-Host $decodedCommand
The key is the explicit mention of 'utf-16le' or [System.Text.Encoding]::Unicode. Without this, you'll continue to see those null bytes interspersed, rendering the script unreadable and potentially leading you to miss critical malicious activity.
Why This Matters for Incident Response
Attackers rely on obscurity. By using obfuscation techniques like PowerShell's -EncodedCommand, they aim to bypass simple signature-based detection and make manual analysis difficult. A common tactic is to use tools or methods that produce output that looks like garbage when decoded incorrectly. This
