Using Bitwise NOT operations to obfuscate commands in PowerShell
malware powershellBitwise NOT commands are often used in PowerShell malware samples to obfuscate commands. A bitwise NOT operation flips all the bits in a given byte sequence.
<#
Bitwise NOT operations will flip all bits
As an example, consider the following:
$byte = 00000101 | binary for 5
Performing a bitwise NOT operation flips all of the bits
$byte = 11111010 | binary for -6 (two's complement)
#>
$dec = 5
-bnot $dec # will print out -6
PowerShell
There are many ways to use this operation in obfuscation and execution of malicious (and non-malicious!) commands. However, this post will focus on crafting custom Invoke-Expression commands using [System.Text.Encoding] to convert the bitwise NOT values to UTF8 strings.
Consider the following sample pulled from MalwareBazaar.
# Convert a Base64 string into a byte array
$bytesOfRes=[Convert]::FromBase64String($OutRes)
# Loop through the byte array
for ($i=0;$i -lt $bytesOfRes.Length;$i++){
#Operate on $i byte
$bytesOfRes[$i]=[Convert]::ToByte(([Convert]::ToString(-bnot ($bytesOfRes[$i]),2).Substring(24,8)),2)
}
#Convert the resulting byte array to a UTF8 string
$LastEx=[System.Text.Encoding]::UTF8.GetString($bytesOfRes)
# Use Get-Command to get execute the string via Invoke-Expression and a call operator
&((gcm *v?k?-?x?re*).name) $LastEx
PowerShell
This snippet uses a bitwise NOT operation as the basis for converting a byte array into a UTF8 string to execute a malicious command. A base 64 string is downloaded from a remote server. This string is decoded via the [Convert]::FromBase64String method. The method decodes a base 64 string into a UTF8 byte array.
[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("hello"))
# aGVsbG8=
[Convert]::FromBase64String("aGVsbG8=")
# 104
# 101
# 108
# 108
# 111
[System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("aGVsbG8="))
# hello
PowerShell
After converting the string to a byte array, the for loop on line #5 operates on each byte element in the array. This is where the bulk of the magic happens.
# Expanded loop
# Replaces the current element with the result of the operation
$bytesOfRes[$i] =
<#
Convert the result to byte
|
|
| Convert the result to a binary string
| |
| |
| | Perform a bitwise NOT operation on $i byte element
| | |
| | |
| | | Get the last 8 bits of the result
| | | |
| | | | #>
[Convert]::ToByte(([Convert]::ToString(-bnot ($bytesOfRes[$i]),2).substring(24,8)),2)
# Note: [Convert]::ToString($foo,2) will return a binary value
# Hence the substring(24,8) on the bitwise NOT operation
}
PowerShell
As you can see, the current element in the loop is transformed via bitwise NOT operation into a binary value which is then converted into a byte value. The resulting byte array of the for loop is converted into a valid UTF8 string and then executed via a call operator and Invoke-Expression.
#Convert the resulting byte array to a UTF8 string
$LastEx=[System.Text.Encoding]::UTF8.GetString($bytesOfRes)
<#
Use Get-Command to get execute the string via Invoke-Expression and a call operator
gcm is the alias for Get-Command. Using wildcard operators, the value "*v?k?-?x?re*" matches
the string name of Invoke-Expression. Using the name property of the returned Get-Command
object, it is possible to dynamically build an IEX command string that can be executed with
the '&' symbol, also called a call operator.
#>
&((gcm *v?k?-?x?re*).name) $LastEx
PowerShell
To create a payload for execution, use the [System.Text.Encoding]::UTF8.GetBytes method to convert a string to a series of bytes. Then, use a bitwise NOT operation on the byte array to get the BNOT array.
# Create a byte array with our command
$ByteArray = [System.Text.Encoding]::UTF8.GetBytes("Write-Host 'Hello World'")
# Perform a bitwise NOT operation on each byte in the array
$BNOTArray = $ByteArray | %{-bnot $_ }
#Convert the BNOT array back to the original value using the same method as described above
$Command = $BNOTArray | %{[Convert]::ToByte(([Convert]::ToString(-bnot ($_),2)),2)}
# Convert the byte array to a string
$STRCommand = [System.Text.Encoding]::UTF8.GetString($Command)
# Use the call operator to invoke the command
&((gcm *v?k?-?x?re*).name) $STRCommand
#Hello World
# In one line
&((gcm *v?k?-?x?re*).name) ([String]::new((($BNOTArray|%{[Convert]::ToString(-bnot $_,2)})|%{[Convert]::ToByte($_,2)})))
PowerShell