/// <summary> /// Get SECURITY_LOGON_SESSION_DATA for a process or thread via a handle to its token and populate an InjectedThread object's Logon Session values /// </summary> /// <param name="hToken"></param> /// <param name="injectedThread"></param> static void GetLogonSessionData(IntPtr hToken, InjectedThread injectedThread) { int tokenInformationLength = 0; bool result = GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenOrigin, IntPtr.Zero, tokenInformationLength, out tokenInformationLength); IntPtr tokenInformation = Marshal.AllocHGlobal(tokenInformationLength); result = GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenOrigin, tokenInformation, tokenInformationLength, out tokenInformationLength); if (result) { // GetTokenInformation to retreive LUID struct TOKEN_ORIGIN tokenOrigin = (TOKEN_ORIGIN)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_ORIGIN)); IntPtr pLUID = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LUID))); // Get pointer to LUID struct for LsaGetLogonSessionData Marshal.StructureToPtr(tokenOrigin.OriginatingLogonSession, pLUID, false); IntPtr pLogonSessionData = IntPtr.Zero; LsaGetLogonSessionData(pLUID, out pLogonSessionData); SECURITY_LOGON_SESSION_DATA logonSessionData = (SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(pLogonSessionData, typeof(SECURITY_LOGON_SESSION_DATA)); // Check for a valid logon if (logonSessionData.PSiD != IntPtr.Zero) { if (injectedThread.Username.Equals("NO OWNER")) { string domain = Marshal.PtrToStringUni(logonSessionData.LoginDomain.buffer).Trim(); string username = Marshal.PtrToStringUni(logonSessionData.Username.buffer).Trim(); injectedThread.Username = $"{domain}\\{username}"; } // Add logon session information to InjectedThread object injectedThread.LogonSessionStartTime = DateTime.FromFileTime(logonSessionData.LoginTime); injectedThread.LogonType = Enum.GetName(typeof(SECURITY_LOGON_TYPES), logonSessionData.LogonType); injectedThread.AuthenticationPackage = Marshal.PtrToStringAuto(logonSessionData.AuthenticationPackage.buffer); } LsaFreeReturnBuffer(pLogonSessionData); } }
/// <summary> /// Extracts Token information from a thread's memory by wrapping GetTokenInformation(). Returns token information specified by the tokenInformationClass param /// </summary> /// <param name="hToken"></param> /// <param name="tokenInformationClass"></param> /// <returns>String containing the requested token information</returns> static string QueryToken(IntPtr hToken, TOKEN_INFORMATION_CLASS tokenInformationClass) { int tokenInformationLength = 0; // First need to get the length of TokenInformation - won't return true bool result = GetTokenInformation(hToken, tokenInformationClass, IntPtr.Zero, tokenInformationLength, out tokenInformationLength); // Buffer for the struct IntPtr tokenInformation = Marshal.AllocHGlobal(tokenInformationLength); // Make call to GetTokenInformation() and get particular Struct switch (tokenInformationClass) { case TOKEN_INFORMATION_CLASS.TokenUser: // Store the requested token information in the buffer result = GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenUser, tokenInformation, tokenInformationLength, out tokenInformationLength); if (result) { // Marshal the buffer to TOKEN_USER Struct TOKEN_USER tokenUser = (TOKEN_USER)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_USER)); // Extract SID from the TOKEN_USER struct IntPtr pSID = IntPtr.Zero; ConvertSidToStringSid(tokenUser.User.Sid, out pSID); string SID = Marshal.PtrToStringAuto(pSID); return(SID); } else { return(null); } case TOKEN_INFORMATION_CLASS.TokenPrivileges: result = GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenPrivileges, tokenInformation, tokenInformationLength, out tokenInformationLength); if (result) { TOKEN_PRIVILEGES tokenPrivileges = (TOKEN_PRIVILEGES)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_PRIVILEGES)); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < tokenPrivileges.PrivilegeCount; i++) { // Bitwise AND comparison to check that each token privilege attribute for SE_PRIVILEGE_ENABLED if (((LUID_ATTRIBUTES)tokenPrivileges.Privileges[i].Attributes & LUID_ATTRIBUTES.SE_PRIVILEGE_ENABLED) == LUID_ATTRIBUTES.SE_PRIVILEGE_ENABLED) { // Append the privilege to the stringBuilder stringBuilder.Append($", {tokenPrivileges.Privileges[i].Luid.LowPart.ToString()}"); } } return(stringBuilder.ToString().Remove(0, 2)); } else { return(null); } case TOKEN_INFORMATION_CLASS.TokenIntegrityLevel: // Mandatory Level SIDs for QueryToken() // https://support.microsoft.com/en-au/help/243330/well-known-security-identifiers-in-windows-operating-systems#allsids Dictionary <string, string> tokenIntegritySIDs = new Dictionary <string, string> { { "S-1-16-0", "Untrusted Mandatory Level" }, { "S-1-16-4096", "Low Mandatory Level" }, { "S-1-16-8192", "Medium Mandatory Level" }, { "S-1-16-8448", "Medium Plus Mandatory Level" }, { "S-1-16-12288", "High Mandatory Level" }, { "S-1-16-16384", "System Mandatory Level" }, { "S-1-16-20480", "Protected Process Mandatory Level" }, { "S-1-16-28672", "Secure Process Mandatory Level" } }; result = GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, tokenInformation, tokenInformationLength, out tokenInformationLength); if (result) { TOKEN_MANDATORY_LABEL tokenMandatoryLabel = (TOKEN_MANDATORY_LABEL)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_MANDATORY_LABEL)); // Extract SID string from TOKEN_MANDATORY_LABEL IntPtr pSID = IntPtr.Zero; ConvertSidToStringSid(tokenMandatoryLabel.label.Sid, out pSID); string SID = Marshal.PtrToStringAuto(pSID); if (tokenIntegritySIDs.ContainsKey(SID)) { return(tokenIntegritySIDs[SID]); } else { return(null); } } else { return(null); } case TOKEN_INFORMATION_CLASS.TokenOrigin: result = GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenOrigin, tokenInformation, tokenInformationLength, out tokenInformationLength); if (result) { TOKEN_ORIGIN tokenOrigin = (TOKEN_ORIGIN)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_ORIGIN)); string logonId = tokenOrigin.OriginatingLogonSession.LowPart.ToString(); return(logonId); } else { return(null); } } return(null); }