2011-12-14 15 views
1

ローカルマシンのシステムアカウントで実行されるWindowsサービスがあります。このサービスの内部では、リモート共有フォルダで使用できるリモート.iniファイルを読み取ろうとします。このファイルを読み取ろうとしているコードは、LogonUserを使用して偽装されています(単純化されたコードは、以下のとおりです)。偽装は、構成されたユーザーを偽装するのに成功しますが、リモートネットワーク共有上にあるリモートのiniファイルを読み取ろうとすると、UnauthorizedAccessExceptionがスローされます。これは、構成されたユーザーがリモートマシンに対して読み取り/書き込みアクセス許可を持っている場合でも発生します。すべての偽装を削除するコードを変更し、Windowsサービスを構成済みのユーザーとして実行すると、リモートの.iniファイルへのすべてのアクセスが成功します。私は、ユーザーとしてサービスを実行するなどのハッキングではなく、このファイルへのアクセスを得るためになりすましを使用することをお勧めします。この例の偽装コードで誰かがエラーを見ることができますか?これを有効にするためにVista 64ビットボックスで何かする必要がありますか? IT同僚が有効にするために必要なアクティブなディレクトリのアクセス許可がありますか?Windowsサービスは、偽装中にリモート共有からファイルを読み取るとUnauthorizedAccessExceptionを取得します

private WindowsImpersonationContext _impersonatedUser; 
    private IntPtr _token; 

    // 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); 
    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 
    } 
    .... 

    var result = LogonUser(exchangeUserId, exchangeDomain, 
          password, 
          LogonSessionType.Network, 
          LogonProvider.Default, 
          out _token); 

    var id = new WindowsIdentity(_token); 
    _impersonatedUser = id.Impersonate(); 

    try 
    { 
     //Validate access to the file on the remote computer/share 
     File.GetAccessControl(remoteFileAvailableInSharedFolder); 
    } 
    catch (UnauthorizedAccessException unauthorized) 
    { 
     ... 
    } 
    .... 

    // Stop impersonation and revert to the process identity 
    if (_impersonatedUser != null) 
    { 
     _impersonatedUser.Undo(); 
     _impersonatedUser = null; 
    } 

    if (_token != IntPtr.Zero) 
    { 
     CloseHandle(_token); 
     _token = IntPtr.Zero; 
    } 
+0

ユーザーアカウントとして実行される場合、ファイルから別のアカウントを偽装することはできますか? – bryanmac

+0

実際にファイルにアクセスするためにユーザーアカウントを使用しようとしましたか? –

+0

別のLogonSessionTypeとLogonProviderを試してください.NewCredentialsとWinNT35を使用することをお勧めします。 – Thinhbk

答えて

1

さらなる調査を行う中で、偽装コードによって引き起こされる中心的な問題を発見しました。私は、APIのDuplicateTokenの使用を追加し、APIのRevertToSelfの使用法を追加しなければならなかった。これらの変更(下記のクラスを参照)を行うと、サービス全体がドメインユーザーの下で実行されたときのコードと同様に、偽装が機能しました。このコードが他の人にも同じように役立つことを願っています。

public class Impersonation : 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 Impersonation(string user, string password) 
    { 
     var token = ValidateParametersAndGetFirstLoginToken(user, 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 user, string password) 
    { 
     if (string.IsNullOrEmpty(user)) 
     { 
      throw new ConfigurationErrorsException("No user passed into impersonation class"); 
     } 
     var userHaves = user.Split('\\'); 
     if (userHaves.Length != 2) 
     { 
      throw new ConfigurationErrorsException("User must be formatted as follows: domain\\user"); 
     } 
     if (!RevertToSelf()) 
     { 
      throw new Exception("RevertToSelf call to remove any prior impersonations failed"); 
     } 

     IntPtr token; 

     var result = LogonUser(userHaves[1], userHaves[0], 
           password, 
           LogonSessionType.Interactive, 
           LogonProvider.Default, 
           out token); 
     if (!result) 
     { 
      throw new ConfigurationErrorsException("Logon for user " + user + " failed."); 
     } 
     return token; 
    } 

    public void Dispose() 
    { 
     // Stop impersonation and revert to the process identity 
     if (_impersonatedUserContext != null) 
     { 
      _impersonatedUserContext.Undo(); 
      _impersonatedUserContext = null; 
     } 
    } 
} 
関連する問題