Impersonating the current computer through Windows

2019-05-19 21:45发布

问题:

I am trying to get the WindowsIdentity for the computer account the current user is logged into.

Currently I am using the following code to get the group membership of the current user:

WindowsIdentity currentIdent = WindowsIdentity.GetCurrent();
foreach (IdentityReference indentity in currentGroups)
{
  String groupName = indentity.Translate(typeof(NTAccount)).ToString();
}

This works fine, but I also need to do the same for the current computer account preferably without querying AD.

I beleive that I will have to do this using Impersonation but have not been able to find out how.

回答1:

There are two places on the local computer that would have its domain account group membership: a user token for domain\computer$ and a Kerberos ticket for domain\computer$. Whenever the local computer needs its user token, then it will be set up as SYSTEM, not domain\computer$, so that's not an option. The only way to get a user token from a domain\computer$ Kerberos ticket is to be running as SYSTEM, since you need its key to decrypt the ticket (also, you would need the Act as Part of the Operating System privilege, and even then I don't know how to create the token from the ticket).

So, you have to query AD:

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using System.Security.Principal;
using System.ComponentModel;
using System.DirectoryServices;

public static SecurityIdentifier[] GetLocalComputerGroups()
{
    string sAMAccountName = PInvoke.GetSYSTEMsAMAccountName();
    DirectorySearcher searcher = new DirectorySearcher("(sAMAccountName=" + sAMAccountName + ")");
    DirectoryEntry entry = searcher.FindOne().GetDirectoryEntry();
    entry.RefreshCache(new string[] { "tokenGroups" });
    List<SecurityIdentifier> groupSids = new List<SecurityIdentifier>();
    foreach(byte[] byteSid in entry.Properties["tokenGroups"])
    {
        groupSids.Add(new SecurityIdentifier(byteSid, 0));
    }
    return groupSids.ToArray();
}

public class PInvoke
{
    public const int STATUS_SUCCESS = 0;
    public static readonly IntPtr NULL = IntPtr.Zero;

    public enum SECURITY_LOGON_TYPE
    {
        UndefinedLogonType = 0,
        Interactive = 2,
        Network,
        Batch,
        Service,
        Proxy,
        Unlock,
        NetworkCleartext,
        NewCredentials,
        RemoteInteractive,
        CachedInteractive,
        CachedRemoteInteractive,
        CachedUnlock
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LARGE_INTEGER
    {
        public uint LowPart;
        public int HighPart;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LUID
    {
        public uint LowPart;
        public int HighPart;

        public static LUID GetSYSTEMLuid()
        {
            return new LUID() { LowPart = 0x3E7, HighPart = 0 };
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LSA_UNICODE_STRING
    {
        public ushort Length;
        public ushort MaximumLength;
        public IntPtr Buffer;

        public override string ToString()
        {
            if (Buffer == NULL) return null;
            return Marshal.PtrToStringUni(Buffer, Length / UnicodeEncoding.CharSize);
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_LOGON_SESSION_DATA
    {
        public uint Size;
        public LUID LogonId;
        public LSA_UNICODE_STRING UserName;
        public LSA_UNICODE_STRING LogonDomain;
        public LSA_UNICODE_STRING AuthenticationPackage;
        public SECURITY_LOGON_TYPE LogonType;
        public uint Session;
        public IntPtr Sid;
        public LARGE_INTEGER LogonTime;
        public LSA_UNICODE_STRING LogonServer;
        public LSA_UNICODE_STRING DnsDomainName;
        public LSA_UNICODE_STRING Upn;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_LOGON_SESSION_Managed
    {
        public LUID LogonId;
        public string UserName;
        public string LogonDomain;
        public string AuthenticationPackage;
        public SECURITY_LOGON_TYPE LogonType;
        public uint Session;
        public SecurityIdentifier Sid;
        public LARGE_INTEGER LogonTime;
        public string LogonServer;
        public string DnsDomainName;
        public string Upn;

        public SECURITY_LOGON_SESSION_DATA_Managed(IntPtr pSecurityLogonSessionData)
        {
            SECURITY_LOGON_SESSION_DATA data = (SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(pSecurityLogonSessionData, typeof(SECURITY_LOGON_SESSION_DATA));
            this.LogonId = data.LogonId;
            this.UserName = data.UserName.ToString();
            this.LogonDomain = data.LogonDomain.ToString();
            this.AuthenticationPackage = data.AuthenticationPackage.ToString();
            this.LogonType = data.LogonType;
            this.Session = data.Session;
            this.Sid = new SecurityIdentifier(ConvertPSIDToString(data.Sid));
            this.LogonTime = data.LogonTime;
            this.LogonServer = data.LogonServer.ToString();
            this.DnsDomainName = data.DnsDomainName.ToString();
            this.Upn = data.Upn.ToString();
        }
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr LocalFree(IntPtr hMem);

    [DllImport("advapi32.dll", SetLastError = true)]
    protected static extern bool ConvertSidToStringSidW(IntPtr Sid, out IntPtr StringSid);

    public static string ConvertPSIDToString(IntPtr pSid)
    {
        IntPtr pString;
        if (ConvertSidToStringSidW(pSid, out pString))
        {
            try
            {
                return Marshal.PtrToStringUni(pString);
            }
            finally
            {
                LocalFree(pString);
            }
        }
        else
        {
            throw new Win32Exception();
        }
    }

    [DllImport("advapi32.dll")]
    protected static extern int LsaNtStatusToWinError(uint Status);

    public static Win32Exception NtStatusToWinException(uint ntstatus)
    {
        return new Win32Exception(LsaNtStatusToWinError(ntstatus);
    }

    [DllImport("secur32.dll")]
    public static extern uint LsaFreeReturnBuffer(IntPtr Buffer);

    [DllImport("secur32.dll")]
    protected static extern uint LsaGetLogonSessionData(ref LUID LogonId, out IntPtr ppLogonSessionData);

    public static SECURITY_LOGON_SESSION_DATA_Managed GetLogonSessionData(LUID logonId)
    {
        IntPtr pLogonSessionData;
        uint ntstatus = LsaGetLogonSessionData(ref logonId, out pLogonSessionData);
        if(ntstatus != STATUS_SUCCESS)
        {
            throw NtStatusToWinException(ntstatus);
        }

        try
        {
            return new SECURITY_LOGON_SESSION_DATA_Managed(pLogonSessionData);
        }
        finally
        {
            LsaFreeReturnBuffer(pLogonSessionData);
        }
    }

    public static string GetSYSTEMsAMAccountName()
    {
        LUID systemLuid = LUID.GetSYSTEMLuid();
        SECURITY_LOGON_SESSION_DATA_Managed systemData = GetLogonSessionData(systemLuid);
        return systemData.UserName;
    }
}