The Out-ObfuscatedCommandTokenLevel2 function adds an invoke operator even if one already exists, without wrapping the script in parentheses.
I discovered this issue while attempting to obfuscate modules in the Empire project.
This error specifically was found while attempting to obfuscate Invoke-WinEnum.ps1
Steps to reproduce
PS> git clone https://github.com/danielbohannon/Invoke-Obfuscation.git
PS> wget https://github.com/adaptivethreat/Empire/raw/master/data/module_source/situational_awareness/host/Invoke-WinEnum.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 .\Invoke-WinEnum.ps1 | Out-File out
Obfuscating Invoke-WinEnum.ps1
[*] Obfuscating 25 Comment tokens.
[*] Obfuscating 155 String tokens.
[*] Obfuscating 66 Argument tokens.
[*] Obfuscating 90 Command tokens.
Exception calling "Create" with "1" argument(s): "At line:116 char:15
+ & &("{0}{1}{2}"-f 'powers','h','ell') -Sta -Command $cmd
+ ~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation marks ("&") to pass it as part of a string."
At <PATH>\Invoke-Obfuscation\Out-ObfuscatedTokenCommand.ps1:137 char:13
+ $ScriptString = Out-ObfuscatedTokenCommand ([ScriptBlock] ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ParseException
(errors continue)
The error message makes it pretty clear that there is a problem with an invoke operator (ampersand).
Reducing the Invoke-WinEnum.ps1 file to this minified version still reproduces the error.
& powershell
Solution
It seems as if simply wrapping parentheses around the existing invoke operator fixes the problem.
Adding code so that the following:
# Randomly choose between the & and . Invoke Operators.
# In certain large scripts where more than one parameter are being passed into a custom function
# (like Add-SignedIntAsUnsigned in Invoke-Mimikatz.ps1) then using . will cause errors but & will not.
# For now we will default to only & if $ScriptString.Length -gt 10000
If($ScriptString.Length -gt 10000) {$RandomInvokeOperator = '&'}
Else {$RandomInvokeOperator = Get-Random -InputObject @('&','.')}
# Add invoke operator (and potentially whitespace) to complete splatting command.
$ObfuscatedToken = $RandomInvokeOperator + $ObfuscatedToken
# Add the obfuscated token back to $ScriptString.
$ScriptString = $ScriptString.SubString(0,$Token.Start) + $ObfuscatedToken + $ScriptString.SubString($Token.Start+$Token.Length)
Return $ScriptString
becomes:
# Randomly choose between the & and . Invoke Operators.
# In certain large scripts where more than one parameter are being passed into a custom function
# (like Add-SignedIntAsUnsigned in Invoke-Mimikatz.ps1) then using . will cause errors but & will not.
# For now we will default to only & if $ScriptString.Length -gt 10000
If($ScriptString.Length -gt 10000) {$RandomInvokeOperator = '&'}
Else {$RandomInvokeOperator = Get-Random -InputObject @('&','.')}
# Add invoke operator (and potentially whitespace) to complete splatting command.
$ObfuscatedToken = $RandomInvokeOperator + $ObfuscatedToken
# If an invoke operator is already in use, then we need to wrap this one in parentheses
If($ScriptString.SubString(0,$Token.Start).Trim().EndsWith('&') -or $ScriptString.SubString(0,$Token.Start).Trim().EndsWith('.')) {
$ObfuscatedToken = '(' + $ObfuscatedToken + ')'
}
# Add the obfuscated token back to $ScriptString.
$ScriptString = $ScriptString.SubString(0,$Token.Start) + $ObfuscatedToken + $ScriptString.SubString($Token.Start+$Token.Length)
Return $ScriptString
Problem
The Out-ObfuscatedCommandTokenLevel2 function adds an invoke operator even if one already exists, without wrapping the script in parentheses.
I discovered this issue while attempting to obfuscate modules in the Empire project.
This error specifically was found while attempting to obfuscate Invoke-WinEnum.ps1
Steps to reproduce
The error message makes it pretty clear that there is a problem with an invoke operator (ampersand).
Reducing the Invoke-WinEnum.ps1 file to this minified version still reproduces the error.
Solution
It seems as if simply wrapping parentheses around the existing invoke operator fixes the problem.
Adding code so that the following:
becomes: