在Windows服务中模拟用户

我正在尝试模拟一个Windows服务中的域用户,服务以本地系统帐户login。

到目前为止,我只能通过logging服务并使用用户凭证来设置进程来实现这个function,如下所示。

ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = CommandDetails.Command; startInfo.WorkingDirectory = Settings.RoboCopyWorkingDirectory; startInfo.Arguments = commandLine; startInfo.UseShellExecute = false; startInfo.CreateNoWindow = true; startInfo.RedirectStandardError = true; startInfo.RedirectStandardOutput = true; // Credentials startInfo.Domain = ImperDomain; startInfo.UserName = ImperUsername; startInfo.Password = ImperPasswordSecure; process = Process.Start(startInfo); 

我的目标是没有服务login域用户,而是作为本地系统,因为域帐户密码得到重置。

当我使用本地系统时,我得到的访问被拒绝

任何想法如何做到这一点?

StackTace

 Access is denied at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo) at System.Diagnostics.Process.Start() at System.Diagnostics.Process.Start(ProcessStartInfo startInfo) at Ace.WindowsService.ProcessCmd.ProcessCommand.StartProcess(ProcessStartInfo startInfo) in 

我曾尝试在下面列出的模拟代码中包装代码,但没有成功。

模拟代码

 public class Impersonation2 : IDisposable { private WindowsImpersonationContext _impersonatedUserContext; // Declare signatures for Win32 LogonUser and CloseHandle APIs [DllImport("advapi32.dll", SetLastError = true)] static extern bool LogonUser( string principal, string authority, string password, LogonSessionType logonType, LogonProvider logonProvider, out IntPtr token); [DllImport("kernel32.dll", SetLastError = true)] static extern bool CloseHandle(IntPtr handle); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern bool RevertToSelf(); // ReSharper disable UnusedMember.Local enum LogonSessionType : uint { Interactive = 2, Network, Batch, Service, NetworkCleartext = 8, NewCredentials } // ReSharper disable InconsistentNaming enum LogonProvider : uint { Default = 0, // default for platform (use this!) WinNT35, // sends smoke signals to authority WinNT40, // uses NTLM WinNT50 // negotiates Kerb or NTLM } // ReSharper restore InconsistentNaming // ReSharper restore UnusedMember.Local /// <summary> /// Class to allow running a segment of code under a given user login context /// </summary> /// <param name="user">domain\user</param> /// <param name="password">user's domain password</param> public Impersonation2(string domain, string username, string password) { var token = ValidateParametersAndGetFirstLoginToken(username, domain, password); var duplicateToken = IntPtr.Zero; try { if (DuplicateToken(token, 2, ref duplicateToken) == 0) { throw new Exception("DuplicateToken call to reset permissions for this token failed"); } var identityForLoggedOnUser = new WindowsIdentity(duplicateToken); _impersonatedUserContext = identityForLoggedOnUser.Impersonate(); if (_impersonatedUserContext == null) { throw new Exception("WindowsIdentity.Impersonate() failed"); } } finally { if (token != IntPtr.Zero) CloseHandle(token); if (duplicateToken != IntPtr.Zero) CloseHandle(duplicateToken); } } private static IntPtr ValidateParametersAndGetFirstLoginToken(string domain, string username, string password) { if (!RevertToSelf()) { throw new Exception("RevertToSelf call to remove any prior impersonations failed"); ErrorLogger.LogEvent("RevertToSelf call to remove any prior impersonations failed", System.Diagnostics.EventLogEntryType.Error, ""); } IntPtr token; var result = LogonUser(domain, username, password, LogonSessionType.Interactive, LogonProvider.Default, out token); if (!result) { var errorCode = Marshal.GetLastWin32Error(); ErrorLogger.LogEvent(string.Format("Could not impersonate the elevated user. LogonUser: {2}\\{1} returned error code: {0}.", errorCode, username, domain), System.Diagnostics.EventLogEntryType.Error, ""); throw new Exception("Logon for user " + username + " failed."); } return token; } public void Dispose() { // Stop impersonation and revert to the process identity if (_impersonatedUserContext != null) { _impersonatedUserContext.Undo(); _impersonatedUserContext = null; } } 

更新

这工作正常,如果我只是在运行,如果我只是执行它。 但是,当它作为服务运行时,它将不起作用

更新2

当我将模拟login更改为LogonSessionType.NewCredentials并从stream程中删除信用时,我没有从Process.Start中获取拒绝的访问权限。 但是现在我运行robocopy命令时看到一个错误。 当我在进程上拥有凭据时,它不会从robocopy命令生成日志文件

错误

 2016/07/16 09:19:12 ERROR 5 (0x00000005) Accessing Source Directory \\[server]\[path]\ Access is denied. 

更改

 var result = LogonUser(domain, username, password, LogonSessionType.NewCredentials, LogonProvider.Default, out token); 

更新3

复制和移动function正在工作。 但是创build子stream程不是。 我一直在玩Hary Johnstonbuild议的CreateProcessAsUser。

我能够得到它的工作。

对于正常的模拟,我使用下面的代码

 public class Impersonation : IDisposable { private WindowsImpersonationContext _impersonatedUserContext; #region FUNCTIONS (P/INVOKE) // Declare signatures for Win32 LogonUser and CloseHandle APIs [DllImport("advapi32.dll", SetLastError = true)] static extern bool LogonUser( string principal, string authority, string password, LogonSessionType logonType, LogonProvider logonProvider, out IntPtr token); [DllImport("kernel32.dll", SetLastError = true)] static extern bool CloseHandle(IntPtr handle); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern bool RevertToSelf(); #endregion #region ENUMS enum LogonSessionType : uint { Interactive = 2, Network, Batch, Service, NetworkCleartext = 8, NewCredentials } enum LogonProvider : uint { Default = 0, // default for platform (use this!) WinNT35, // sends smoke signals to authority WinNT40, // uses NTLM WinNT50 // negotiates Kerb or NTLM } #endregion /// <summary> /// Class to allow running a segment of code under a given user login context /// </summary> /// <param name="user">domain\user</param> /// <param name="password">user's domain password</param> public Impersonation(string domain, string username, string password) { var token = ValidateParametersAndGetFirstLoginToken(username, domain, password); var duplicateToken = IntPtr.Zero; try { if (DuplicateToken(token, 2, ref duplicateToken) == 0) { throw new InvalidOperationException("DuplicateToken call to reset permissions for this token failed"); } var identityForLoggedOnUser = new WindowsIdentity(duplicateToken); _impersonatedUserContext = identityForLoggedOnUser.Impersonate(); if (_impersonatedUserContext == null) { throw new InvalidOperationException("WindowsIdentity.Impersonate() failed"); } } finally { if (token != IntPtr.Zero) CloseHandle(token); if (duplicateToken != IntPtr.Zero) CloseHandle(duplicateToken); } } private static IntPtr ValidateParametersAndGetFirstLoginToken(string domain, string username, string password) { if (!RevertToSelf()) { ErrorLogger.LogEvent("RevertToSelf call to remove any prior impersonations failed", System.Diagnostics.EventLogEntryType.Error, ""); throw new InvalidOperationException("RevertToSelf call to remove any prior impersonations failed"); } IntPtr token; var result = LogonUser(domain, username, password, LogonSessionType.NewCredentials, LogonProvider.Default, out token); if (!result) { var errorCode = Marshal.GetLastWin32Error(); ErrorLogger.LogEvent(string.Format("Could not impersonate the elevated user. LogonUser: {2}\\{1} returned error code: {0}.", errorCode, username, domain), System.Diagnostics.EventLogEntryType.Error, ""); throw new InvalidOperationException("Logon for user " + username + " failed."); } return token; } public void Dispose() { // Stop impersonation and revert to the process identity if (_impersonatedUserContext != null) { _impersonatedUserContext.Undo(); _impersonatedUserContext = null; } } } 

运行它,我做了以下几点:

  FileInfo fi = new FileInfo(logfile); using (var imp = new Impersonation(Settings.ImpersonateUser.AccountDomain, Settings.ImpersonateUser.AccountName, Settings.ImpersonateUser.AccountPassword)) { if (File.Exists(filename)) File.Delete(filename); fi.MoveTo(filename); } 

为了运行控制台命令,我使用了下面的代码。

 public class CreateProcess { #region Constants const UInt32 INFINITE = 0xFFFFFFFF; const UInt32 WAIT_FAILED = 0xFFFFFFFF; #endregion #region ENUMS [Flags] public enum LogonType { LOGON32_LOGON_INTERACTIVE = 2, LOGON32_LOGON_NETWORK = 3, LOGON32_LOGON_BATCH = 4, LOGON32_LOGON_SERVICE = 5, LOGON32_LOGON_UNLOCK = 7, LOGON32_LOGON_NETWORK_CLEARTEXT = 8, LOGON32_LOGON_NEW_CREDENTIALS = 9 } [Flags] public enum LogonProvider { LOGON32_PROVIDER_DEFAULT = 0, LOGON32_PROVIDER_WINNT35, LOGON32_PROVIDER_WINNT40, LOGON32_PROVIDER_WINNT50 } #endregion #region Structs [StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO { public Int32 cb; public String lpReserved; public String lpDesktop; public String lpTitle; public Int32 dwX; public Int32 dwY; public Int32 dwXSize; public Int32 dwYSize; public Int32 dwXCountChars; public Int32 dwYCountChars; public Int32 dwFillAttribute; public Int32 dwFlags; public Int16 wShowWindow; public Int16 cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public Int32 dwProcessId; public Int32 dwThreadId; } [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public int nLength; public unsafe byte* lpSecurityDescriptor; public int bInheritHandle; } public enum TOKEN_TYPE { TokenPrimary = 1, TokenImpersonation } public enum SECURITY_IMPERSONATION_LEVEL { SecurityAnonymous, SecurityIdentification, SecurityImpersonation, SecurityDelegation } #endregion #region FUNCTIONS (P/INVOKE) [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern bool RevertToSelf(); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern Boolean LogonUser ( String UserName, String Domain, String Password, LogonType dwLogonType, LogonProvider dwLogonProvider, out IntPtr phToken ); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern Boolean CreateProcessAsUser ( IntPtr hToken, String lpApplicationName, String lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, Boolean bInheritHandles, Int32 dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation ); [DllImport("kernel32.dll", SetLastError = true)] public static extern UInt32 WaitForSingleObject ( IntPtr hHandle, UInt32 dwMilliseconds ); [DllImport("kernel32", SetLastError = true)] public static extern Boolean CloseHandle(IntPtr handle); #endregion #region Functions public static int LaunchCommand(string command, string domain, string account, string password) { int ProcessId = -1; PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION(); STARTUPINFO startInfo = new STARTUPINFO(); Boolean bResult = false; UInt32 uiResultWait = WAIT_FAILED; var token = ValidateParametersAndGetFirstLoginToken(domain, account, password); var duplicateToken = IntPtr.Zero; try { startInfo.cb = Marshal.SizeOf(startInfo); // startInfo.lpDesktop = "winsta0\\default"; bResult = CreateProcessAsUser( token, null, command, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref startInfo, out processInfo ); if (!bResult) { throw new Exception("CreateProcessAsUser error #" + Marshal.GetLastWin32Error()); } // Wait for process to end uiResultWait = WaitForSingleObject(processInfo.hProcess, INFINITE); ProcessId = processInfo.dwProcessId; if (uiResultWait == WAIT_FAILED) { throw new Exception("WaitForSingleObject error #" + Marshal.GetLastWin32Error()); } } finally { if (token != IntPtr.Zero) CloseHandle(token); if (duplicateToken != IntPtr.Zero) CloseHandle(duplicateToken); CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); } return ProcessId; } private static IntPtr ValidateParametersAndGetFirstLoginToken(string domain, string username, string password) { if (!RevertToSelf()) { ErrorLogger.LogEvent("RevertToSelf call to remove any prior impersonations failed", System.Diagnostics.EventLogEntryType.Error, ""); throw new Exception("RevertToSelf call to remove any prior impersonations failed"); } IntPtr token; var result = LogonUser(username, domain, password, LogonType.LOGON32_LOGON_INTERACTIVE, LogonProvider.LOGON32_PROVIDER_DEFAULT, out token); if (!result) { var errorCode = Marshal.GetLastWin32Error(); ErrorLogger.LogEvent(string.Format("Could not impersonate the elevated user. LogonUser: {2}\\{1} returned error code: {0}.", errorCode, username, domain), System.Diagnostics.EventLogEntryType.Error, ""); throw new Exception("Logon for user " + username + " failed."); } return token; } #endregion } 

并执行以下操作

 string commandLine = "Robocopy " + args; ProcessId = CreateProcess.LaunchCommand(commandLine, ImperDomain, ImperUsername, ImperPassword); 

我还必须对本地策略进行一些更改,因为我想能够在robocopy中复制权限。

感谢所有的意见和帮助。

这不会发生。

Windows不是* nix。 没有sudo。 您不能简单地模拟用户而不具有用户的登录凭据。 而且,即使你确实管理了它,你也基本上已经发现了一个漏洞,一旦它通过微软的更新过程,就会被修补。

有效的方法是创建一个具有正确权限的域帐户,并且不会过期并使用服务登录的帐户。