When Out-ObfuscatedTokenCommand.ps1 attempts to determine whether to '$EncapsulateAsScriptBlockInsteadOfParentheses', it misses the 'HelpMessage' and 'ConfirmImpact' ParameterBinding options.
I discovered this issue while attempting to obfuscate modules in the Empire project.
PS> git clone https://github.com/danielbohannon/Invoke-Obfuscation.git
PS> wget https://github.com/adaptivethreat/Empire/raw/master/data/module_source/situational_awareness/network/Get-SPN.ps1
PS> wget https://github.com/adaptivethreat/Empire/raw/master/data/module_source/privesc/Invoke-EventVwrBypass.ps1
PS> wget https://github.com/adaptivethreat/Empire/raw/master/data/module_source/code_execution/Invoke-Shellcode.ps1
PS> Import-Module .\Invoke-Obfuscation\Invoke-Obfuscation.psm1
[*] Validating necessary commands are loaded into current PowerShell session.
[*] Function Loaded :: Out-ObfuscatedTokenCommand
[*] Function Loaded :: Out-ObfuscatedStringCommand
[*] Function Loaded :: Out-EncodedAsciiCommand
[*] Function Loaded :: Out-EncodedHexCommand
[*] Function Loaded :: Out-EncodedOctalCommand
[*] Function Loaded :: Out-EncodedBinaryCommand
[*] Function Loaded :: Out-SecureStringCommand
[*] Function Loaded :: Out-EncodedBXORCommand
[*] Function Loaded :: Out-PowerShellLauncher
[*] Function Loaded :: Invoke-Obfuscation
[*] All modules loaded and ready to run Invoke-Obfuscation
PS> Out-ObfuscatedTokenCommand -Path .\Get-SPN.ps1 | Out-File out
Obfuscating Get-SPN.ps1
[*] Obfuscating 27 Comment tokens.
[*] Obfuscating 69 String tokens.
Exception calling "Create" with "1" argument(s): "At line:14 char:21
+ ... HelpMessage=("{8}{12}{14}{1}{11}{13}{5}{10}{3}{0}{7}{4}{2}{6}{9}{15}" ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Attribute argument must be a constant or a script block.
At line:19 char:21
+ ... HelpMessage=("{8}{11}{5}{9}{2}{0}{1}{10}{4}{6}{7}{3}"-f 'r Domain',' ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Attribute argument must be a constant or a script block.
(errors continue)
The error message makes it pretty clear that there is a problem with the 'HelpMessage' ParameterBinding.
The other two files show a similar error message, but for the 'ConfirmImpact' ParameterBinding.
Reducing the Get-SPN.ps1 file to this minified version still reproduces the error.
function Get-SPN
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$false,
HelpMessage="Credentials to use when connecting to a Domain Controller.")]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty
)
}
Solution
It seems that these are similar issues to the one described in the source here.
# For Parameter Binding the value has to either be plain concatenation or must be a scriptblock in which case we will encapsulate with {} instead of ().
# The encapsulation will occur later in the function. At this point we're just setting the boolean variable $EncapsulateAsScriptBlockInsteadOfParentheses.
# Actual error that led to this is: "Attribute argument must be a constant or a script block."
# ALLOWED :: [CmdletBinding(DefaultParameterSetName={"{1}{0}{2}"-f'd','DumpCre','s'})]
# NOT ALLOWED :: [CmdletBinding(DefaultParameterSetName=("{1}{0}{2}"-f'd','DumpCre','s'))]
The only difference being that it is for 'HelpMessage' and 'ConfirmImpact' instead of 'DefaultParameterSetName'.
The code that follow this explanation seems to only cover the case of 'DefaultParameterSetName'.
Replacing that code with the following code remediates the issue for 'HelpMessage' and 'ConfirmImpact'. (Though, maybe some work should be done to determine if others should join this list.)
Problem
When Out-ObfuscatedTokenCommand.ps1 attempts to determine whether to '$EncapsulateAsScriptBlockInsteadOfParentheses', it misses the 'HelpMessage' and 'ConfirmImpact' ParameterBinding options.
I discovered this issue while attempting to obfuscate modules in the Empire project.
This error specifically was found while attempting to obfuscate Get-SPN.ps1, Invoke-EventVwrBypass.ps1, and Invoke-ShellCode.ps1.
Steps to reproduce
The error message makes it pretty clear that there is a problem with the 'HelpMessage' ParameterBinding. The other two files show a similar error message, but for the 'ConfirmImpact' ParameterBinding.
Reducing the Get-SPN.ps1 file to this minified version still reproduces the error.
Solution
It seems that these are similar issues to the one described in the source here.
The only difference being that it is for 'HelpMessage' and 'ConfirmImpact' instead of 'DefaultParameterSetName'.
The code that follow this explanation seems to only cover the case of 'DefaultParameterSetName'.
Replacing that code with the following code remediates the issue for 'HelpMessage' and 'ConfirmImpact'. (Though, maybe some work should be done to determine if others should join this list.)
This is also a more systematic way of grabbing the ParameterBinding option's name, as opposed to assuming a length of the attribute itself.