def main(self): #my_app_path = 'C:\\Windows\\System32\\cmd.exe' my_app_path = r'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' startup = win32process.STARTUPINFO() priority = win32con.NORMAL_PRIORITY_CLASS console_user_token = getusertoken() environment = win32profile.CreateEnvironmentBlock( console_user_token, False) handle, thread_id, pid, tid = win32process.CreateProcessAsUser( console_user_token, my_app_path, None, None, None, True, priority, environment, None, startup)
def StartAgent(): #pythonw (run in background) my_app_path = r'C:\Users\Mathieu\AppData\Local\Programs\Python\Python37-32\pythonw.exe' #my_app_path = r'C:\Windows\System32\cmd.exe' startup = win32process.STARTUPINFO() priority = win32con.NORMAL_PRIORITY_CLASS console_user_token = getusertoken() environment = win32profile.CreateEnvironmentBlock(console_user_token, False) handle, thread_id ,pid, tid = win32process.CreateProcessAsUser(console_user_token, my_app_path, r' C:\git\WebsocketShelling\shell-pwned.py', None, None, True, priority, environment, None, startup) return pid
def create_env(user_token, inherit, timeout=1): """ CreateEnvironmentBlock might fail when we close a login session and then try to re-open one very quickly. Run the method multiple times to work around the async nature of logoffs. """ start = time.time() env = None exc = None while True: try: env = win32profile.CreateEnvironmentBlock(user_token, False) except pywintypes.error as exc: pass else: break if time.time() - start > timeout: break if env is not None: return env raise exc
## Marshal saved credential and use it to log on mc = win32cred.CredMarshalCredential(win32cred.UsernameTargetCredential, target) th = win32security.LogonUser(mc, None, '', win32con.LOGON32_LOGON_INTERACTIVE, win32con.LOGON32_PROVIDER_DEFAULT) win32security.ImpersonateLoggedOnUser(th) print 'GetUserName:'******'s profile. (first check if user has a roaming profile) username, domain = win32cred.CredUIParseUserName(target) user_info_4 = win32net.NetUserGetInfo(None, username, 4) profilepath = user_info_4['profile'] ## LoadUserProfile apparently doesn't like an empty string if not profilepath: profilepath = None ## leave Flags in since 2.3 still chokes on some types of optional keyword args hk = win32profile.LoadUserProfile(th, { 'UserName': username, 'Flags': 0, 'ProfilePath': profilepath }) ## Get user's environment variables in a form that can be passed to win32process.CreateProcessAsUser env = win32profile.CreateEnvironmentBlock(th, False) ## Cleanup should probably be in a finally block win32profile.UnloadUserProfile(th, hk) th.Close()
def runScreenShotApp(self): global DISABLE_SSHOT if DISABLE_SSHOT is True: return # Get the session id for the console session_id = win32ts.WTSGetActiveConsoleSessionId() if session_id == 0xffffffff: # User not logged in right now? logging.info("No console user") return None # logging.info("Got Console: " + str(session_id)) # Login to the terminal service to get the user token for the console id svr = win32ts.WTSOpenServer(".") user_token = win32ts.WTSQueryUserToken(session_id) # logging.info("User Token " + str(user_token)) # Copy the token user_token_copy = win32security.DuplicateTokenEx( user_token, win32security.SecurityImpersonation, win32security.TOKEN_ALL_ACCESS, win32security.TokenPrimary) # Put this token in the logged in session win32security.SetTokenInformation(user_token_copy, win32security.TokenSessionId, session_id) # Switch to the user # win32security.ImpersonateLoggedOnUser(user_token) # logging.info("Impersonating " + win32api.GetUserName()) # Run the screen shot app # app_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))) # cmd = os.path.join(app_path, "sshot\\dist\\sshot.exe") cmd = os.path.join(ROOT_FOLDER, "ope_laptop_binaries\\sshot\\sshot.exe" ) # "c:\\programdata\\ope\\bin\\sshot.exe" # cmd = "cmd.exe" logging.info("Running sshot app " + cmd) # Use win create process function si = win32process.STARTUPINFO() si.dwFlags = win32process.STARTF_USESHOWWINDOW si.wShowWindow = win32con.SW_NORMAL # si.lpDesktop = "WinSta0\Default" si.lpDesktop = "" # Setup envinroment for the user environment = win32profile.CreateEnvironmentBlock(user_token, False) try: ( hProcess, hThread, dwProcessId, dwThreadId ) = win32process.CreateProcessAsUser( user_token_copy, None, # AppName (really command line, blank if cmd line supplied) "\"" + cmd + "\"", # Command Line (blank if app supplied) None, # Process Attributes None, # Thread Attributes 0, # Inherits Handles win32con. NORMAL_PRIORITY_CLASS, # or win32con.CREATE_NEW_CONSOLE, environment, # Environment os.path.dirname(cmd), # Curr directory si) # Startup info # logging.info("Process Started: " + str(dwProcessId)) # logging.info(hProcess) except Exception as e: logging.info("Error launching process: " + str(e)) # logging.info(os.system(cmd)) # Return us to normal security # win32security.RevertToSelf() # Cleanup win32ts.WTSCloseServer(svr) user_token.close() user_token_copy.close() return
def _RunAsOnWindowStationDesktop(command_line, security_token, window_station, desktop, env=None, cwd=None, timeout=win32event.INFINITE): """Runs a command as the security token user on given desktop. Args: command_line: Full command line string to run. security_token: Security token that the command run as. window_station: Window station for the new process to run, tpically is "WinSta0", aka the interactive window station. desktop: Desktop that the new process will be associatedw with, typically is 'default'. env: The environment variables to pass to the child process, or None to inherit from parent. cwd: The working directory of the child process, or None to inherit from parent. timeout: How long should wait for child process. 0 means no wait, None means infinitely. Returns: (pid, exit_code, stdout, stderr) tuple. Raises: ImpersonationError: when impersonation failed. """ pipes = _StdoutStderrPipes() si = win32process.STARTUPINFO() si.dwFlags = (win32process.STARTF_USESHOWWINDOW | win32con.STARTF_USESTDHANDLES) si.wShowWindow = win32con.SW_SHOW si.lpDesktop = '%s\\%s' % (window_station, desktop) si.hStdOutput = pipes.stdout_w si.hStdError = pipes.stderr_w create_flags = (win32process.CREATE_NEW_CONSOLE | win32process.CREATE_UNICODE_ENVIRONMENT) if env: saved_env = dict(os.environ) os.environ.update(env) env_block = win32profile.CreateEnvironmentBlock(security_token, True) (process_handle, unused_thread, pid, unused_thread_id) = win32process.CreateProcessAsUser( security_token, None, command_line, None, None, 1, create_flags, env_block, cwd, si) if env: os.environ.clear() os.environ.update(saved_env) pipes.CloseWriteHandles() if not process_handle: logging.error('Failed to create child process [%s] on [%s\\%s]', command_line, window_station, desktop) raise ImpersonationError( 'Failed to create process [%s] with impersonation: [%s\\%s][%s]' % (command_line, window_station, desktop, cwd)) pipes.ReadAll() logging.info('Child process [%s] created on [%s\\%s]', command_line, window_station, desktop) logging.info('Waiting %s seconds for child process.', timeout) if timeout != win32event.INFINITE: timeout *= 1000 # Convert from seconds to milli-seconds. wait_result = win32event.WaitForSingleObject(process_handle, timeout * 1000) if wait_result == win32event.WAIT_OBJECT_0: exit_code = win32process.GetExitCodeProcess(process_handle) logging.info('Child process exited with code %s.', exit_code) logging.info('Child process STDOUT: %s', pipes.stdout) logging.error('Child process STDERR: %s.', pipes.stderr) return (pid, exit_code, pipes.stdout, pipes.stderr) else: if timeout != 0: logging.warning('Wait for child process timeout in %s seconds', timeout / 1000) return (pid, None, None, None)
async def start(self): """Start the single-user server.""" self.port = random_port() cmd = [] env = self.get_env() token = None cmd.extend(self.cmd) cmd.extend(self.get_args()) if self.shell_cmd: # using shell_cmd (e.g. bash -c), # add our cmd list as the last (single) argument: cmd = self.shell_cmd + [' '.join(pipes.quote(s) for s in cmd)] self.log.info("Spawning %s", ' '.join(pipes.quote(s) for s in cmd)) auth_state = await self.user.get_auth_state() if auth_state: token = pywintypes.HANDLE(auth_state['auth_token']) user_env = None cwd = None try: # Will load user variables, if the user profile is loaded user_env = win32profile.CreateEnvironmentBlock(token, False) except Exception as exc: self.log.warning("Failed to load user environment for %s: %s", self.user.name, exc) else: # Only load user environment if we hold a valid auth token if token: env.update(user_env) if not 'APPDATA' in user_env: #If the 'APPDATA' does not exist, the USERPROFILE points at the default #directory which is not writable. this changes the path over to public #documents, so at least its a writable location. user_env['USERPROFILE'] = user_env['PUBLIC'] # On Posix, the cwd is set to ~ before spawning the singleuser server (preexec_fn). # Windows Popen doesn't have preexec_fn support, so we need to set cwd directly. if self.notebook_dir: cwd = os.getcwd() elif env['APPDATA']: cwd = user_env['USERPROFILE'] else: # Set CWD to a temp directory, since we failed to load the user profile cwd = mkdtemp() popen_kwargs = dict( token=token, cwd=cwd, ) popen_kwargs.update(self.popen_kwargs) # don't let user config override env popen_kwargs['env'] = env try: self.proc = PopenAsUser(cmd, **popen_kwargs) except PermissionError: # use which to get abspath script = shutil.which(cmd[0]) or cmd[0] self.log.error("Permission denied trying to run %r. Does %s have access to this file?", script, self.user.name, ) if token: token.Detach() raise self.pid = self.proc.pid if token: token.Detach() if self.__class__ is not LocalProcessSpawner: # subclasses may not pass through return value of super().start, # relying on deprecated 0.6 way of setting ip, port, # so keep a redundant copy here for now. # A deprecation warning will be shown if the subclass # does not return ip, port. if self.ip: self.server.ip = self.ip self.server.port = self.port self.db.commit() return (self.ip or '127.0.0.1', self.port)
def runas_system(cmd, username, password): # This only works as system, when salt is running as a service for example # Check for a domain domain = '.' if '@' in username: username, domain = username.split('@') if '\\' in username: domain, username = username.split('\\') # Load User and Get Token token = win32security.LogonUser(username, domain, password, win32con.LOGON32_LOGON_INTERACTIVE, win32con.LOGON32_PROVIDER_DEFAULT) # Load the User Profile handle_reg = win32profile.LoadUserProfile(token, {'UserName': username}) try: # Get Unrestricted Token (UAC) if this is an Admin Account elevated_token = win32security.GetTokenInformation( token, win32security.TokenLinkedToken) # Get list of privileges this token contains privileges = win32security.GetTokenInformation( elevated_token, win32security.TokenPrivileges) # Create a set of all privileges to be enabled enable_privs = set() for luid, flags in privileges: enable_privs.add((luid, win32con.SE_PRIVILEGE_ENABLED)) # Enable the privileges win32security.AdjustTokenPrivileges(elevated_token, 0, enable_privs) except win32security.error as exc: # User doesn't have admin, use existing token if exc[0] == winerror.ERROR_NO_SUCH_LOGON_SESSION \ or exc[0] == winerror.ERROR_PRIVILEGE_NOT_HELD: elevated_token = token else: raise # Get Security Attributes security_attributes = win32security.SECURITY_ATTRIBUTES() security_attributes.bInheritHandle = 1 # Create a pipe to set as stdout in the child. The write handle needs to be # inheritable. stdin_read, stdin_write = win32pipe.CreatePipe(security_attributes, 0) stdin_read = make_inheritable(stdin_read) stdout_read, stdout_write = win32pipe.CreatePipe(security_attributes, 0) stdout_write = make_inheritable(stdout_write) stderr_read, stderr_write = win32pipe.CreatePipe(security_attributes, 0) stderr_write = make_inheritable(stderr_write) # Get startup info structure startup_info = win32process.STARTUPINFO() startup_info.dwFlags = win32con.STARTF_USESTDHANDLES startup_info.hStdInput = stdin_read startup_info.hStdOutput = stdout_write startup_info.hStdError = stderr_write # Get User Environment user_environment = win32profile.CreateEnvironmentBlock(token, False) # Build command cmd = 'cmd /c {0}'.format(cmd) # Run command and return process info structure procArgs = (None, cmd, security_attributes, security_attributes, 1, 0, user_environment, None, startup_info) hProcess, hThread, PId, TId = \ win32process.CreateProcessAsUser(elevated_token, *procArgs) if stdin_read is not None: stdin_read.Close() if stdout_write is not None: stdout_write.Close() if stderr_write is not None: stderr_write.Close() hThread.Close() # Initialize ret and set first element ret = {'pid': PId} # Get Standard Out fd_out = msvcrt.open_osfhandle(stdout_read, os.O_RDONLY | os.O_TEXT) with os.fdopen(fd_out, 'r') as f_out: ret['stdout'] = f_out.read() # Get Standard Error fd_err = msvcrt.open_osfhandle(stderr_read, os.O_RDONLY | os.O_TEXT) with os.fdopen(fd_err, 'r') as f_err: ret['stderr'] = f_err.read() # Get Return Code if win32event.WaitForSingleObject( hProcess, win32event.INFINITE) == win32con.WAIT_OBJECT_0: exitcode = win32process.GetExitCodeProcess(hProcess) ret['retcode'] = exitcode # Close handle to process win32api.CloseHandle(hProcess) # Unload the User Profile win32profile.UnloadUserProfile(token, handle_reg) return ret
def CreateProc(appname, cmdline=None): global cfg #找到winlogon.exe的进程信息,然后复制它的token,再赋权新的token,用新token创建的新进程,就有前台交互权限了 p = getProcess(caption='winlogon.exe')[0] pid = p['pid'] if cfg['debug']: mylog("pid=%d,type=%s" % (pid, type(pid))) #通过winlogon.exe的pid打开进程,获得它的句柄 handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid) #通过winlogon.exe的句柄,获得它的令牌(经测试,admin权限运行的程序,只能用TOKEN_QUERY方式打开,service方式运行的程序,有全部权限) token_handle = win32security.OpenProcessToken( handle, win32con.TOKEN_ADJUST_PRIVILEGES | win32con.TOKEN_QUERY | win32con.TOKEN_DUPLICATE) if cfg['debug']: print("winlogon.exe's handle=%s,token=%s" % (handle, token_handle)) res = None #通过winlogon.exe的令牌,复制一个新令牌(经测试,admin权限运行的程序,权限不足,service方式运行的程序,有全部权限) dup_th = win32security.DuplicateTokenEx( token_handle, win32security.SecurityImpersonation, win32security.TOKEN_ALL_ACCESS, win32security.TokenPrimary, ) #通过winlogon.exe的pid,获得它的session id(经测试,admin权限运行的程序,没TCB权限,需要service方式运行的程序,有全部权限) curr_session_id = win32ts.ProcessIdToSessionId(pid) if cfg['debug']: print("dup_th=%s" % dup_th) #获得系统默认的程序启动信息(初始化程序所需的,标准输出、桌面选择等信息) startup = win32process.STARTUPINFO() if cfg['debug']: print(startup) #下面的这个win32con.CREATE_NEW_CONSOLE权限必须给,要不后面CreateProcessAsUser时看到执行了,然后程序就没了 priority = win32con.NORMAL_PRIORITY_CLASS | win32con.CREATE_NEW_CONSOLE if cfg['debug']: mylog("in CreateProc(),appname=%s,cmdline=%s" % (appname, cmdline)) (hProcess, hThread, dwProcessId, dwThreadId) = (None, None, None, None) #通过winlogon.exe的session id获得它的console令牌 console_user_token = win32ts.WTSQueryUserToken(curr_session_id) #通过winlogon.exe的console令牌,获得它的环境profile设置信息 environment = win32profile.CreateEnvironmentBlock(console_user_token, False) #给复制出来的token,绑定对应的session id,使之基于和winlogon.exe一样的会话 win32security.SetTokenInformation(dup_th, win32security.TokenSessionId, curr_session_id) #设置调整权限的flag权限 flags = win32con.TOKEN_ADJUST_PRIVILEGES | win32con.TOKEN_QUERY #设置权限1:找到SE_DEBUG_NAME的权限的id,给p1 p1 = win32security.LookupPrivilegeValue(None, win32con.SE_DEBUG_NAME) newPrivileges = [(p1, win32con.SE_PRIVILEGE_ENABLED)] #把复制出来的winlogon.exe的token,增加新权限(也即是SE_DEBUG_NAME权限) win32security.AdjustTokenPrivileges(dup_th, False, newPrivileges) if cfg['debug']: privs = getPrivs(dup_th) mylog("privs=%s" % "\n".join(privs)) #下面准备启动程序需要的重定向的标准输出和标准错误输出的文件句柄,但目前似乎没有重定向成功:( fh_stdout = win32file.CreateFile( os.path.join(app_path, "watchdog.stdout"), win32file.GENERIC_WRITE, win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE, None, win32file.OPEN_ALWAYS, win32file.FILE_FLAG_SEQUENTIAL_SCAN, 0) fh_stderr = win32file.CreateFile( os.path.join(app_path, "watchdog.stderr"), win32file.GENERIC_WRITE, win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE, None, win32file.OPEN_ALWAYS, win32file.FILE_FLAG_SEQUENTIAL_SCAN, 0) startup.hStdOutput = fh_stdout startup.hStdError = fh_stderr #下面开始尝试用复制好的token:dup_th,并也给了足够的权限的token,然后来启动指定程序 try: (hProcess, hThread, dwProcessId, dwThreadId) = win32process.CreateProcessAsUser( dup_th, appname, cmdline, None, None, True, priority, None, None, startup) except Exception as e: mylog("in CreateProc(),return False,ERROR:%s" % str(e)) return False mylog("%s,%s,%s,%s" % (hProcess, hThread, dwProcessId, dwThreadId)) if dwProcessId == None: #创建进程失败 mylog( "Can not get dwProcessId from win32process.CreateProcessAsUser()") return False try: time.sleep(2) mylog("dwProcessId=%s" % dwProcessId) process = psutil.Process(dwProcessId) except Exception as e: mylog("CreateProc(),try to psutil.Process(),ERROR:%s" % str(e)) mylog("process:%s" % process) return_code = None try: return_code = process.wait(10) except Exception as e: mylog("CreateProc(),try to process.wait(),ERROR:%s" % str(e)) mylog("Maybe Child process Running already , but not quit") mylog("CreateProc return code=%s" % str(return_code))
def take_screenshot(): ret = False ScreenShot.init_globals() if ScreenShot.DISABLE_SSHOT: p("}}ybSkipping screen shot - disabled by .disable_sshot file}}xx", log_level=2) return # Find the logged in user and run the sshot.exe app cmd = os.path.join(util.BINARIES_FOLDER, "sshot\\sshot.exe") p("}}gnTrying to run " + cmd + "}}xx", log_level=4) user_token = UserAccounts.get_active_user_token() if user_token is None: p("}}ynUnable to get user token - screen locked?}}xx", log_level=2) return ret sidObj, intVal = win32security.GetTokenInformation( user_token, win32security.TokenUser) #source = win32security.GetTokenInformation(tokenh, TokenSource) if sidObj: accountName, domainName, accountTypeInt = \ win32security.LookupAccountSid(".", sidObj) else: p("}}rnUnable to get User Token! }}xx", log_level=1) return None #p("}}gnFound User Token: " + str(user_token) + "}}xx", log_level=5) # If user is in the administrators group, skip taking the sshot if UserAccounts.is_in_admin_group(accountName): p("}}mbUser (" + accountName + ") is in admin group, skipping screen shot...}}xx") return True p("}}gnRunning As: " + accountName + "}}xx", log_level=2) # Put this token in the logged in session #win32security.SetTokenInformation(user_token_copy, win32security.TokenSessionId, session_id) # Use win create process function si = win32process.STARTUPINFO() si.dwFlags = win32process.STARTF_USESHOWWINDOW si.wShowWindow = win32con.SW_NORMAL # si.lpDesktop = "WinSta0\Default" si.lpDesktop = "WinSta0\\Default" # Setup envinroment for the user environment = win32profile.CreateEnvironmentBlock(user_token, False) try: ( hProcess, hThread, dwProcessId, dwThreadId ) = win32process.CreateProcessAsUser( user_token, None, # AppName (really command line, blank if cmd line supplied) "\"" + cmd + "\"", # Command Line (blank if app supplied) None, # Process Attributes None, # Thread Attributes 0, # Inherits Handles win32con. NORMAL_PRIORITY_CLASS, # or win32con.CREATE_NEW_CONSOLE, environment, # Environment os.path.dirname(cmd), # Curr directory si) # Startup info p("Process Started: " + str(dwProcessId), log_level=5) p(hProcess, log_level=5) ret = True except Exception as e: p("}}rnError launching process:}}xx\n" + str(e), log_level=1) # Cleanup user_token.close() # else: # # Not logged in as system user, run as current user # try: # timeout = 10 # 10 seconds? # # Log an error if the process doesn't return 0 # # stdout=PIPE and stderr=STDOUT instead of capture_output=True # p("}}gnRunning as current user " + user_name + "}}xx") # proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,timeout=timeout, check=False) # if (proc.returncode == 0): # p("Command Results: " + cmd + "\n" + proc.stdout.decode()) # ret = True # else: # p("*** Command Failed!: " + cmd + "(" + str(proc.returncode) + ") \n" + proc.stdout.decode()) # except Exception as ex: # p("*** Command Exception! " + cmd + " \n" + \ # str(ex)) if ret is True: p("}}gnSnapped.}}xx", log_level=3) return ret
def runas(cmdLine, username, password=None, cwd=None): ''' Run a command as another user. If the process is running as an admin or system account this method does not require a password. Other non privileged accounts need to provide a password for the user to runas. Commands are run in with the highest level privileges possible for the account provided. ''' # Validate the domain and sid exist for the username username, domain = split_username(username) try: _, domain, _ = win32security.LookupAccountName(domain, username) except pywintypes.error as exc: message = win32api.FormatMessage(exc.winerror).rstrip('\n') raise CommandExecutionError(message) # Elevate the token from the current process access = ( win32security.TOKEN_QUERY | win32security.TOKEN_ADJUST_PRIVILEGES ) th = win32security.OpenProcessToken(win32api.GetCurrentProcess(), access) hubblestack.platform.win.elevate_token(th) # Try to impersonate the SYSTEM user. This process needs to be running as a # user who as been granted the SeImpersonatePrivilege, Administrator # accounts have this permission by default. try: impersonation_token = hubblestack.platform.win.impersonate_sid( hubblestack.platform.win.SYSTEM_SID, session_id=0, privs=['SeTcbPrivilege'], ) except WindowsError: # pylint: disable=undefined-variable log.debug("Unable to impersonate SYSTEM user") impersonation_token = None win32api.CloseHandle(th) # Impersonation of the SYSTEM user failed. Fallback to an un-privileged # runas. if not impersonation_token: log.debug("No impersonation token, using unprivileged runas") return runas_unpriv(cmdLine, username, password, cwd) if domain == 'NT AUTHORITY': # Logon as a system level account, SYSTEM, LOCAL SERVICE, or NETWORK # SERVICE. user_token = win32security.LogonUser( username, domain, '', win32con.LOGON32_LOGON_SERVICE, win32con.LOGON32_PROVIDER_DEFAULT, ) elif password: # Login with a password. user_token = win32security.LogonUser( username, domain, password, win32con.LOGON32_LOGON_INTERACTIVE, win32con.LOGON32_PROVIDER_DEFAULT, ) else: # Login without a password. This always returns an elevated token. user_token = hubblestack.platform.win.logon_msv1_s4u(username).Token # Get a linked user token to elevate if needed elevation_type = win32security.GetTokenInformation( user_token, win32security.TokenElevationType ) if elevation_type > 1: user_token = win32security.GetTokenInformation( user_token, win32security.TokenLinkedToken ) # Elevate the user token hubblestack.platform.win.elevate_token(user_token) # Make sure the user's token has access to a windows station and desktop hubblestack.platform.win.grant_winsta_and_desktop(user_token) # Create pipes for standard in, out and error streams security_attributes = win32security.SECURITY_ATTRIBUTES() security_attributes.bInheritHandle = 1 stdin_read, stdin_write = win32pipe.CreatePipe(security_attributes, 0) stdin_read = hubblestack.platform.win.make_inheritable(stdin_read) stdout_read, stdout_write = win32pipe.CreatePipe(security_attributes, 0) stdout_write = hubblestack.platform.win.make_inheritable(stdout_write) stderr_read, stderr_write = win32pipe.CreatePipe(security_attributes, 0) stderr_write = hubblestack.platform.win.make_inheritable(stderr_write) # Run the process without showing a window. creationflags = ( win32process.CREATE_NO_WINDOW | win32process.CREATE_NEW_CONSOLE | win32process.CREATE_SUSPENDED ) startup_info = hubblestack.platform.win.STARTUPINFO( dwFlags=win32con.STARTF_USESTDHANDLES, hStdInput=stdin_read.handle, hStdOutput=stdout_write.handle, hStdError=stderr_write.handle, ) # Create the environment for the user env = win32profile.CreateEnvironmentBlock(user_token, False) hProcess = None try: # Start the process in a suspended state. process_info = hubblestack.platform.win.CreateProcessWithTokenW( int(user_token), logonflags=1, applicationname=None, commandline=cmdLine, currentdirectory=cwd, creationflags=creationflags, startupinfo=startup_info, environment=env, ) hProcess = process_info.hProcess hThread = process_info.hThread dwProcessId = process_info.dwProcessId dwThreadId = process_info.dwThreadId # We don't use these so let's close the handle hubblestack.platform.win.kernel32.CloseHandle(stdin_write.handle) hubblestack.platform.win.kernel32.CloseHandle(stdout_write.handle) hubblestack.platform.win.kernel32.CloseHandle(stderr_write.handle) ret = {'pid': dwProcessId} # Resume the process psutil.Process(dwProcessId).resume() # Wait for the process to exit and get it's return code. if win32event.WaitForSingleObject(hProcess, win32event.INFINITE) == win32con.WAIT_OBJECT_0: exitcode = win32process.GetExitCodeProcess(hProcess) ret['retcode'] = exitcode # Read standard out fd_out = msvcrt.open_osfhandle(stdout_read.handle, os.O_RDONLY | os.O_TEXT) with os.fdopen(fd_out, 'r') as f_out: stdout = f_out.read() ret['stdout'] = stdout # Read standard error fd_err = msvcrt.open_osfhandle(stderr_read.handle, os.O_RDONLY | os.O_TEXT) with os.fdopen(fd_err, 'r') as f_err: stderr = f_err.read() ret['stderr'] = stderr finally: if hProcess is not None: hubblestack.platform.win.kernel32.CloseHandle(hProcess) win32api.CloseHandle(th) win32api.CloseHandle(user_token) if impersonation_token: win32security.RevertToSelf() win32api.CloseHandle(impersonation_token) return ret
def runas_system(cmd, username, password): # This only works as system, when salt is running as a service for example # Check for a domain domain = '.' if '@' in username: username, domain = username.split('@') if '\\' in username: domain, username = username.split('\\') # Get User Token token = win32security.LogonUser(username, domain, password, win32con.LOGON32_LOGON_INTERACTIVE, win32con.LOGON32_PROVIDER_DEFAULT) # Get Security Attributes security_attributes = win32security.SECURITY_ATTRIBUTES() security_attributes.bInheritHandle = 1 # Create a pipe to set as stdout in the child. The write handle needs to be # inheritable. stdin_read, stdin_write = win32pipe.CreatePipe(security_attributes, 0) stdin_read = make_inheritable(stdin_read) stdout_read, stdout_write = win32pipe.CreatePipe(security_attributes, 0) stdout_write = make_inheritable(stdout_write) stderr_read, stderr_write = win32pipe.CreatePipe(security_attributes, 0) stderr_write = make_inheritable(stderr_write) # Get startup info structure startup_info = win32process.STARTUPINFO() startup_info.dwFlags = win32con.STARTF_USESTDHANDLES startup_info.hStdInput = stdin_read startup_info.hStdOutput = stdout_write startup_info.hStdError = stderr_write # Get User Environment user_environment = win32profile.CreateEnvironmentBlock(token, False) # Build command cmd = 'cmd /c {0}'.format(cmd) # Run command and return process info structure procArgs = (None, cmd, security_attributes, security_attributes, 1, 0, user_environment, None, startup_info) hProcess, hThread, PId, TId = win32process.CreateProcessAsUser( token, *procArgs) if stdin_read is not None: stdin_read.Close() if stdout_write is not None: stdout_write.Close() if stderr_write is not None: stderr_write.Close() hThread.Close() # Initialize ret and set first element ret = {'pid': PId} # Get Standard Out fd_out = msvcrt.open_osfhandle(stdout_read, os.O_RDONLY | os.O_TEXT) with os.fdopen(fd_out, 'r') as f_out: ret['stdout'] = f_out.read() # Get Standard Error fd_err = msvcrt.open_osfhandle(stderr_read, os.O_RDONLY | os.O_TEXT) with os.fdopen(fd_err, 'r') as f_err: ret['stderr'] = f_err.read() # Get Return Code if win32event.WaitForSingleObject( hProcess, win32event.INFINITE) == win32con.WAIT_OBJECT_0: exitcode = win32process.GetExitCodeProcess(hProcess) ret['retcode'] = exitcode # Close handle to process win32api.CloseHandle(hProcess) return ret
def onRunCommand(self, nodeId, avatar, command, args, cwd, envMap): def merge(d1, d2): ''' Merges the two dictionaries into one so that d1 contains all the keys of d2. If d1 already contains a key in d2, d1 retains its key/value pair. ''' for k in d2.keys(): if not d1.has_key(k): d1[k] = d2[k] self.mLogger.debug("LaunchService.onRunCommand(%s, %s, %s, %s)" % \ (command, str(args), cwd, envMap)) try: if self.mProcess is not None: running, exit_code = self.isProcessRunning() if running: self.mLogger.warning("Command already running.") return False else: self.mProcess = None env = maestro.core.Environment() env.mEventManager.emit("*", "launch.report_is_running", False, exit_code) #self.mLogger.debug("Original env: " + str(envMap)) # Ensure that common environment variables that may be referenced in # command or the current working directory are set according to the # user execution environment rather than the daemon execution # environment. # TODO: What about Windows? if not sys.platform.startswith('win'): user_name = avatar.mUserName # Do not overwrite settings that were provided as part of the # command execution request. if not envMap.has_key('HOME'): envMap['HOME'] = pwd.getpwnam(user_name)[5] if not envMap.has_key('USER'): envMap['USER'] = user_name if not envMap.has_key('LOG_NAME'): envMap['LOG_NAME'] = user_name # Retrieve the user's environment. # TODO: Need to find a way to do this on other platforms. if sys.platform.startswith('win'): user_env = win32profile.CreateEnvironmentBlock( avatar.mUserHandle, False) else: # XXX: This might not give us what we think it does because on UNIX # os.environ is bound when the service starts. This will happen # before many things get set up in the environment, $HOSTNAME # for example is not defined yet. On Windows it should give # us the System Environment. user_env = os.environ # Merge our environment with the local environment. merge(envMap, user_env) # No need to do this since we are merging the entire os.environ. if sys.platform.startswith("win"): # XXX: For some reason SYSTEMROOT is not getting into user env. envMap["SYSTEMROOT"] = os.environ["SYSTEMROOT"] else: # XXX: This could be better. if user_env.has_key('DISPLAY'): envMap['DISPLAY'] = user_env['DISPLAY'] if user_env.has_key('USER_XAUTHORITY'): envMap['XAUTHORITY'] = user_env['USER_XAUTHORITY'] # Expand all environment variables. # XXX: Do we really need to do this in all cases? The operating system # should be able to do this for us. Except we are not using cross # platform envvar syntax. self.evaluateEnvVars(envMap, user_env) command = self.expandEnv(command, envMap, user_env)[0] if args is not None: for i in xrange(len(args)): args[i] = self.expandEnv(args[i], envMap, user_env)[0] match_obj = self.cmd_space_re.search(command) # If command contains spaces, ensure that it is wrapped in double # quotes. # NOTE: For Windows, what will happen is that the command will be # run as ""command" <args>". This is valid behavior because the # command gets executed within a command shell where that quoting # indicates a special interpretation. Specifically, it applies to # this part of the output from running 'cmd /?': # # If /C or /K is specified, then the remainder of the command line # after the switch is processed as a command line, where the # following logic is used to process quote (") characters: # # 1. [...] # # 2. Otherwise, old behavior is to see if the first character # is a quote character and if so, strip the leading # character and remove the last quote character on the # command line, preserving any text after the last quote # character. # # This behavior is why we are using double quotes rather than single # quotes for wrapping command. For non-Windows platforms, using # double quotes allows shell variable interpolation when the command # gets executed (since it is run within a /bin/sh process). if match_obj is not None: match_obj = self.single_quote_cmd_re.search(command) # If command is enclosed in single quotes, change them to double # quotes. if match_obj: command = '"%s"' % match_obj.group(1) else: match_obj = self.double_quote_cmd_re.search(command) # If command is not enclosed in single quotes or double quotes, # wrap it in double quotes. if match_obj is None: command = '"%s"' % command if cwd is not None: cwd = self.expandEnv(cwd, envMap, user_env)[0] #command = command.replace('\\', '\\\\') self.mLogger.info("Running command: " + command) self.mLogger.debug("Working Dir: " + str(cwd)) self.mLogger.debug("Translated env: " + str(envMap)) # Construct the actual command that will be executed. At this point, # all quoting on command and the individual arguments has to be # correct. if args is not None and len(args) > 0: command = '%s %s' % (command, ' '.join(args)) self.mProcess = process.ProcessOpen(cmd=command, cwd=cwd, env=envMap, avatar=avatar) self.mStdoutThread = OutputThread(self, self.mProcess.stdout) #self.mStderrThread = OutputThread(self, self.mProcess.stderr) self.mLogger.debug("BEFORE THREAD START") sys.stdout.flush() self.mStdoutThread.start() #self.mStderrThread.start() self.mLogger.debug("AFTER THREAD START") sys.stdout.flush() return True except KeyError, ex: #traceback.print_stack() self.mLogger.error("runCommand() failed with KeyError: " + str(ex)) return False