diff --git a/Rubeus/Commands/Asktgt.cs b/Rubeus/Commands/Asktgt.cs index f4e88e55..658c651d 100644 --- a/Rubeus/Commands/Asktgt.cs +++ b/Rubeus/Commands/Asktgt.cs @@ -255,7 +255,8 @@ public void Execute(Dictionary arguments) else if (String.IsNullOrEmpty(certificate)) Ask.TGT(user, domain, hash, encType, outfile, ptt, dc, luid, true, opsec, servicekey, changepw, pac, proxyUrl, service); else - Ask.TGT(user, domain, certificate, password, encType, outfile, ptt, dc, luid, true, verifyCerts, servicekey, getCredentials, proxyUrl, service, changepw); + // Ask.TGT is overloaded! This is another function implementation than the one above + Ask.TGT(user, domain, certificate, password, encType, outfile, ptt, dc, luid, true, opsec, verifyCerts, servicekey, getCredentials, proxyUrl, service, changepw); return; } diff --git a/Rubeus/lib/Ask.cs b/Rubeus/lib/Ask.cs index d0e1538b..3e82712e 100644 --- a/Rubeus/lib/Ask.cs +++ b/Rubeus/lib/Ask.cs @@ -53,7 +53,7 @@ public class Ask Console.WriteLine("[*] Using {0} hash: {1}", etype, keyString); Console.WriteLine("[*] Building AS-REQ (w/ preauth) for: '{0}\\{1}'", domain, userName); AS_REQ userHashASREQ = AS_REQ.NewASReq(userName, domain, keyString, etype, opsec, changepw, pac, service); - return InnerTGT(userHashASREQ, etype, outfile, ptt, domainController, luid, describe, true, opsec, servicekey, false, proxyUrl); + return InnerTGT(userHashASREQ, etype, outfile, ptt, domainController, luid, describe, true, servicekey, false, proxyUrl); } } catch (KerberosErrorException ex) @@ -186,7 +186,22 @@ public static X509Certificate2 FindCertificate(string certificate, string storeP } } - public static byte[] TGT(string userName, string domain, string certFile, string certPass, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", LUID luid = new LUID(), bool describe = false, bool verifyCerts = false, string servicekey = "", bool getCredentials = false, string proxyUrl = null, string service = null, bool changepw = false) { + /// + /// Use this overload to request a TGT via PKINIT and a X509 certificate + /// + public static byte[] TGT(string userName, string domain, string certFile, string certPass, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", LUID luid = new LUID(), bool describe = false, bool opsec = false, bool verifyCerts = false, string servicekey = "", bool getCredentials = false, string proxyUrl = null, string service = null, bool changepw = false) + { + // send request without Pre-Auth to emulate genuine traffic + bool preauth = false; + if (opsec) + { + try + { + preauth = NoPreAuthTGT(userName, domain, "", etype, domainController, outfile, ptt, luid, describe, true, proxyUrl); + } + catch (KerberosErrorException) { } + } + try { X509Certificate2 cert = FindCertificate(certFile, certPass); @@ -206,8 +221,8 @@ public static X509Certificate2 FindCertificate(string certificate, string storeP Console.WriteLine("[*] Using PKINIT with etype {0} and subject: {1} ", etype, cert.Subject); Console.WriteLine("[*] Building AS-REQ (w/ PKINIT preauth) for: '{0}\\{1}'", domain, userName); - AS_REQ pkinitASREQ = AS_REQ.NewASReq(userName, domain, cert, agreement, etype, verifyCerts, service, changepw); - return InnerTGT(pkinitASREQ, etype, outfile, ptt, domainController, luid, describe, true, false, servicekey, getCredentials, proxyUrl); + AS_REQ pkinitASREQ = AS_REQ.NewASReq(userName, domain, cert, agreement, etype, opsec, verifyCerts, service, changepw); + return InnerTGT(pkinitASREQ, etype, outfile, ptt, domainController, luid, describe, true, servicekey, getCredentials, proxyUrl); } catch (KerberosErrorException ex) { KRB_ERROR error = ex.krbError; @@ -248,7 +263,7 @@ public static int GetKeySize(Interop.KERB_ETYPE etype) { } } - public static byte[] InnerTGT(AS_REQ asReq, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", LUID luid = new LUID(), bool describe = false, bool verbose = false, bool opsec = false, string serviceKey = "", bool getCredentials = false, string proxyUrl = null) + public static byte[] InnerTGT(AS_REQ asReq, Interop.KERB_ETYPE etype, string outfile, bool ptt, string domainController = "", LUID luid = new LUID(), bool describe = false, bool verbose = false, string serviceKey = "", bool getCredentials = false, string proxyUrl = null) { if ((ulong)luid != 0) { Console.WriteLine("[*] Target LUID : {0}", (ulong)luid); diff --git a/Rubeus/lib/krb_structures/AS_REQ.cs b/Rubeus/lib/krb_structures/AS_REQ.cs index b8f20fb7..ce6d44d7 100755 --- a/Rubeus/lib/krb_structures/AS_REQ.cs +++ b/Rubeus/lib/krb_structures/AS_REQ.cs @@ -62,27 +62,10 @@ public static AS_REQ NewASReq(string userName, string domain, Interop.KERB_ETYPE req.req_body.sname.name_string.Add(domain); } - // try to build a realistic request if (opsec) - { - string hostName = Dns.GetHostName(); - List addresses = new List(); - 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 + ApplyOpsecChanges(req.req_body); + else // add in our encryption type req.req_body.etypes.Add(etype); - } return req; } @@ -134,38 +117,21 @@ public static AS_REQ NewASReq(string userName, string domain, string keyString, req.req_body.sname.name_string.Add("changepw"); } - // try to build a realistic request if (opsec) - { - string hostName = Dns.GetHostName(); - List addresses = new List(); - 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 + ApplyOpsecChanges(req.req_body); + else // add in our encryption type req.req_body.etypes.Add(etype); - } return req; } //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, string service = null, bool changepw = false) { - + public static AS_REQ NewASReq(string userName, string domain, X509Certificate2 cert, KDCKeyAgreement agreement, Interop.KERB_ETYPE etype, bool opsec = false, bool verifyCerts = false, string service = null, bool changepw = 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); + AS_REQ req = new AS_REQ(cert, agreement, opsec, verifyCerts); // req.padata.Add() @@ -209,8 +175,10 @@ public static AS_REQ NewASReq(string userName, string domain, X509Certificate2 c req.req_body.sname.name_string.Add("changepw"); } - // add in our encryption type - req.req_body.etypes.Add(etype); + if (opsec) + ApplyOpsecChanges(req.req_body); + else // add in our encryption type + req.req_body.etypes.Add(etype); return req; } @@ -246,21 +214,21 @@ public AS_REQ(string keyString, Interop.KERB_ETYPE etype, bool opsec = false, bo this.keyString = keyString; } - public AS_REQ(X509Certificate2 pkCert, KDCKeyAgreement agreement, bool verifyCerts = false) { - + public AS_REQ(X509Certificate2 pkCert, KDCKeyAgreement agreement, bool opsec = false, bool verifyCerts = false) { // default, for creation pvno = 5; - msg_type = 10; + msg_type = (long)Interop.KERB_MESSAGE_TYPE.AS_REQ; padata = new List(); - req_body = new KDCReqBody(); + req_body = new KDCReqBody(true, opsec); // add the include-pac == true padata.Add(new PA_DATA()); // add the encrypted timestamp - padata.Add(new PA_DATA(pkCert, agreement, req_body, verifyCerts)); + padata.Add(new PA_DATA(pkCert, agreement, req_body, verifyCerts)); + } public AS_REQ(byte[] data) @@ -313,6 +281,25 @@ public AS_REQ(byte[] data) } } } + /// + /// Applies opsec changes in-place to an existing, initialized KDCReqBody including + /// common etypes, the optional addresses field and the "canonicalize" kdc_option. + /// + /// + private static void ApplyOpsecChanges(KDCReqBody req_body) + { + string hostName = Dns.GetHostName(); + List addresses = new List(); + addresses.Add(new HostAddress(hostName)); + req_body.addresses = addresses; + req_body.kdcOptions = req_body.kdcOptions | Interop.KdcOptions.CANONICALIZE; + req_body.etypes.Add(Interop.KERB_ETYPE.aes256_cts_hmac_sha1); + req_body.etypes.Add(Interop.KERB_ETYPE.aes128_cts_hmac_sha1); + req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac); + req_body.etypes.Add(Interop.KERB_ETYPE.rc4_hmac_exp); + req_body.etypes.Add(Interop.KERB_ETYPE.old_exp); + req_body.etypes.Add(Interop.KERB_ETYPE.des_cbc_md5); + } public AsnElt Encode() {