【问题标题】:Windows API to get information about cached Kerberos tickets用于获取有关缓存的 Kerberos 票证信息的 Windows API
【发布时间】:2019-02-16 07:09:28
【问题描述】:

我知道我可以通过运行“klist.exe”并解析输出来获得所需的信息,但我想知道是否有 Windows/C#/Powershell API 可以获取有关 Windows 服务器上缓存的 Kerberos 票证的信息。

【问题讨论】:

    标签: c# powershell winapi kerberos klist


    【解决方案1】:

    Microsoft 已经为此提供了一组脚本。所以,你不必从头开始写这个。 Viewing and Purging Cached Kerberos Tickets 是的,他们有 klist。否则,你最终会试图利用……

    [System.Security.Principal.WindowsIdentity]
    

    ...然后进行 SID 翻译等,否则您最终会在此问答中进行相同的讨论。

    How to programmatically clear the Kerberos ticket cache

    或利用这些资源并根据需要进行调整。

    Kerberos Module 该模块允许访问 Kerberos 票证缓存。它可以读取和清除当前登录会话的票证。

    A Managed Code validator for Kerberos tickets

    Kerberos.NET 的重点是让 Kerberos 更易于使用 在这种情况下。这是通过删除任何硬依赖来完成的 Windows 并将所有票证处理转移到应用程序本身。 这当然意味着您不需要将应用程序放在 加入域的机器,它可能不需要在 Windows 上 要么。

    Install-Package Kerberos.NET
    

    使用库

    票证身份验证分两个阶段进行。第一阶段验证 通过具有默认值的 IKerberosValidator 的正确性票证 KerberosValidator 的实现。第二阶段涉及 将票据转换为可用的 ClaimsIdentity,发生在 KerberosAuthenticator。

    最简单的开始方法是创建一个新的 KerberosAuthenticator 并调用 Authenticate。如果你需要调整 转换的行为,您可以通过覆盖 ConvertTicket(DecryptedData data) 方法。

    var authenticator = new KerberosAuthenticator(new KeyTable(File.ReadAllBytes("sample.keytab")));
    
    var identity = authenticator.Authenticate("YIIHCAYGKwYBBQUCoIIG...");
    
    Assert.IsNotNull(identity);
    
    var name = identity.Name;
    
    Assert.IsFalse(string.IsNullOrWhitespace(name));
    

    请注意,验证器的构造函数参数是 键表。 KeyTable 是一种常用格式,用于将密钥存储在其他设备上 平台。您可以使用由 ktpass 等工具创建的文件,或者 你可以在实例化过程中传递一个 KerberosKey,它会有 效果一样。

    列出所有缓存的 Kerberos 票证

    在域中对身份验证进行管理或故障排除时,有时您需要知道用户和服务的票证是否缓存在计算机上。此脚本将计算机上所有用户缓存的票证导出到文本文件以供审核。

    下载: GetKerbTix.ps1

    清除所有 Kerberos 票证

    在某些情况下,管理员可能想要清除服务器上缓存的 Kerberos 票证。例如,用户 Bob 离开了公司。在这种情况下,您可以运行此脚本来清除计算机上所有会话的所有缓存 Kerberos 票证和 TGT。

    下载: PurgeAllKerbTickets.ps1

    #************************************************ 
    # GetKerbTix.ps1 
    # Version 1.0 
    # Date: 6-11-2014 
    # Author: Tim Springston [MSFT] 
    # Description: On a specific computer the script is ran on,  
    #  this script finds all logon sessions which have Kerberos 
    #     tickets cached and enumerates the tickets and any ticket granting tickets. 
    # The tickets may be from remote or interactive users and may be  
    #  any logon type session (network, batch, interactive, remote interactive...). 
    # This script will run on Windows Server 2008/Vista and later. 
    #************************************************ 
    cls 
    $FormatEnumerationLimit = -1 
    $ComputerName = $env:COMPUTERNAME 
    $UserName = [Security.Principal.WindowsIdentity]::GetCurrent().name 
    $ComputerDomain = [System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain().name 
    $Date = Get-Date 
    
    
    #Prepare an output file to place info into. 
    $ExportFile = "C:\windows\temp\" + $ComputerName + "_CachedKerberosTickets.txt" 
    "Cached Kerberos Tickets" | Out-File $ExportFile -Encoding utf8 
    "Logged on User:$UserName" | Out-File $ExportFile -Append -Encoding utf8 
    "Computer name: $ComputerName" | Out-File $ExportFile -Append -Encoding utf8 
    "Computer Domain: $ComputerDomain" | Out-File $ExportFile -Append -Encoding utf8 
    "Date: $Date" | Out-File $ExportFile -Append -Encoding utf8 
    "************************************" | Out-File $ExportFile -Append -Encoding utf8 
    
    function GetKerbSessions 
        { 
        $Sessions = @() 
        $WMILogonSessions = gwmi win32_LogonSession 
        foreach ($WMILogonSession in $WMILogonSessions) 
            { 
            $LUID = [Convert]::ToString($WMILogonSession.LogonID, 16) 
            $LUID = '0x' + $LUID 
            $Sessions += $LUID 
            } 
        return $sessions 
        } 
    
    function GetKerbSessionInfo 
        { 
        $OS = gwmi win32_operatingsystem 
        $sessions = New-Object PSObject 
        if ($OS.Buildnumber -ge 9200) 
            { 
            $KlistSessions = klist sessions 
            $Counter = 0 
    
            foreach ($item in $KlistSessions) 
                { 
                if ($item -match "^\[.*\]") 
                    { 
                    $LogonId = $item.split(' ')[3] 
                    $LogonId = $LogonId.Replace('0:','') 
                    $Identity = $item.split(' ')[4] 
                    $Token5 = $item.Split(' ')[5] 
                    $AuthnMethod = $Token5.Split(':')[0] 
                    $LogonType = $Token5.Split(':')[1] 
                    $Session = New-Object PSObject 
                    Add-Member -InputObject $Session -MemberType NoteProperty -Name "SessionID" -Value $LogonId 
                    Add-Member -InputObject $Session -MemberType NoteProperty -Name "Identity" -Value $Identity 
                    Add-Member -InputObject $Session -MemberType NoteProperty -Name "Authentication Method" -Value $AuthnMethod             
                    Add-Member -InputObject $Session -MemberType NoteProperty -Name "Logon Type" -Value $LogonType 
    
                    Add-Member -InputObject $sessions -MemberType NoteProperty -Name $LogonId -Value $Session 
                    $Session = $null 
                    } 
                } 
            } 
        if ($OS.Buildnumber -lt 9200) 
            { 
            $WMILogonSessions = gwmi win32_LogonSession 
            foreach ($WMILogonSession in $WMILogonSessions) 
                { 
                $LUID = [Convert]::ToString($WMILogonSession.LogonID, 16) 
                $LUID = '0x' + $LUID 
                $Session = New-Object PSObject 
                Add-Member -InputObject $Session -MemberType NoteProperty -Name "SessionID" -Value $LUID 
                Add-Member -InputObject $Session -MemberType NoteProperty -Name "Identity" -Value "Not available" 
                Add-Member -InputObject $Session -MemberType NoteProperty -Name "Authentication Method" -Value $WMILogonSession.AuthenticationPackage         
                Add-Member -InputObject $Session -MemberType NoteProperty -Name "Logon Type" -Value $WMILogonSession.LogonType 
    
                Add-Member -InputObject $sessions -MemberType NoteProperty -Name $LUID -Value $Session 
                $Session = $null 
                } 
            } 
        return $sessions 
        } 
    
    function ReturnSessionTGTs 
        { 
        param ($SessionID = $null) 
        if ($SessionID -eq $null) 
            { 
            $RawTGT =  klist.exe tgt 
            } 
            else 
                { 
                $RawTGT =  klist.exe tgt -li $sessionID 
                } 
        $TGT = @() 
        foreach ($Line in $RawTGT) 
            { 
            if ($Line.length -ge 1) 
                { 
                $TGT += $Line 
                } 
            } 
        if ($TGT -contains 'Error calling API LsaCallAuthenticationPackage (Ticket Granting Ticket substatus): 1312') 
            {$TGT = 'No ticket granting ticket cached in session.'} 
        return $TGT 
        }     
    
    function ReturnSessionTickets  
        { 
        param ($SessionID = $null) 
        $OS = gwmi win32_operatingsystem 
        if ($SessionID -eq $null) 
            { 
            $TicketsArray =  klist.exe tickets 
            } 
            else 
                { 
                $TicketsArray =  klist.exe tickets -li $sessionID 
                } 
        $Counter = 0 
        $TicketsObject = New-Object PSObject 
        foreach ($line in $TicketsArray) 
            { 
            if ($line -match "^#\d") 
                { 
                $Ticket = New-Object PSObject 
                $Number = $Line.Split('>')[0] 
                $Line1 = $Line.Split('>')[1] 
                $TicketNumber = "Ticket " + $Number 
                $Client = $Line1 ;    $Client = $Client.Replace('Client:','') ; $Client = $Client.Substring(2) 
                $Server = $TicketsArray[$Counter+1]; $Server = $Server.Replace('Server:','') ;$Server = $Server.substring(2) 
                $KerbTicketEType = $TicketsArray[$Counter+2];$KerbTicketEType = $KerbTicketEType.Replace('KerbTicket Encryption Type:','');$KerbTicketEType = $KerbTicketEType.substring(2) 
                $TickFlags = $TicketsArray[$Counter+3];$TickFlags = $TickFlags.Replace('Ticket Flags','');$TickFlags = $TickFlags.substring(2) 
                $StartTime =  $TicketsArray[$Counter+4];$StartTime = $StartTime.Replace('Start Time:','');$StartTime = $StartTime.substring(2) 
                $EndTime = $TicketsArray[$Counter+5];$EndTime = $EndTime.Replace('End Time:','');$EndTime = $EndTime.substring(4) 
                $RenewTime = $TicketsArray[$Counter+6];$RenewTime = $RenewTime.Replace('Renew Time:','');$RenewTime = $RenewTime.substring(2) 
                $SessionKey = $TicketsArray[$Counter+7];$SessionKey = $SessionKey.Replace('Session Key Type:','');$SessionKey = $SessionKey.substring(2) 
    
                Add-Member -InputObject $Ticket -MemberType NoteProperty -Name "Client" -Value $Client 
                Add-Member -InputObject $Ticket -MemberType NoteProperty -Name "Server" -Value $Server 
                Add-Member -InputObject $Ticket -MemberType NoteProperty -Name "KerbTicket Encryption Type" -Value $KerbTicketEType 
                Add-Member -InputObject $Ticket -MemberType NoteProperty -Name "Ticket Flags" -Value $TickFlags 
                Add-Member -InputObject $Ticket -MemberType NoteProperty -Name "Start Time" -Value $StartTime 
                Add-Member -InputObject $Ticket -MemberType NoteProperty -Name "End Time" -Value $EndTime 
                Add-Member -InputObject $Ticket -MemberType NoteProperty -Name "Renew Time" -Value $RenewTime 
                Add-Member -InputObject $Ticket -MemberType NoteProperty -Name "Session Key Type" -Value $SessionKey 
    
                if ($OS.BuildNumber -ge 9200) 
                    { 
                    $CacheFlags =  $TicketsArray[$Counter+8];$CacheFlags = $CacheFlags.Replace('Cache Flags:','');$CacheFlags = $CacheFlags.substring(2) 
                    $KDCCalled = $TicketsArray[$Counter+9];$KDCCalled = $KDCCalled.Replace('Kdc Called:','');$KDCCalled = $KDCCalled.substring(2) 
                    Add-Member -InputObject $Ticket -MemberType NoteProperty -Name "Cache Flags" -Value $CacheFlags 
                    Add-Member -InputObject $Ticket -MemberType NoteProperty -Name "KDC Called" -Value $KDCCalled 
                    } 
                Add-Member -InputObject $TicketsObject -MemberType NoteProperty -Name $TicketNumber -Value $Ticket 
                $Ticket = $null 
                } 
            $Counter++ 
    
    
            } 
        return $TicketsObject 
        }     
    
    $OS = gwmi win32_operatingsystem 
    $sessions = getkerbsessions 
    $sessioninfo = GetKerbSessionInfo 
    foreach ($Session in $sessions) 
    {     
        #Get Session details as well 
        $currentsessioninfo = $sessioninfo.$session 
        $ID = $currentsessioninfo.identity 
        $SessionID = $currentsessioninfo.SessionID 
        $LogonType = $currentsessioninfo.'Logon Type' 
        $AuthMethod = $currentsessioninfo.'Authentication Method' 
        if ($OS.Buildnumber -lt 9200) 
            { 
            Write-Host "Kerberos Tickets for LogonID $SessionID" 
            "Kerberos Tickets for LogonID $SessionID" | Out-File $ExportFile -Append -Encoding utf8 
            } 
            else 
            { 
            Write-Host "Kerberos Tickets for $ID" 
            "Kerberos Tickets for $ID" | Out-File $ExportFile -Append -Encoding utf8 
            } 
        Write-Host "*****************************" 
         "*****************************" | Out-File $ExportFile -Append -Encoding utf8 
        Write-Host "Logon Type: $LogonType" 
        "Logon Type: $LogonType" | Out-File $ExportFile -Append -Encoding utf8 
        Write-host "Session ID: $SessionID" 
        "Session ID: $SessionID" | Out-File $ExportFile -Append -Encoding utf8 
        Write-host "Auth Method: $AuthMethod" 
        "Auth Method: $AuthMethod" | Out-File $ExportFile -Append -Encoding utf8 
        $SessionTickets = ReturnSessionTickets $Session 
    
    
        $TGT = ReturnSessionTGTs $SessionID 
        $TGT | FL * 
        $TGT | Out-File $ExportFile -Append -Encoding utf8 
    
        if ($SessionTickets -notmatch 'Ticket') 
            { 
            Write-Host "Session TGT: No tickets for this session in cache." 
            "Session TGT: No tickets for this session in cache." | Out-File $ExportFile -Append -Encoding utf8 
            } 
            else 
            { 
            $SessionTickets | FL * 
            $SessionTickets    | Out-File $ExportFile -Append -Encoding utf8 
            } 
        Write-Host "`n" 
         "`n" | Out-File $ExportFile -Append -Encoding utf8 
    
    } 
    
    
    #************************************************
    # PurgeAllKerbTickets.ps1
    # Version 1.0
    # Date: 6-12-2014
    # Author: Tim Springston [MSFT]
    # Description: On a specific computer the script is ran on, 
    #  this script finds all logon sessions which have Kerberos
    #  tickets cached and for each session purges the ticket granting
    #   tickets and the tickets using klist.exe.
    #************************************************
    cls
    
    function GetKerbSessions
        {
        $Sessions = @()
        $WMILogonSessions = gwmi win32_LogonSession
        foreach ($WMILogonSession in $WMILogonSessions)
            {
            $LUID = [Convert]::ToString($WMILogonSession.LogonID, 16)
            $LUID = '0x' + $LUID
            $Sessions += $LUID
            }
        return $sessions
        }
    
    Write-Host "WARNING: This script will purge all cached Kerberos tickets on the local computer for all sessions (whether interactive, network or other sessions)."  -backgroundcolor Red 
    Write-Host "In a well-connected environment clients will request and obtain Kerberos tickets on demand without interruption. If not well-connected to a domain controller (remote network) then further network resource authentication may fail or use NTLM if tickets are purged." -BackgroundColor red
    Write-Host "Confirm whether to purge by entering YES"
    $Response = Read-Host
    
    if ($Response -match 'YES')
        {
        $sessions = GetKerbSessions
    
        foreach ($Session in $sessions)
            {
            $PurgedTix = klist.exe -li $Session purge
            }
        Write-Host "All tickets purged!" -backgroundcolor green
        }
        else
            {
            Write-Host "Confirmation not received. NOT purging tickets." -backgroundcolor yellow
            }
    

    【讨论】:

      【解决方案2】:

      到目前为止,我能够找到 klist.exe 的源代码,“LsaCa​​llAuthenticationPackage”似乎是与 Windows 中的 Kerberos 缓存进行通信的方式:

      https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/security/authorization/klist/KList.c

      Status = LsaCallAuthenticationPackage(
                  LogonHandle,
                  PackageId,
                  &CacheRequest,
                  sizeof(CacheRequest),
                  (PVOID *) &CacheResponse,
                  &ResponseSize,
                  &SubStatus
                  );
      if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus))
      {
          ShowNTError("LsaCallAuthenticationPackage", Status);
          printf("Substatus: 0x%x\n",SubStatus);
          return FALSE;
      }
      
      printf("\nCached Tickets: (%lu)\n", CacheResponse->CountOfTickets);
      for (Index = 0; Index < CacheResponse->CountOfTickets ; Index++ )
      {
          printf("\n   Server: %wZ@%wZ\n",
              &CacheResponse->Tickets[Index].ServerName,
              &CacheResponse->Tickets[Index].RealmName);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-23
        • 1970-01-01
        • 2023-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多