The Invoke-Obfuscation Usage Guide :: Part 1

It has been just over a year since I released Invoke-Obfuscation and it has led to an exciting year of sharing this obfuscation, evasion and detection research with anybody who will listen. It has been fascinating to see how Red Teamers, commodity malware authors and advanced threat actors like APT32 have used this framework in their various campaigns. Most satisfying, though, is detecting this obfuscation in the wild and talking with other defenders who have used Invoke-Obfuscation to build out and refine their own detection techniques for catching obfuscated PowerShell.

From time to time I myself am tasked to assist a Red Team engagement by crafting custom, obfuscated PowerShell payloads using Invoke-Obfuscation. When this happens I often get questions about why I chose certain obfuscation options or was so particular about applying a certain ordering of options to the payload. I also realized that there are several lesser-known components of Invoke-Obfuscation that I have not drawn attention to in any one place...until now.

This series of posts is intended to inform users about several lesser-known features in Invoke-Obfuscation as well as the HOW and WHY behind my thinking about obfuscating commands and scripts with Invoke-Obfuscation. And it all begins with a brief timeline of updates to the framework (which are listed in the project's README file under "Release Notes") and why I added them.

PART A :: Timeline of Invoke-Obfuscation's Evolution

I released Invoke-Obfuscation on 2016-09-25 at DerbyCon 6 (video). At the time it included concatenation obfuscation for TOKEN obfuscation, five ENCODING options and six LAUNCHER options. Two weeks later I added -f format operator reordering obfuscation for all applicable TOKEN options (check out this post for the reasoning behind this addition), and over the next month I added one ENCODING option and two more LAUNCHER options.

On 2017-01-24 I released version v1.6 by adding command option chaining, enabling full regular expression usage in command options, adding an UNDO command (easily my favorite addition to the framework!), and providing full framework interaction via CLI (mainly from chronic begging of several Red Teamers, but joke's on them because this feature made defenders' test harness payload generation 100 times simpler). Since then I added four more LAUNCHERS and two more ENCODING options, in addition to numerous bug fixes -- mostly thanks to Ryan Cobb (@cobbr_io) who is now an official maintainer of the project.

PART B :: Lesser-Known Features of Invoke-Obfuscation

Numerous times I have had people tweet or DM me thanking me for adding a "new feature" to Invoke-Obfuscation. In reality many were present from version 1.0, but a few have been added since the framework's inception.

Here is a list of Invoke-Obfuscation functions that hopefully others will find interesting and helpful in their ethical, legal and approved-with-express-written-consent usage of obfuscation:

  1. Invoke-Obfuscation can obfuscate PowerShell commands AND scripts. More than a few Red Teamers have pinged me thanking me for adding script obfuscation to the latest version of the framework. Yes, it has been present since the very beginning, but who am I to rain on their new discovery? Godspeed!
  2. SET SCRIPTPATH will also accept a URL to a PowerShell command or script so you can obfuscate the latest version of whatever remotely-hosted script you want, like Invoke-Mimikatz (SET SCRIPTPATH https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1) or the latest PowerShell logging bypass from @Lee_Homes: (SET SCRIPTPATH http://bit.ly/e0Mw9w). This feature is outlined in the framework's tutorial which can be viewed by running TUTORIAL: When a URL is entered as the ScriptPath value then the URL will be displayed in the ScriptPath field and the ScriptBlock field will show the downloaded command or script content.
  3. On the topic of input options, you can enter a ScriptBlock value containing basic EncodedCommand syntax (like that produced as one-liners from popular frameworks like Empire and Cobalt Strike) and Invoke-Obfuscation will extract and decode the encoded command and set the decoded payload as the ScriptBlock. For example:
    SET SCRIPTBLOCK powershell -enc VwByAGkAdABlAC0ASABvAHMAdAAgACcAWQBvAHUAIABjAGEAbgAgAHUAcwBlACAAYgBhAHMAaQBjACAALQBlAG4AYwAgAEUAbgBjAG8AZABlAGQAQwBvAG0AbQBhAG4AZAAgAHMAeQBuAHQAYQB4ACAAdwBpAHQAaABvAHUAdAAgAGEAbgB5ACAAbwB0AGgAZQByACAAZQB4AGUAYwB1AHQAaQBvAG4AIABhAHIAZwB1AG0AZQBuAHQAcwAgAGEAcwAgAGkAbgBwAHUAdAAgAGYAbwByACAAUwBjAHIAaQBwAHQAQgBsAG8AYwBrACAAdgBhAGwAdQBlACAAaQBuACAASQBuAHYAbwBrAGUALQBPAGIAZgB1AHMAYwBhAHQAaQBvAG4ALgAnACAALQBmACAAZwByAGUAZQBuAA==
  4. UNDO -- this is BY FAR my favorite addition to the framework. There is nothing more frustrating than walking through 10 obfuscation steps in a precise order only to have the very last obfuscation option bump the command over the 8,191 character limit for the command line. Now you can just enter UNDO as many times as you need to keep applying that obfuscation until it produces a result within the desired command length range.
  5. In version 1.6 (2017-01-24) I added the Process Argument Tree display whenever a LAUNCHER option is applied. This is particularly helpful for defenders to see additional detection opportunities outside of the final powershell.exe process execution. However, it is equally important for a Red Teamer to know what data is hitting the command line and in which process argument fields, as this should dictate heavily which LAUNCHER option is used (if any is used at all depending on what one is trying to evade). Below is an example of LAUNCHER\STDIN++\234:
  6. Another addition in version 1.6 was introducing CLI to enable non-interactive usage of the framework without needing to call all of the exposed underlying functions (the original intent behind exposing the ExecutionCommands values in the SHOW OPTIONS menu). This CLI addition also included numerous additions for both interactive and non-interactive usage of Invoke-Obfuscation. One feature included in the CLI update is Invoke-Obfuscation's support of full-blown RegEx in obfuscation option commands, like ENCODING\* or LAUNCHER\.*[+]{2} which greatly simplified and removed the need to update my testing harness after adding new obfuscation options to the framework.
  7. The CLI update also added auto-HOME/auto-MAIN functionality for command options. This means that if you are in TOKEN\ALL and want to add a random LAUNCHER, you do not have to first enter HOME or MAIN or repeatedly enter BACK until you arrive at the main menu. Instead, from any menu you can run LAUNCHER or LAUNCHER\*\234 and it will automatically route you to that menu. The ONLY exception to this is if you are in TOKEN and enter STRING then it will take you to TOKEN\STRING instead of the home menu's STRING. Joke's on me for not keeping all of the menu options unique.
  8. Lastly, CLI introduced command chaining in both interactive and non-interactive usage. When I am obfuscating payloads I RARELY use TOKEN\ALL\1 but instead obfuscate on particular tokens and in very particular orderings and layerings. With command chaining I can save off these "recipes" and share them with other Red Teamers trying to accomplish the same obfuscation goals. I will cover the particulars of this command chaining ordering in the next blog post, so for now let's focus on the chaining functionality regardless of what options or orderings are used. For non-interactive/CLI usage this chaining looks like: Invoke-Obfuscation -ScriptBlock {Write-Host 'CLI FTW!'} -Command 'Token\All\1,Encoding\1,Launcher\Stdin++\234,Clip' -Quiet -NoExit. However, my favorite use case for command chaining (after using it to store off obfuscation "recipes") is for undoing and re-applying obfuscation options until a certain command length is produced or a desired obfuscation syntax is applied (more on this last point in the next blog post in this series). So if I have a long PowerShell command to which I've already applied TOKEN\ALL\1 and I want to apply an ENCODING option but the result exceeds 8,191 characters (and I do not know which ENCODING options create the least command length bloat), then command chaining is a life saver. After applying TOKEN\ALL\1,ENCODING\* then I can keep running UNDO,* or UNDO,ENCODING\1 until it produces a result that is less than 8,191 characters in length.

NOTE: If running Invoke-Obfuscation on PowerShell for Linux or OS X then the back slashes might not be interpreted correctly, so change all back slashes to commas in above command chaining examples.

This wraps up Part 1 of this series on Invoke-Obfuscation usage. Hopefully you found some of the framework's history and lesser-known functionalities interesting. In the next post I will cover how I approach using Invoke-Obfuscation in various situations including obfuscation ordering, command option chaining for coaxing out particular obfuscation options, when (and how often) I use token-layer obfuscation options, and when I use (and more importantly do not use) LAUNCHER obfuscation. Stay tuned!