最终我找到了如何做到这一点。这是相当复杂的,我不得不从几个示例中合并代码(其中一些是用C写的)。下面的示例适用于以Network Service或System用户身份执行时。无论是在用户会话还是会话0中执行都没有关系。
以下是代码:
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):
userGroupSid = win32security.LookupAccountName(domainName, userName)[0]
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)
hWinSta = win32service.OpenWindowStation("winsta0", False, win32con.READ_CONTROL | win32con.WRITE_DAC )
secDescWinSta = win32security.GetUserObjectSecurity(hWinSta, win32security.OWNER_SECURITY_INFORMATION
| win32security.DACL_SECURITY_INFORMATION
| win32con.GROUP_SECURITY_INFORMATION)
daclWinSta = secDescWinSta.GetSecurityDescriptorDacl()
if daclWinSta is None:
daclWinSta = win32security.ACL()
daclWinSta.AddAccessAllowedAce(win32security.ACL_REVISION_DS, GENERIC_ACCESS, userGroupSid)
daclWinSta.AddAccessAllowedAce(win32security.ACL_REVISION_DS, WINSTA_ALL, userGroupSid)
win32security.SetSecurityInfo(hWinSta, win32security.SE_WINDOW_OBJECT, win32security.DACL_SECURITY_INFORMATION,
None, None, daclWinSta, None)
hDesktop = win32service.OpenDesktop("default", 0, False, win32con.READ_CONTROL
| win32con.WRITE_DAC
| win32con.DESKTOP_WRITEOBJECTS
| win32con.DESKTOP_READOBJECTS)
secDescDesktop = win32security.GetUserObjectSecurity(hDesktop, win32security.OWNER_SECURITY_INFORMATION
| win32security.DACL_SECURITY_INFORMATION
| win32con.GROUP_SECURITY_INFORMATION )
daclDesktop = secDescDesktop.GetSecurityDescriptorDacl()
if daclDesktop is None:
daclDesktop = win32security.ACL()
daclDesktop.AddAccessAllowedAce(win32security.ACL_REVISION_DS, GENERIC_ACCESS, userGroupSid)
daclDesktop.AddAccessAllowedAce(win32security.ACL_REVISION_DS, DESKTOP_ALL, userGroupSid)
win32security.SetSecurityInfo(hDesktop, win32security.SE_WINDOW_OBJECT, win32security.DACL_SECURITY_INFORMATION,
None, None, daclDesktop, None)
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,
cmdLine,
None,
None,
1,
win32process.CREATE_NEW_CONSOLE,
environment,
profileDir,
startupInfo)[0]
win32file.CloseHandle(stdErrWr)
win32file.CloseHandle(stdOutWr)
win32security.RevertToSelf()
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))
GetUserName
(由os.getlogin
调用)用于从关联的登录会话中查询用户名。getpass.getuser
仅从进程环境中获取USERNAME
环境变量。模拟对此没有影响。获取用户的环境变量需要ExpandEnvironmentStringsForUser
。 - Eryk SunCreateProcessAsUser
。但是,使用CreateProcessWithLogonW
会更容易,它通过将请求发送到Secondary Logon服务来实现。在这种情况下,CREATE_NO_WINDOW
将被忽略,因为Secondary Logon服务使用标志CREATE_NEW_CONSOLE
创建进程。 - Eryk Sun