2016-07-08 25 views
12

サービスをローカルシステムアカウントとしてログインしているWindowsサービスで、ドメインユーザーを偽装しようとしています。Windowsサービスの偽装ユーザー

これまでのところ、サービスをログに記録し、次のようなユーザーの資格情報を使用してプロセスを設定するだけで、これを動作させることができました。

 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); 

私の目標は、ドメインがパスワードをリセットを取得アカウントので、ドメインユーザーではなく、ローカルシステムとしてサービスのログを持っていないことです。

私は、ローカルシステムを使用する場合は、私が取得アクセスはこれを実現する方法をどのように

任意のアイデアを拒否されましたか?

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

私はLogonSessionType.NewCredentialsになりすましログインを変更し、削除するとき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

からログファイルを生成しません。コピー機能と移動機能が動作しています。しかし、サブプロセスを作成することはできません。 Hary Johnstonが提案しているように、私はCreateProcessAsUserで遊んでいました。

+0

サービスがローカルシステムとして実行されており、サービスがドメインユーザーのアカウントを使用して別のプロセスを開始しているとしますか? – wablab

+0

もしそうなら、この質問はおそらくhttp://stackoverflow.com/questions/559719/windows-impersonation-from-c-sharpの複製である – wablab

+0

「アクセスが拒否されました」というエラーを引き起こすコード行はありますか? –

答えて

7

私はそれを動作させることができました。通常なりすまして

、私はそれを実行するには、次のコード

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をでアクセス許可をコピーすることがしたいので、ローカルポリシーにいくつかの変更をしなければなりませんでした。

すべてのコメントとご協力ありがとうございます。

+0

あなたはWindows 10にいますか?私はそれを使用し、あなたのコードでAccess deniedを受け取り続けます。 – freedeveloper

+0

私はWindowsを使用していません10.あなたが使用しているコマンドのタイプ。そしてあなたはあなたが偽装しているそのユーザーとWindows 10マシンでそのコマンドを実行しようとしましたか? – H20rider

-4

これは起こりません。

Windowsは* nixではありません。 sudoはありません。ユーザーのログオン資格情報を持たずに、単にユーザーを偽装することはできません。また、たとえそれを管理しても、Microsoftのアップデートプロセスを経てすぐにパッチが適用される脆弱性が明らかになりました。

何がになるのですか?正しい特権と有効期限がないドメインアカウントを作成し、サービスのログインに使用します。

+0

OPには問題のユーザーアカウントの資格情報があるので、この質問には関係ありません。 –

+0

オペラには何らかの理由でそれらを使用したいが、使用したくない。 –

+0

あなたは疑問を誤解しています。 OPは、資格情報が変更されたときに自動的にサービスを再構成する方法がないため、これらの資格情報で*サービス*を実行するように設定したくない場合があります。彼はLogonUserに資格情報を渡すことに反対していません。実際、それはまさに彼の自己回答がするものです。 –

関連する問題