There seems to be an issue that can arise when doing string token obfuscation when using one of the special characters that use the string "replace" obfuscation. I encountered this issue when obfuscating the Get-SQLColumnSampleData module in Empire.
Steps to reproduce
PS > Invoke-Obfuscation -ScriptPath 'https://raw.githubusercontent.com/EmpireProject/Empire/2.0_beta/data/module_source/collection/Get-SQLColumnSampleData.ps1' -Command 'Token\All\1' -Quiet
Exception calling "Create" with "1" argument(s): "At line:843 char:23
+ HelpMessage = {("{3}{4}{1}{0}{2}"-f 'tput anyt','ou','hing.', ...
+ ~
Missing closing '}' in statement block or type definition.
At line:843 char:85
+ ... ("{3}{4}{1}{0}{2}"-f 'tput anyt','ou','hing.','DonCK','Et ')).REplacE ...
+ ~
Missing ] at end of attribute or type literal.
At line:843 char:85
+ ... ("{3}{4}{1}{0}{2}"-f 'tput anyt','ou','hing.','DonCK','Et ')).REplacE ...
+ ~
Parameter declarations are a comma-separated list of variable names with optional initializer expressions.
At line:843 char:85
+ ... ("{3}{4}{1}{0}{2}"-f 'tput anyt','ou','hing.','DonCK','Et ')).REplacE ...
+ ~
Missing ')' in function parameter list."
The problem can be minimized with this script as input:
PS> cat .\test.ps1
Function Get-DomainObject {
[CmdletBinding()]
Param(
[Parameter(HelpMessage = 'domain\user')]
[string]$Username
)
}
PS > Invoke-Obfuscation -ScriptPath .\test.ps1 -Command 'Token\All\1' -Quiet
Exception calling "Create" with "1" argument(s): "At line:4 char:34
+ [Parameter(HelpMessage = {("{2}{0}{4}{1}{3}" -f'om','P','d',' ...
+ ~
Missing closing '}' in statement block or type definition.
At line:4 char:85
+ ... Message = {("{2}{0}{4}{1}{3}" -f'om','P','d','Huser','ain6')).rEPLAce ...
+ ~
Missing ] at end of attribute or type literal.
At line:4 char:85
+ ... Message = {("{2}{0}{4}{1}{3}" -f'om','P','d','Huser','ain6')).rEPLAce ...
+ ~
Parameter declarations are a comma-separated list of variable names with optional initializer expressions.
At line:4 char:85
+ ... Message = {("{2}{0}{4}{1}{3}" -f'om','P','d','Huser','ain6')).rEPLAce ...
It may take a few tries to reproduce the error, as the error only occurs when the ".replace()" method of replacement is randomly selected.
Solution
The issue appears to stem from this section of code in Out-ObfuscatedTokenCommand.ps1:
When the ".replace()" technique of replacement is used it results in an $ObfuscatedToken of this form: (something).replace(something). You can see why trimming the leading and trailing parentheses wouldn't work in this case.
This can be fixed by checking if the parantheses are properly balanced post-trim before permanently removing the parentheses:
# Evenly trim leading/trailing parentheses.
While($ObfuscatedToken.StartsWith('(') -AND $ObfuscatedToken.EndsWith(')'))
{
$TrimmedObfuscatedToken = ($ObfuscatedToken.SubString(1,$ObfuscatedToken.Length-2)).Trim()
# Check if the parentheses are balanced before permenantly trimming
$Balanced = $True
$Counter = 0
ForEach($char in $TrimmedObfuscatedToken.ToCharArray()) {
If($char -eq '(') {
$Counter = $Counter + 1
}
ElseIf($char -eq ')') {
If($Counter -eq 0) {
$Balanced = $False
break
}
Else {
$Counter = $Counter - 1
}
}
}
# If parantheses are balanced, we can safely trim the parentheses
If($Balanced -and $Counter -eq 0) {
$ObfuscatedToken = $TrimmedObfuscatedToken
}
# If parentheses cannot be trimmed, break out of loop
Else {
break
}
}
There might be other ways of solving it, but this was the only one I could think of. There is another suspiciously similar looking block of code in Out-ObfuscatedTokenCommand.ps1:
Problem
There seems to be an issue that can arise when doing string token obfuscation when using one of the special characters that use the string "replace" obfuscation. I encountered this issue when obfuscating the Get-SQLColumnSampleData module in Empire.
Steps to reproduce
The problem can be minimized with this script as input:
It may take a few tries to reproduce the error, as the error only occurs when the ".replace()" method of replacement is randomly selected.
Solution
The issue appears to stem from this section of code in Out-ObfuscatedTokenCommand.ps1:
When the ".replace()" technique of replacement is used it results in an
$ObfuscatedToken
of this form:(something).replace(something)
. You can see why trimming the leading and trailing parentheses wouldn't work in this case.This can be fixed by checking if the parantheses are properly balanced post-trim before permanently removing the parentheses:
There might be other ways of solving it, but this was the only one I could think of. There is another suspiciously similar looking block of code in Out-ObfuscatedTokenCommand.ps1:
I haven't run into any problems from this block of code, but it may be worth investigating as well.