diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index 491bf2f1a7..8217009840 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -365,7 +365,7 @@ def kerberos_login(self, domain, username, password="", ntlm_hash="", aesKey="", kerb_pass = "" self.username = self.args.delegate serverName = Principal(self.args.delegate_spn if self.args.delegate_spn else f"cifs/{self.remoteName}", type=constants.PrincipalNameType.NT_SRV_INST.value) - tgs, sk = kerberos_login_with_S4U(domain, self.hostname, username, password, nthash, lmhash, aesKey, kdcHost, self.args.delegate, serverName, useCache, no_s4u2proxy=self.args.no_s4u2proxy) + tgs, sk = kerberos_login_with_S4U(domain, self.hostname, username, password, nthash, lmhash, aesKey, kdcHost, self.args.delegate, serverName, useCache, no_s4u2proxy=self.args.no_s4u2proxy, u2u=self.args.u2u) self.logger.debug(f"TGS obtained for {self.args.delegate} for {serverName}") spn = f"cifs/{self.remoteName}" @@ -387,10 +387,14 @@ def kerberos_login(self, domain, username, password="", ntlm_hash="", aesKey="", used_ccache = " from ccache" if useCache else f":{process_secret(kerb_pass)}" if self.args.delegate: - used_ccache = f" through S4U with {username}" + u2u_str = "+U2U" if self.args.u2u else "" + auth_user = username if username else "ccache" + used_ccache = f" through S4U{u2u_str} with {auth_user}" if self.args.delegate_spn: - used_ccache = f" through S4U with {username} (w/ SPN {self.args.delegate_spn})" + u2u_str = "+U2U" if self.args.u2u else "" + auth_user = username if username else "ccache" + used_ccache = f" through S4U{u2u_str} with {auth_user} (w/ SPN {self.args.delegate_spn})" out = f"{self.domain}\\{self.username}{used_ccache} {self.mark_pwned()}" self.logger.success(out) diff --git a/nxc/protocols/smb/kerberos.py b/nxc/protocols/smb/kerberos.py index d34795b63d..62a5f15cf8 100644 --- a/nxc/protocols/smb/kerberos.py +++ b/nxc/protocols/smb/kerberos.py @@ -18,15 +18,17 @@ from nxc.logger import nxc_logger -def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash, aesKey, kdcHost, impersonate, spn, use_cache, no_s4u2proxy=False): +def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash, aesKey, kdcHost, impersonate, spn, use_cache, no_s4u2proxy=False, u2u=False): my_tgt = None if use_cache: - domain, _, tgt, _ = CCache.parseFile(domain, username, f"cifs/{hostname}") - if my_tgt is None: - raise - my_tgt = tgt["KDC_REP"] + domain, ccache_user, tgt, _ = CCache.parseFile(domain) + if tgt is None: + raise Exception("No TGT found in ccache file") + my_tgt = decoder.decode(tgt["KDC_REP"], asn1Spec=AS_REP())[0] cipher = tgt["cipher"] session_key = tgt["sessionKey"] + if not username and ccache_user: + username = ccache_user if my_tgt is None: principal = Principal(username, type=constants.PrincipalNameType.NT_PRINCIPAL.value) nxc_logger.debug("Getting TGT for user") @@ -117,9 +119,14 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash opts.append(constants.KDCOptions.renewable.value) opts.append(constants.KDCOptions.canonicalize.value) + if u2u: + opts.append(constants.KDCOptions.renewable_ok.value) + opts.append(constants.KDCOptions.enc_tkt_in_skey.value) + req_body["kdc-options"] = constants.encodeFlags(opts) - server_name = Principal(username, type=constants.PrincipalNameType.NT_UNKNOWN.value) + # For U2U, include the domain in the serverName + server_name = Principal(username, domain.upper(), type=constants.PrincipalNameType.NT_UNKNOWN.value) if u2u else Principal(username, type=constants.PrincipalNameType.NT_UNKNOWN.value) seq_set(req_body, "sname", server_name.components_to_asn1) req_body["realm"] = str(decoded_tgt["crealm"]) @@ -130,7 +137,10 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash req_body["nonce"] = random.getrandbits(31) seq_set_iter(req_body, "etype", (int(cipher.enctype), int(constants.EncryptionTypes.rc4_hmac.value))) - nxc_logger.info("Requesting S4U2self") + if u2u: + seq_set_iter(req_body, "additional-tickets", (ticket.to_asn1(TicketAsn1()),)) + + nxc_logger.info(f"Requesting S4U2self{'+U2U' if u2u else ''}") message = encoder.encode(tgs_req) r = sendReceive(message, domain, kdcHost) diff --git a/nxc/protocols/smb/proto_args.py b/nxc/protocols/smb/proto_args.py index cde7dcd574..6c0373e998 100644 --- a/nxc/protocols/smb/proto_args.py +++ b/nxc/protocols/smb/proto_args.py @@ -10,6 +10,7 @@ def proto_args(parser, parents): delegate_spn_arg = smb_parser.add_argument("--delegate-spn", action=get_conditional_action(_StoreAction), make_required=[], help="SPN to use for S4U2Proxy, if not specified the SPN used will be cifs/", type=str) generate_st = smb_parser.add_argument("--generate-st", type=str, dest="generate_st", action=get_conditional_action(_StoreAction), make_required=[], help="Store the S4U Service Ticket in the specified file") self_delegate_arg = smb_parser.add_argument("--self", dest="no_s4u2proxy", action=get_conditional_action(_StoreTrueAction), make_required=[], help="Only do S4U2Self, no S4U2Proxy (use with delegate)") + u2u_arg = smb_parser.add_argument("--u2u", action=get_conditional_action(_StoreTrueAction), make_required=[], help="Use User-to-User (U2U) authentication with S4U2Self") dgroup = smb_parser.add_mutually_exclusive_group() dgroup.add_argument("-d", "--domain", metavar="DOMAIN", dest="domain", type=str, help="domain to authenticate to") @@ -29,6 +30,7 @@ def proto_args(parser, parents): self_delegate_arg.make_required = [delegate_arg] generate_st.make_required = [delegate_arg] delegate_spn_arg.make_required = [delegate_arg] + u2u_arg.make_required = [delegate_arg] cred_gathering_group = smb_parser.add_argument_group("Credential Gathering") cred_gathering_group.add_argument("--sam", choices={"regdump", "secdump"}, nargs="?", const="regdump", help="dump SAM hashes from target systems")