MetaCTF - PowerShell Obfuscation

A multi-layered PowerShell one-liner used string format tricks, base64 encoding, char arrays, and a rolling XOR cipher to hide a registry write command. Peeling back each layer statically revealed the full registry key.


Challenge

Platform: MetaCTF Category: DFIR / Malware Analysis

Even as the more advanced adversaries are shifting back towards more custom tooling and detections have improved, actors are still leveraging PowerShell in their attacks with lots of obfuscation to make analysis difficult. Take a look at the payload below.

Note: The name of the registry key accessed is the flag. We want the full registry key.

1$s=[string]([System.Text.Encoding]::ASCII."GetString"([System.Convert]::("f{2}m{1}e6{0}inG"-f"4sTR","BaS","rO")("JHQ9KDIwMSwxOTQsMjM3LDE2NCwyNTEsMjEsMTc4LDI0MCwzMzgsOTMsMTAwLDM2LDI5LDEzOCwyMCw5MSwyNDMsMjM2LDIwNywxNTcsMTMwLDM4LDE0MywyMjEsMzcxLDEwMiw3Nyw1OCwzNiwxODksNjEsMTIyLDIyOCwyNTEsMjE1LDEyOCwxNjIsNDQsMTQ2LDI0NSwzMzgsOTcsNjQsMjcsMzYsMTczLDMyLDc0LDIyNiwyMzYsMjEwLDE1NCwxNTcsMjUsMTI4LDIxOSwzNTIsMTAwLDY4LDI5LDM2LDE4NywxOCwxMTcsMTk5LDIyNCwyMTEsMTQwLDE4Miw0MCwxNDEsMTk3LDMzNywxMDIsNzcsMCwzNCwxNzYsNjEsMTIyLDI0NSwyMzIsMjA3LDE0MSwxNjAsNTksMTMzLDI0OSwzNzEsMTAyLDcxLDAsNDUsMTcyfCUgLXB7W2NoYXJdJF99KS1qb2luIiI7JHk9NDE7JGs9KCR0LigidGB7MH1gUmF7MX1gWSItZiJgT2NIYEEiLCJyYFJhIikoKXwlIC1we1tjaGFyXSgkXy1ieG9yKCR5PSR5KjMlMHgxMDArNikpfSktam9pbiIiOyR0PSgxNTQsMjA1LDE0MiwxNzcsMTksMjMwLDIwMSwyMTgsMTA5LDYsODgsMjQyLDIxMSw0N3wlIC1we1tjaGFyXSRffSktam9pbiIiOyR5PTI0MzskYz0oJHQuKCJ7MX1gSHsyfUFgezB9Ii1mIlJyQWBZIiwiVGBvQyIsImBBciIpKCl8JSAtcHtbY2hhcl0oJF8tYnhvcigkeT0keSozJTB4MTAwKzYpKX0pLWpvaW4iIjtTZXQtSXRlbVByb3BlcnR5IC1QYXRoICRrIC1OYW1lICRjIC1WYWx1ZSAx")));Invoke-Expression $s

Reconnaissance

The payload is a heavily obfuscated PowerShell one-liner. Before touching anything, the key rule with malware analysis: never execute unknown code. All of this can be deobfuscated statically.

Breaking down the outer structure, there are several layers at work:

  1. A string format trick to hide FromBase64String
  2. A base64-encoded payload
  3. Number arrays with [char] casting
  4. A rolling XOR cipher for the actual strings

Layer 1 — Reconstructing the Method Name

The converter method is obfuscated using PowerShell’s -f string format operator:

1"f{2}m{1}e6{0}inG" -f "4sTR","BaS","rO"

Filling in the placeholders: f + rO + m + BaS + e6 + 4sTR + inG = fromBase64String. PowerShell ignores backtick characters mid-string, so From`Base64String still resolves correctly — a common technique for breaking up recognizable strings that AV/EDR tools signature-match on.


Layer 2 — Decoding the Base64

1echo "JHQ9KDIwM..." | base64 -d

This reveals the inner PowerShell script, which contains:

  • Two number arrays ($t)
  • A rolling XOR key computation
  • A final Set-ItemProperty call

Layer 3 — Decoding the Number Arrays

The numbers are converted to characters with [char] casting. Values above 255 wrap around with modulo 256 — so [char]338 = [char](338 % 256) = [char]82 = R.


Layer 4 — The Rolling XOR Cipher

Each character is XOR’d against a key that updates every iteration:

y = (y * 3 % 0x100) + 6

With starting seeds of y=41 for $k (the registry path) and y=243 for $c (the key name). Implementing this in Python:

 1# Decode $k (registry path)
 2t_nums = [201,194,237,164,251,21,178,240,338,93,100,...]
 3t_str = "".join([chr(n % 256) for n in t_nums])
 4
 5y = 41
 6k = "".join([chr(ord(ch) ^ (y := (y * 3 % 0x100) + 6)) for ch in t_str])
 7
 8# Decode $c (registry key name)
 9t2_nums = [154,205,142,177,19,230,201,218,109,6,88,242,211,47]
10t2_str = "".join([chr(n % 256) for n in t2_nums])
11
12y = 243
13c = "".join([chr(ord(ch) ^ (y := (y * 3 % 0x100) + 6)) for ch in t2_str])

Result

The deobfuscated command:

1Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile' -Name 'EnableFirewall' -Value 1

Flag:

HKLM:\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\EnableFirewall

What This Malware Actually Does

Setting EnableFirewall to 0 under the StandardProfile key disables the Windows Firewall for public network profiles. This is a classic defense evasion step — after initial access, attackers disable host-based firewalls to make lateral movement and C2 communication easier. The registry path is a well-known target documented in multiple threat actor TTPs.


Obfuscation Techniques Used

Technique Purpose
-f string format with scrambled indexes Hides recognizable method names from static signatures
Base64 encoding Prevents casual inspection of the payload
Integer arrays + [char] casting Avoids plaintext strings in the script body
Rolling XOR cipher Makes the encoded strings non-trivially reversible
Backtick escaping Breaks up strings like To`Char`Array that EDR tools pattern-match

Takeaways

  • Layer-by-layer deobfuscation is the only reliable method. Tools like PowerShell’s own AST parser or CyberChef can handle base64 and charcode layers, but rolling XOR ciphers require a few lines of custom code.
  • The obfuscation complexity is proportional to the simplicity of the final payload — all of that work to hide one registry write.
  • In incident response, this kind of payload typically arrives as a second or third stage, dropped by a loader that handled the initial access. The firewall disable is preparation for follow-on activity.