Hello All,
I want that my windows service from session 0 will create active session and run python application as different user.
At first I started to developed part related with creating process.
I use modules win32*, python 3.
Possible solutions:
A) Use LogonUser() + CreateProcessAsUser();
B) Use CreateProcessWithLogonW();
Solution A (LogonUser() + CreateProcessAsUser()):
import os
import msvcrt
import win32security
import win32con
import win32pipe
import win32process
import win32api
import win32net
import win32file
import win32event
import win32profile
import win32service
GENERIC_ACCESS = win32con.GENERIC_READ | win32con.GENERIC_WRITE | win32con.GENERIC_EXECUTE | win32con.GENERIC_ALL
WINSTA_ALL = (win32con.WINSTA_ACCESSCLIPBOARD | win32con.WINSTA_ACCESSGLOBALATOMS | \
win32con.WINSTA_CREATEDESKTOP | win32con.WINSTA_ENUMDESKTOPS | \
win32con.WINSTA_ENUMERATE | win32con.WINSTA_EXITWINDOWS | \
win32con.WINSTA_READATTRIBUTES | win32con.WINSTA_READSCREEN | \
win32con.WINSTA_WRITEATTRIBUTES | win32con.DELETE | \
win32con.READ_CONTROL | win32con.WRITE_DAC | \
win32con.WRITE_OWNER)
DESKTOP_ALL = (win32con.DESKTOP_CREATEMENU | win32con.DESKTOP_CREATEWINDOW | \
win32con.DESKTOP_ENUMERATE | win32con.DESKTOP_HOOKCONTROL | \
win32con.DESKTOP_JOURNALPLAYBACK | win32con.DESKTOP_JOURNALRECORD | \
win32con.DESKTOP_READOBJECTS | win32con.DESKTOP_SWITCHDESKTOP | \
win32con.DESKTOP_WRITEOBJECTS | win32con.DELETE | \
win32con.READ_CONTROL | win32con.WRITE_DAC | \
win32con.WRITE_OWNER)
def runAsDomainUser(domainName, userName, password, cmdLine, maxWait):
# maxWait = Maximum execution time in ms
policy_handle = win32security.LsaOpenPolicy(None, win32security.POLICY_ALL_ACCESS)
userGroupSid = win32security.LookupAccountName(domainName, userName)[0]
# Login as domain user and create new session
userToken = win32security.LogonUser(userName, domainName, password,
win32con.LOGON32_LOGON_INTERACTIVE,
win32con.LOGON32_PROVIDER_DEFAULT)
rc = win32api.GetLastError()
if userToken is None or (rc != 0):
return -1, "", "LogonUser failed with RC=%d!" % rc
profileDir = win32profile.GetUserProfileDirectory(userToken)
tokenUser = win32security.GetTokenInformation(userToken, win32security.TokenUser)
# Set access rights to window station
hWinSta = win32service.OpenWindowStation("winsta0", False, win32con.READ_CONTROL | win32con.WRITE_DAC )
# Get security descriptor by winsta0-handle
secDescWinSta = win32security.GetUserObjectSecurity(hWinSta, win32security.OWNER_SECURITY_INFORMATION
| win32security.DACL_SECURITY_INFORMATION
| win32con.GROUP_SECURITY_INFORMATION)
# Get DACL from security descriptor
daclWinSta = secDescWinSta.GetSecurityDescriptorDacl()
if daclWinSta is None:
# Create DACL if not exisiting
daclWinSta = win32security.ACL()
# Add ACEs to DACL for specific user group
daclWinSta.AddAccessAllowedAce(win32security.ACL_REVISION_DS, GENERIC_ACCESS, userGroupSid)
daclWinSta.AddAccessAllowedAce(win32security.ACL_REVISION_DS, WINSTA_ALL, userGroupSid)
# Set modified DACL for winsta0
win32security.SetSecurityInfo(hWinSta, win32security.SE_WINDOW_OBJECT, win32security.DACL_SECURITY_INFORMATION,
None, None, daclWinSta, None)
# Set access rights to desktop
hDesktop = win32service.OpenDesktop("default", 0, False, win32con.READ_CONTROL
| win32con.WRITE_DAC
| win32con.DESKTOP_WRITEOBJECTS
| win32con.DESKTOP_READOBJECTS)
# Get security descriptor by desktop-handle
secDescDesktop = win32security.GetUserObjectSecurity(hDesktop, win32security.OWNER_SECURITY_INFORMATION
| win32security.DACL_SECURITY_INFORMATION
| win32con.GROUP_SECURITY_INFORMATION )
# Get DACL from security descriptor
daclDesktop = secDescDesktop.GetSecurityDescriptorDacl()
if daclDesktop is None:
#create DACL if not exisiting
daclDesktop = win32security.ACL()
# Add ACEs to DACL for specific user group
daclDesktop.AddAccessAllowedAce(win32security.ACL_REVISION_DS, GENERIC_ACCESS, userGroupSid)
daclDesktop.AddAccessAllowedAce(win32security.ACL_REVISION_DS, DESKTOP_ALL, userGroupSid)
# Set modified DACL for desktop
win32security.SetSecurityInfo(hDesktop, win32security.SE_WINDOW_OBJECT, win32security.DACL_SECURITY_INFORMATION,
None, None, daclDesktop, None)
# Setup stdin, stdOut and stderr
secAttrs = win32security.SECURITY_ATTRIBUTES()
secAttrs.bInheritHandle = 1
stdOutRd, stdOutWr = win32pipe.CreatePipe(secAttrs, 0)
stdErrRd, stdErrWr = win32pipe.CreatePipe(secAttrs, 0)
ppid = win32api.GetCurrentProcess()
tmp = win32api.DuplicateHandle(ppid, stdOutRd, ppid, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
win32file.CloseHandle(stdOutRd)
stdOutRd = tmp
environment = win32profile.CreateEnvironmentBlock(userToken, False)
startupInfo = win32process.STARTUPINFO()
startupInfo.dwFlags = win32con.STARTF_USESTDHANDLES
startupInfo.hStdOutput = stdOutWr
startupInfo.hStdError = stdErrWr
hPrc = win32process.CreateProcessAsUser(
userToken,
None, # appName
cmdLine, # commandLine
None, # processAttributes
None, # threadAttributes
1, # bInheritHandles
win32process.CREATE_NEW_CONSOLE, # dwCreationFlags
environment, # newEnvironment
profileDir, # currentDirectory
startupInfo)[0]
win32file.CloseHandle(stdErrWr)
win32file.CloseHandle(stdOutWr)
win32security.RevertToSelf()
# Wait for process to complete
stdOutBuf = os.fdopen(msvcrt.open_osfhandle(stdOutRd, 0), "rb")
stdErrBuf = os.fdopen(msvcrt.open_osfhandle(stdErrRd, 0), "rb")
win32event.WaitForSingleObject(hPrc, maxWait)
stdOut = stdOutBuf.read()
stdErr = stdErrBuf.read()
rc = win32process.GetExitCodeProcess(hPrc)
return rc, str(stdOut, "utf-8"), str(stdErr, "utf-8")
if __name__ == "__main__":
cmdLine = "C:/Windows/System32/cmd.exe"
domainName = input("Domain: ")
userName = input("User: ")
password = input("Password: ")
print(runAsDomainUser(domainName, userName, password, cmdLine, 60000))
But I have error/problem with privileges:
Traceback (most recent call last):
File "", line 137, in <module>
print(runAsDomainUser(domainName, userName, password, cmdLine, 60000))
File "", line 37, in runAsDomainUser
userGroupSid = win32security.LookupAccountName(domainName, userName)[0]
pywintypes.error: (1722, 'LookupAccountName', 'The RPC server is unavailable.')
What privileges need this process?
How add them?
Solution B (CreateProcessLogonW()):
from ctypes import *
from ctypes.wintypes import *
import win32ts
INVALID_HANDLE_VALUE = -1
CREATE_UNICODE_ENVIRONMENT = 0x00000400
CData = Array.__base__
LPBYTE = POINTER(BYTE)
class PROCESS_INFORMATION(Structure):
'''http://msdn.microsoft.com/en-us/library/ms684873'''
_fields_ = [
('hProcess', HANDLE),
('hThread', HANDLE),
('dwProcessId', DWORD),
('dwThreadId', DWORD),
]
LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
class STARTUPINFOW(Structure):
'http://msdn.microsoft.com/en-us/library/ms686331'
_fields_ = [
('cb', DWORD),
('lpReserved', LPWSTR),
('lpDesktop', LPWSTR),
('lpTitle', LPWSTR),
('dwX', DWORD),
('dwY', DWORD),
('dwXSize', DWORD),
('dwYSize', DWORD),
('dwXCountChars', DWORD),
('dwYCountChars', DWORD),
('dwFillAttribute', DWORD),
('dwFlags', DWORD),
('wShowWindow', WORD),
('cbReserved2', WORD),
('lpReserved2', LPBYTE),
('hStdInput', HANDLE),
('hStdOutput', HANDLE),
('hStdError', HANDLE),
]
LPSTARTUPINFOW = POINTER(STARTUPINFOW)
# http://msdn.microsoft.com/en-us/library/ms682431
windll.advapi32.CreateProcessWithLogonW.restype = BOOL
windll.advapi32.CreateProcessWithLogonW.argtypes = [
LPCWSTR, # lpUsername
LPCWSTR, # lpDomain
LPCWSTR, # lpPassword
DWORD, # dwLogonFlags
LPCWSTR, # lpApplicationName
LPWSTR, # lpCommandLine (inout)
DWORD, # dwCreationFlags
LPCWSTR, # lpEnvironment (force Unicode)
LPCWSTR, # lpCurrentDirectory
LPSTARTUPINFOW, # lpStartupInfo
LPPROCESS_INFORMATION, # lpProcessInfo (out)
]
def CreateProcessWithLogonW(
lpUsername=None,
lpDomain=None,
lpPassword=None,
dwLogonFlags=0,
lpApplicationName=None,
lpCommandLine=None,
dwCreationFlags=0,
lpEnvironment=None,
lpCurrentDirectory=None,
startupInfo=None
):
if (lpCommandLine is not None and
not isinstance(lpCommandLine, CData)
):
lpCommandLine = create_unicode_buffer(lpCommandLine)
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT
if startupInfo is None:
startupInfo = STARTUPINFOW(sizeof(STARTUPINFOW))
processInformation = PROCESS_INFORMATION(
INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE)
success = windll.advapi32.CreateProcessWithLogonW(
lpUsername, lpDomain, lpPassword, dwLogonFlags, lpApplicationName,
lpCommandLine, dwCreationFlags, lpEnvironment, lpCurrentDirectory,
byref(startupInfo), byref(processInformation))
if not success:
raise WinError()
return processInformation
if __name__ == '__main__':
cmdLine = "C:\\Windows\\notepad.exe"
domainName = input("Domain: ")
userName = input("User: ")
password = input("Password: ")
pi = CreateProcessWithLogonW(
userName, domainName, password, 1, None,
cmdLine)
print(pi.dwProcessId)
Not so good solution, because this process start in the same session.
I would really appreciate any help.