diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index 641b08eb..7e1cd6f2 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -354,8 +354,10 @@ class smb(connection): kerb_pass = "" self.username = self.args.delegate serverName = Principal(f"cifs/{self.hostname}", type=constants.PrincipalNameType.NT_SRV_INST.value) - tgs = 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) self.logger.debug(f"Got TGS for {self.args.delegate} through S4U") + if self.args.store_st: + self.save_st(tgs, sk) self.conn.kerberosLogin(self.username, password, domain, lmhash, nthash, aesKey, kdcHost, useCache=useCache, TGS=tgs) if "Unix" not in self.server_os: @@ -630,6 +632,19 @@ class smb(connection): if self.host not in relay_list.read(): relay_list.write(self.host + "\n") + def save_st(self, st, sk): + ccache = CCache() + tgs_rep = st['KDC_REP'] + session_key = sk + try: + ccache.fromTGS(tgs_rep, session_key, session_key) + except SessionKeyDecryptionError as e: + self.logger.fail(f"Failed to decrypt session key: {e}") + return + + ccache.saveFile(f"{self.args.store_st}.ccache") + self.logger.success(f"Saved ST to {self.args.store_st}.ccache") + def generate_tgt(self): self.logger.info(f"Attempting to get TGT for {self.username}@{self.domain}") userName = Principal(self.username, type=constants.PrincipalNameType.NT_PRINCIPAL.value) diff --git a/nxc/protocols/smb/kerberos.py b/nxc/protocols/smb/kerberos.py index 87c64b0d..9c0a5aec 100644 --- a/nxc/protocols/smb/kerberos.py +++ b/nxc/protocols/smb/kerberos.py @@ -275,4 +275,4 @@ def kerberos_login_with_S4U(domain, hostname, username, password, nthash, lmhash tgs_formated["KDC_REP"] = r tgs_formated["cipher"] = cipher tgs_formated["sessionKey"] = new_session_key - return tgs_formated + return tgs_formated, session_key diff --git a/nxc/protocols/smb/proto_args.py b/nxc/protocols/smb/proto_args.py index 43a6feaa..6fd77f7d 100644 --- a/nxc/protocols/smb/proto_args.py +++ b/nxc/protocols/smb/proto_args.py @@ -1,4 +1,4 @@ -from argparse import _StoreTrueAction +from argparse import _StoreTrueAction, _StoreAction from nxc.helpers.args import DisplayDefaultsNotNone, DefaultTrackingAction @@ -7,6 +7,7 @@ def proto_args(parser, parents): smb_parser.add_argument("-H", "--hash", metavar="HASH", dest="hash", nargs="+", default=[], help="NTLM hash(es) or file(s) containing NTLM hashes") delegate_arg = smb_parser.add_argument("--delegate", action="store", help="Impersonate user with S4U2Self + S4U2Proxy") + store_st = smb_parser.add_argument("--store-st", dest="store_st", action=get_conditional_action(_StoreAction), make_required=[], help="Store the S4U Service Ticket in the specified file", type=str) 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)") dgroup = smb_parser.add_mutually_exclusive_group() @@ -24,6 +25,7 @@ def proto_args(parser, parents): smb_parser.add_argument("--generate-krb5-file", type=str, help="Generate a krb5 file like from a range of IP") smb_parser.add_argument("--generate-tgt", type=str, help="Generate a tgt ticket") self_delegate_arg.make_required = [delegate_arg] + store_st.make_required = [delegate_arg] cred_gathering_group = smb_parser.add_argument_group("Credential Gathering", "Options for gathering credentials") cred_gathering_group.add_argument("--sam", choices={"regdump", "secdump"}, nargs="?", const="regdump", help="dump SAM hashes from target systems")