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:
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);