Windows API,用于获取有关缓存的Kerberos票证的信息

问题描述 投票:0回答:2

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

c# powershell winapi kerberos klist
2个回答
2
投票

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

使用图书馆

票证认证分两个阶段进行。第一阶段通过具有默认实现KerberosValidator的IKerberosValidator验证故障单的正确性。第二阶段涉及将故障单转换为可用的ClaimsIdentity,该声明发生在KerberosAuthenticator中。

最简单的入门方法是创建一个新的KerberosAuthenticator并调用Authenticate。如果需要调整转换的行为,可以通过重写ConvertTicket(DecryptedData数据)方法来实现。

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。 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
        }

0
投票

到目前为止,我能够找到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);
© www.soinside.com 2019 - 2024. All rights reserved.