Windows API для получения информации о кэшированных билетах Kerberos

Я понимаю, что могу получить то, что мне нужно, запустив "klist.exe" и проанализировав вывод, но мне интересно, есть ли Windows/C#/Powershell API для получения информации о кэшированных билетах Kerberos на сервере Windows.

2 ответа

Microsoft уже предоставляет набор сценариев для этого. Таким образом, вам не нужно писать это с нуля. Просмотр и очистка кэшированных билетов Kerberos, и да, в них есть klist. В противном случае вы в конечном итоге пытаетесь использовать...

[System.Security.Principal.WindowsIdentity]

… А затем выполняете SID-переводы и т. П., Или вы заканчиваете тем же обсуждением в этом Q&A.

Как программно очистить кеш билетов Kerberos

Или используя эти ресурсы и настраивая их по мере необходимости.

Модуль Kerberos Модуль предоставляет доступ к кешу билетов Kerberos. Он может читать и удалять билеты текущего сеанса входа.

Валидатор управляемого кода для билетов Kerberos

Смысл Kerberos.NET в том, чтобы в таких сценариях было намного проще работать с Kerberos. Это делается путем удаления любых жестких зависимостей от Windows и переноса всей обработки заявки в само приложение. Это, конечно, означает, что вам не нужно, чтобы приложение находилось на компьютере, присоединенном к домену, и, вероятно, оно также не должно быть в Windows.

Install-Package Kerberos.NET

Использование библиотеки

Аутентификация билетов происходит в два этапа. На первом этапе проверяется правильность заявки с помощью IKerberosValidator с реализацией KerberosValidator по умолчанию. Второй этап включает преобразование заявки в пригодный для использования 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 на сервере. Например, пользователь Боб покинул компанию. В подобных ситуациях вы можете запустить этот сценарий, чтобы очистить все кэшированные билеты 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
        }

До сих пор я был в состоянии найти исходный код для klist.exe, и "LsaCallAuthenticationPackage", кажется, способ связи с кешем Kerberos в Windows:

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);
Другие вопросы по тегам