Base64 Encoding & Decoding with CLM

TLDR – Here’s the link: https://github.com/FortyNorthSecurity/CLM-Base64

Why Writing CLM-Compliant V2 Code?

Following in the footsteps of those I originally learned from (@mattifestation and @harmj0y), when I first began to learn PowerShell, I tried to force myself to only write PowerShell v2 code. Developing in version 2 ensured that I could use what I wrote on nearly every computer I would encounter, even if the system I was using had v3 or higher. This concept stood the test of time, and worked well. Then, I encountered Constrained Language mode (CLM) while developing the tool WMImplant.

Constrained Language Mode Description

Constrained Language Mode essentially allows pure-PowerShell cmdlets, but blocks blacklisted datatypes. Upon discovering the above, my interest in developing PowerShell code shifted from strictly developing v2 compliant code to v2 code which also is Constrained Language mode compliant. This may seem odd, because the most probable use case where one would encounter CLM is on a Device Guard protected system, in which case an attacker would have access to PowerShell v5. I chose to develop under these circumstances because – if possible – I’d prefer to have a tool or library, which can work in any environment without limitation.

Bases64 Encoding/Decoding Within CLM

When developing WMImplant, one of the first issues I encountered was finding an encoder which would work in CLM. PowerShell can perform base64 encoding and decoding, but attempting to do so within CLM results in the following (steps taken from ADSecurity.org):

Base64 Encoding Blocked in CLM

As of the time of this blog post (and as far as I am aware) there is currently no other means to Base64 encode/data within CLM. Eventually, with the help of Daniel Bohannon, I added a different encoder to WMImplant but remained interested in researching how to enable Base64 encoding and decoding in CLM. As such, I’m excited to show you a PowerShell script which provides base64 encoding and decoding functionality within CLM.

CLM-Base64 Script Functionality

This script enables users to “ConvertTo-Base64” or “ConvertFrom-Base64”. You can Base64 encode both strings or files and decode both inputs as well. To Base64 encode the string “FortyNorth Security” you can use the following command:

ConvertTo-Base64 -String “FortyNorth Security”

The inverse operation would be to convert the Base64 encoded string back to its original format with the following:

ConvertFrom-Base64 -String “Rm9ydHlOb3J0aCBTZWN1cml0eQ==”

These commands are shown below:

Base64 Encoding within CLM

The same concept applies with files you would like to encode. For example, we can encode a google logo and output it to a file. Then, we can read in the file’s contents (containing the encoded image) and decode it, writing the graphic back to disk. This is shown in the image below:

Encoding Files

Alternate Character Set

According to the RFC, when Base64 encoding data, there is a pre-defined set of characters that are used for encoding it. One of the tricks that malware authors like to use is to encode data with an alternate character set. Doing something as simple as changing the characters used for encoding data can confuse and prevent automated decoding of Base64 encoded data. PowerShell-Base64 allows its users to provide an alternate encoding character set for both encoding and decoding data.

To use an alternate character set, you would need to create a hash table containing the following data (and modify each key’s associated value):

$changed = @{ 0 = "A" 1 = "B" 2 = "C" 3 = "D" 4 = "E" 5 = "F" 6 = "G" 7 = "H" 8 = "I" 9 = "J" 10 = "K" 11 = "L" 12 = "M" 13 = "N" 14 = "O" 15 = "P" 16 = "Q" 17 = "R" 18 = "S" 19 = "T" 20 = "U" 21 = "V" 22 = "W" 23 = "X" 24 = "Y" 25 = "Z" 26 = "a" 27 = "b" 28 = "c" 29 = "d" 30 = "e" 31 = "f" 32 = "g" 33 = "h" 34 = "i" 35 = "j" 36 = "k" 37 = "l" 38 = "m" 39 = "n" 40 = "o" 41 = "p" 42 = "q" 43 = "r" 44 = "s" 45 = "t" 46 = "u" 47 = "v" 48 = "w" 49 = "x" 50 = "y" 51 = "z" 52 = "0" 53 = "1" 54 = "2" 55 = "3" 56 = "4" 57 = "5" 58 = "6" 59 = "7" 60 = "8" 61 = "9" 62 = "+" 63 = "/" "Padding" = "*" }

With the above hash table, you can use the -AltAlphabet option and provide $changed, as shown below:

ConvertTo-Base64 -String 'FortyNorth Security Test' -AltAlphabet $changed

With that one addition, you have now modified the character set that is used when encoding/decoding data.

I hope this functionality can help should you need it on a system with Constrained Language Mode enabled. If you have any questions, please don’t hesitate to reach out to us!