From ce9b76627677ba1e4d65e83bfbd6f2716fead68f Mon Sep 17 00:00:00 2001 From: Marshall Hallenbeck Date: Wed, 20 Mar 2024 17:48:42 -0400 Subject: [PATCH 1/9] fix+feat(smb-users): allow requesting only specific users, print LastPwSet, and functionize more code for future use --- nxc/protocols/smb.py | 8 ++- nxc/protocols/smb/proto_args.py | 2 +- nxc/protocols/smb/samruser.py | 119 +++++++++++++++++++++++--------- 3 files changed, 95 insertions(+), 34 deletions(-) diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index 4db4768f..cc3e5faa 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -1000,8 +1000,12 @@ class smb(connection): return groups def users(self): - self.logger.display("Trying to dump local users with SAMRPC protocol") - return UserSamrDump(self).dump() + if len(self.args.users) > 1: + self.logger.display(f"Dumping users: {', '.join(self.args.users)}") + else: + self.logger.info("Trying to dump local users with SAMRPC protocol") + + return UserSamrDump(self).dump(self.args.users) def hosts(self): hosts = [] diff --git a/nxc/protocols/smb/proto_args.py b/nxc/protocols/smb/proto_args.py index 85148472..164c03ca 100644 --- a/nxc/protocols/smb/proto_args.py +++ b/nxc/protocols/smb/proto_args.py @@ -38,7 +38,7 @@ def proto_args(parser, std_parser, module_parser): egroup.add_argument("--disks", action="store_true", help="enumerate disks") egroup.add_argument("--loggedon-users-filter", action="store", help="only search for specific user, works with regex") egroup.add_argument("--loggedon-users", action="store_true", help="enumerate logged on users") - egroup.add_argument("--users", nargs="?", const="", metavar="USER", help="enumerate domain users, if a user is specified than only its information is queried.") + egroup.add_argument("--users", nargs="*", metavar="USER", help="enumerate domain users, if a user is specified than only its information is queried.") egroup.add_argument("--groups", nargs="?", const="", metavar="GROUP", help="enumerate domain groups, if a group is specified than its members are enumerated") egroup.add_argument("--computers", nargs="?", const="", metavar="COMPUTER", help="enumerate computer users") egroup.add_argument("--local-groups", nargs="?", const="", metavar="GROUP", help="enumerate local groups, if a group is specified then its members are enumerated") diff --git a/nxc/protocols/smb/samruser.py b/nxc/protocols/smb/samruser.py index 11cf30a9..3ed5f5c3 100644 --- a/nxc/protocols/smb/samruser.py +++ b/nxc/protocols/smb/samruser.py @@ -4,6 +4,7 @@ from impacket.dcerpc.v5 import transport, samr from impacket.dcerpc.v5.rpcrt import DCERPCException from impacket.dcerpc.v5.rpcrt import DCERPC_v5 from impacket.nt_errors import STATUS_MORE_ENTRIES +from datetime import datetime, timedelta class UserSamrDump: @@ -26,6 +27,8 @@ class UserSamrDump: self.doKerberos = connection.kerberos self.protocols = UserSamrDump.KNOWN_PROTOCOLS.keys() self.users = [] + self.rpc_transport = None + self.dce = None if self.hash is not None: if self.hash.find(":") != -1: @@ -36,7 +39,7 @@ class UserSamrDump: if self.password is None: self.password = "" - def dump(self): + def dump(self, requested_users=None): # Try all requested protocols until one works. for protocol in self.protocols: try: @@ -45,7 +48,7 @@ class UserSamrDump: except KeyError: self.logger.debug(f"Invalid Protocol '{protocol}'") self.logger.debug(f"Trying protocol {protocol}") - rpctransport = transport.SMBTransport( + self.rpc_transport = transport.SMBTransport( self.addr, port, r"\samr", @@ -58,24 +61,24 @@ class UserSamrDump: doKerberos=self.doKerberos, ) try: - self.fetchList(rpctransport) + self.fetch_users(requested_users) break except Exception as e: - self.logger.debug(f"Protocol failed: {e}") + self.logger.debug(f"Connection with protocol {protocol} failed: {e}") return self.users - def fetchList(self, rpctransport): - dce = DCERPC_v5(rpctransport) - dce.connect() - dce.bind(samr.MSRPC_UUID_SAMR) + def fetch_users(self, requested_users): + self.dce = DCERPC_v5(self.rpc_transport) + self.dce.connect() + self.dce.bind(samr.MSRPC_UUID_SAMR) # Setup Connection - resp = samr.hSamrConnect2(dce) + resp = samr.hSamrConnect2(self.dce) if resp["ErrorCode"] != 0: raise Exception("Connect error") resp2 = samr.hSamrEnumerateDomainsInSamServer( - dce, + self.dce, serverHandle=resp["ServerHandle"], enumerationContext=0, preferedMaximumLength=500, @@ -84,7 +87,7 @@ class UserSamrDump: raise Exception("Connect error") resp3 = samr.hSamrLookupDomainInSamServer( - dce, + self.dce, serverHandle=resp["ServerHandle"], name=resp2["Buffer"]["Buffer"][0]["Name"], ) @@ -92,7 +95,7 @@ class UserSamrDump: raise Exception("Connect error") resp4 = samr.hSamrOpenDomain( - dce, + self.dce, serverHandle=resp["ServerHandle"], desiredAccess=samr.MAXIMUM_ALLOWED, domainId=resp3["DomainId"], @@ -101,28 +104,82 @@ class UserSamrDump: raise Exception("Connect error") self.__domains = resp2["Buffer"]["Buffer"] - domainHandle = resp4["DomainHandle"] + domain_handle = resp4["DomainHandle"] # End Setup - status = STATUS_MORE_ENTRIES - enumerationContext = 0 - while status == STATUS_MORE_ENTRIES: + if requested_users: + self.logger.debug(f"Looping through users requested and looking up their information: {requested_users}") try: - resp = samr.hSamrEnumerateUsersInDomain(dce, domainHandle, enumerationContext=enumerationContext) + names_lookup_resp = samr.hSamrLookupNamesInDomain(self.dce, domain_handle, requested_users) + rids = [r["Data"] for r in names_lookup_resp["RelativeIds"]["Element"]] + self.logger.debug(f"Specific RIDs retrieved: {rids}") + users = self.get_user_info(domain_handle, rids) except DCERPCException as e: - if str(e).find("STATUS_MORE_ENTRIES") < 0: - self.logger.fail("Error enumerating domain user(s)") - break - resp = e.get_packet() - self.logger.success("Enumerated domain user(s)") - for user in resp["Buffer"]["Buffer"]: - r = samr.hSamrOpenUser(dce, domainHandle, samr.MAXIMUM_ALLOWED, user["RelativeId"]) - info_user = samr.hSamrQueryInformationUser2(dce, r["UserHandle"], samr.USER_INFORMATION_CLASS.UserAllInformation)["Buffer"]["All"]["AdminComment"] - self.logger.highlight(f"{self.domain}\\{user['Name']:<30} {info_user}") - self.users.append(user["Name"]) - samr.hSamrCloseHandle(dce, r["UserHandle"]) + self.logger.debug(f"Exception while requesting users in domain: {e}") + if "STATUS_SOME_NOT_MAPPED" in str(e): + # which user is not translated correctly isn't returned so we can't tell the user which is failing, which is very annoying + self.logger.fail("One of the users requested does not exist in the domain, causing a critical failure during translation, re-check the users and try again") + else: + self.logger.fail(f"Error occurred when looking up users in domain: {e}") + else: + status = STATUS_MORE_ENTRIES + enumerationContext = 0 + while status == STATUS_MORE_ENTRIES: + try: + enumerate_users_resp = samr.hSamrEnumerateUsersInDomain(self.dce,domain_handle,enumerationContext=enumerationContext) + except DCERPCException as e: + if str(e).find("STATUS_MORE_ENTRIES") < 0: + self.logger.fail("Error enumerating domain user(s)") + break + enumerate_users_resp = e.get_packet() + + rids = [r["RelativeId"] for r in enumerate_users_resp["Buffer"]["Buffer"]] + self.logger.debug(f"Full domain RIDs retrieved: {rids}") + users = self.get_user_info(domain_handle, rids) + + # set these for the while loop + enumerationContext = enumerate_users_resp["EnumerationContext"] + status = enumerate_users_resp["ErrorCode"] + self.print_user_info(users) + self.dce.disconnect() - enumerationContext = resp["EnumerationContext"] - status = resp["ErrorCode"] + def get_user_info(self, domain_handle, user_ids): + self.logger.debug(f"Getting user info for users: {user_ids}") + users = [] - dce.disconnect() + for user in user_ids: + self.logger.debug(f"Calling hSamrOpenUser for RID {user}") + open_user_resp = samr.hSamrOpenUser( + self.dce, + domain_handle, + samr.MAXIMUM_ALLOWED, + user + ) + info_user_resp = samr.hSamrQueryInformationUser2( + self.dce, + open_user_resp["UserHandle"], + samr.USER_INFORMATION_CLASS.UserAllInformation + )["Buffer"] + + user_info = info_user_resp["All"] + user_name = user_info["UserName"] + user_description = user_info["AdminComment"] + last_pw_set = old_large_int_to_datetime(user_info["PasswordLastSet"]) + users.append({"name": user_name, "description": user_description, "last_pw_set": last_pw_set}) + + samr.hSamrCloseHandle(self.dce, open_user_resp["UserHandle"]) + return users + + def print_user_info(self, users): + self.logger.highlight(f"{'Username':<42} {'Last PW Set':<20}\t {'Description'}") # header + for user in users: + self.logger.debug(f"Full user info: {user}") + self.logger.highlight(f"{self.domain}\\{user['name']:<30} {user['last_pw_set']}\t {user['description']} ") + + +def old_large_int_to_datetime(large_int): + combined = (large_int['HighPart'] << 32) | large_int['LowPart'] + timestamp_seconds = combined / 10**7 + start_date = datetime(1601, 1, 1) + actual_date = (start_date + timedelta(seconds=timestamp_seconds)).replace(microsecond=0) + return actual_date \ No newline at end of file From 60f17856080f2ffad4837205874f5a379d5fe018 Mon Sep 17 00:00:00 2001 From: Marshall Hallenbeck Date: Wed, 20 Mar 2024 18:03:28 -0400 Subject: [PATCH 2/9] ruff: apply ruff --- nxc/protocols/smb/samruser.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/nxc/protocols/smb/samruser.py b/nxc/protocols/smb/samruser.py index 3ed5f5c3..2f28b7da 100644 --- a/nxc/protocols/smb/samruser.py +++ b/nxc/protocols/smb/samruser.py @@ -126,7 +126,7 @@ class UserSamrDump: enumerationContext = 0 while status == STATUS_MORE_ENTRIES: try: - enumerate_users_resp = samr.hSamrEnumerateUsersInDomain(self.dce,domain_handle,enumerationContext=enumerationContext) + enumerate_users_resp = samr.hSamrEnumerateUsersInDomain(self.dce, domain_handle, enumerationContext=enumerationContext) except DCERPCException as e: if str(e).find("STATUS_MORE_ENTRIES") < 0: self.logger.fail("Error enumerating domain user(s)") @@ -171,15 +171,14 @@ class UserSamrDump: return users def print_user_info(self, users): - self.logger.highlight(f"{'Username':<42} {'Last PW Set':<20}\t {'Description'}") # header + self.logger.highlight(f"{'Username':<42} {'Last PW Set':<20}\t {'Description'}") # header for user in users: self.logger.debug(f"Full user info: {user}") self.logger.highlight(f"{self.domain}\\{user['name']:<30} {user['last_pw_set']}\t {user['description']} ") def old_large_int_to_datetime(large_int): - combined = (large_int['HighPart'] << 32) | large_int['LowPart'] + combined = (large_int["HighPart"] << 32) | large_int["LowPart"] timestamp_seconds = combined / 10**7 start_date = datetime(1601, 1, 1) - actual_date = (start_date + timedelta(seconds=timestamp_seconds)).replace(microsecond=0) - return actual_date \ No newline at end of file + return (start_date + timedelta(seconds=timestamp_seconds)).replace(microsecond=0) From 2a66f3636478f8775aae9974bd40c4f3441c0c67 Mon Sep 17 00:00:00 2001 From: Marshall Hallenbeck Date: Wed, 20 Mar 2024 21:57:39 -0400 Subject: [PATCH 3/9] fix(users): remove domain from output, since it's implied, and set timestamp to for last set password date if it should be --- nxc/protocols/smb/samruser.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nxc/protocols/smb/samruser.py b/nxc/protocols/smb/samruser.py index 2f28b7da..debf6c94 100644 --- a/nxc/protocols/smb/samruser.py +++ b/nxc/protocols/smb/samruser.py @@ -165,20 +165,22 @@ class UserSamrDump: user_name = user_info["UserName"] user_description = user_info["AdminComment"] last_pw_set = old_large_int_to_datetime(user_info["PasswordLastSet"]) + if last_pw_set == "1601-01-01 00:00:00": + last_pw_set = "" users.append({"name": user_name, "description": user_description, "last_pw_set": last_pw_set}) samr.hSamrCloseHandle(self.dce, open_user_resp["UserHandle"]) return users def print_user_info(self, users): - self.logger.highlight(f"{'Username':<42} {'Last PW Set':<20}\t {'Description'}") # header + self.logger.highlight(f"{'Username':<30} {'Last PW Set':<20}\t{'Description'}") # header for user in users: self.logger.debug(f"Full user info: {user}") - self.logger.highlight(f"{self.domain}\\{user['name']:<30} {user['last_pw_set']}\t {user['description']} ") + self.logger.highlight(f"{user['name']:<30} {user['last_pw_set']:<20}\t{user['description']} ") def old_large_int_to_datetime(large_int): combined = (large_int["HighPart"] << 32) | large_int["LowPart"] timestamp_seconds = combined / 10**7 start_date = datetime(1601, 1, 1) - return (start_date + timedelta(seconds=timestamp_seconds)).replace(microsecond=0) + return (start_date + timedelta(seconds=timestamp_seconds)).replace(microsecond=0).strftime("%Y-%m-%d %H:%M:%S") From 54e6ebb017ca1878af412d410784571fa0556d5d Mon Sep 17 00:00:00 2001 From: Marshall Hallenbeck Date: Thu, 21 Mar 2024 17:42:05 -0400 Subject: [PATCH 4/9] samruser: clean auth line up --- nxc/protocols/smb/samruser.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/nxc/protocols/smb/samruser.py b/nxc/protocols/smb/samruser.py index debf6c94..dc005c7d 100644 --- a/nxc/protocols/smb/samruser.py +++ b/nxc/protocols/smb/samruser.py @@ -46,20 +46,11 @@ class UserSamrDump: protodef = UserSamrDump.KNOWN_PROTOCOLS[protocol] port = protodef[1] except KeyError: - self.logger.debug(f"Invalid Protocol '{protocol}'") + self.logger.debug(f"Invalid Protocol: {protocol}") + self.logger.debug(f"Trying protocol {protocol}") - self.rpc_transport = transport.SMBTransport( - self.addr, - port, - r"\samr", - self.username, - self.password, - self.domain, - self.lmhash, - self.nthash, - self.aesKey, - doKerberos=self.doKerberos, - ) + self.rpc_transport = transport.SMBTransport(self.addr, port, r"\samr", self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, doKerberos=self.doKerberos) + try: self.fetch_users(requested_users) break From 9a915f0f248bcd72635096c427a5438828a6a915 Mon Sep 17 00:00:00 2001 From: Marshall Hallenbeck Date: Thu, 21 Mar 2024 18:12:40 -0400 Subject: [PATCH 5/9] fix/feat(samruser): add back in bad password count to --users; closes #219 --- nxc/protocols/smb/samruser.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/nxc/protocols/smb/samruser.py b/nxc/protocols/smb/samruser.py index dc005c7d..89de1d5f 100644 --- a/nxc/protocols/smb/samruser.py +++ b/nxc/protocols/smb/samruser.py @@ -154,20 +154,21 @@ class UserSamrDump: user_info = info_user_resp["All"] user_name = user_info["UserName"] + bad_pwd_count = user_info["BadPasswordCount"] user_description = user_info["AdminComment"] last_pw_set = old_large_int_to_datetime(user_info["PasswordLastSet"]) if last_pw_set == "1601-01-01 00:00:00": last_pw_set = "" - users.append({"name": user_name, "description": user_description, "last_pw_set": last_pw_set}) + users.append({"name": user_name, "description": user_description, "bad_pwd_count": bad_pwd_count, "last_pw_set": last_pw_set}) samr.hSamrCloseHandle(self.dce, open_user_resp["UserHandle"]) return users def print_user_info(self, users): - self.logger.highlight(f"{'Username':<30} {'Last PW Set':<20}\t{'Description'}") # header + self.logger.highlight(f"{'Username':<30} {'Last PW Set':<20} {'Bad PW #'} {'Description'}") # header for user in users: self.logger.debug(f"Full user info: {user}") - self.logger.highlight(f"{user['name']:<30} {user['last_pw_set']:<20}\t{user['description']} ") + self.logger.highlight(f"{user['name']:<30} {user['last_pw_set']:<20} {user['bad_pwd_count']:<8} {user['description']} ") def old_large_int_to_datetime(large_int): From 3c1927afd757009e0288bada7bf7e462e1131da8 Mon Sep 17 00:00:00 2001 From: Marshall Hallenbeck Date: Thu, 21 Mar 2024 18:16:09 -0400 Subject: [PATCH 6/9] fix: modules with a name between 8 and 10 length were being erroneously cut off --- nxc/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nxc/logger.py b/nxc/logger.py index e3f95fe7..688142ab 100755 --- a/nxc/logger.py +++ b/nxc/logger.py @@ -40,7 +40,7 @@ class NXCAdapter(logging.LoggerAdapter): if self.extra is None: return f"{msg}", kwargs - if "module_name" in self.extra and len(self.extra["module_name"]) > 8: + if "module_name" in self.extra and len(self.extra["module_name"]) > 11: self.extra["module_name"] = self.extra["module_name"][:8] + "..." # If the logger is being called when hooking the 'options' module function From 590a4e25363be94081f721baaa12e99a5cd658c1 Mon Sep 17 00:00:00 2001 From: Marshall Hallenbeck Date: Thu, 21 Mar 2024 18:20:18 -0400 Subject: [PATCH 7/9] format(logger): fix some newlining stuff that got messed up during old black formatting --- nxc/logger.py | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/nxc/logger.py b/nxc/logger.py index 688142ab..5c0f40d6 100755 --- a/nxc/logger.py +++ b/nxc/logger.py @@ -16,13 +16,11 @@ class NXCAdapter(logging.LoggerAdapter): logging.basicConfig( format="%(message)s", datefmt="[%X]", - handlers=[ - RichHandler( - console=nxc_console, - rich_tracebacks=True, - tracebacks_show_locals=False, - ) - ], + handlers=[RichHandler( + console=nxc_console, + rich_tracebacks=True, + tracebacks_show_locals=False + )], ) self.logger = logging.getLogger("nxc") self.extra = extra @@ -45,25 +43,16 @@ class NXCAdapter(logging.LoggerAdapter): # If the logger is being called when hooking the 'options' module function if len(self.extra) == 1 and ("module_name" in self.extra): - return ( - f"{colored(self.extra['module_name'], 'cyan', attrs=['bold']):<64} {msg}", - kwargs, - ) + return (f"{colored(self.extra['module_name'], 'cyan', attrs=['bold']):<64} {msg}", kwargs) # If the logger is being called from nxcServer if len(self.extra) == 2 and ("module_name" in self.extra) and ("host" in self.extra): - return ( - f"{colored(self.extra['module_name'], 'cyan', attrs=['bold']):<24} {self.extra['host']:<39} {msg}", - kwargs, - ) + return (f"{colored(self.extra['module_name'], 'cyan', attrs=['bold']):<24} {self.extra['host']:<39} {msg}", kwargs) # If the logger is being called from a protocol module_name = colored(self.extra["module_name"], "cyan", attrs=["bold"]) if "module_name" in self.extra else colored(self.extra["protocol"], "blue", attrs=["bold"]) - return ( - f"{module_name:<24} {self.extra['host']:<15} {self.extra['port']:<6} {self.extra['hostname'] if self.extra['hostname'] else 'NONE':<16} {msg}", - kwargs, - ) + return (f"{module_name:<24} {self.extra['host']:<15} {self.extra['port']:<6} {self.extra['hostname'] if self.extra['hostname'] else 'NONE':<16} {msg}", kwargs) def display(self, msg, *args, **kwargs): """Display text to console, formatted for nxc""" @@ -104,17 +93,7 @@ class NXCAdapter(logging.LoggerAdapter): if len(self.logger.handlers): try: for handler in self.logger.handlers: - handler.handle( - LogRecord( - "nxc", - 20, - "", - kwargs, - msg=text, - args=args, - exc_info=None, - ) - ) + handler.handle(LogRecord("nxc", 20, "", kwargs, msg=text, args=args, exc_info=None)) except Exception as e: self.logger.fail(f"Issue while trying to custom print handler: {e}") else: From 1e68591742992c7a28f1ec0550b4931334ee47fd Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Thu, 21 Mar 2024 23:49:35 +0100 Subject: [PATCH 8/9] Formating --- nxc/protocols/smb/samruser.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/nxc/protocols/smb/samruser.py b/nxc/protocols/smb/samruser.py index 89de1d5f..ec86bfc7 100644 --- a/nxc/protocols/smb/samruser.py +++ b/nxc/protocols/smb/samruser.py @@ -47,10 +47,10 @@ class UserSamrDump: port = protodef[1] except KeyError: self.logger.debug(f"Invalid Protocol: {protocol}") - + self.logger.debug(f"Trying protocol {protocol}") self.rpc_transport = transport.SMBTransport(self.addr, port, r"\samr", self.username, self.password, self.domain, self.lmhash, self.nthash, self.aesKey, doKerberos=self.doKerberos) - + try: self.fetch_users(requested_users) break @@ -123,11 +123,11 @@ class UserSamrDump: self.logger.fail("Error enumerating domain user(s)") break enumerate_users_resp = e.get_packet() - + rids = [r["RelativeId"] for r in enumerate_users_resp["Buffer"]["Buffer"]] self.logger.debug(f"Full domain RIDs retrieved: {rids}") users = self.get_user_info(domain_handle, rids) - + # set these for the while loop enumerationContext = enumerate_users_resp["EnumerationContext"] status = enumerate_users_resp["ErrorCode"] @@ -139,11 +139,11 @@ class UserSamrDump: users = [] for user in user_ids: - self.logger.debug(f"Calling hSamrOpenUser for RID {user}") + self.logger.debug(f"Calling hSamrOpenUser for RID {user}") open_user_resp = samr.hSamrOpenUser( self.dce, - domain_handle, - samr.MAXIMUM_ALLOWED, + domain_handle, + samr.MAXIMUM_ALLOWED, user ) info_user_resp = samr.hSamrQueryInformationUser2( @@ -151,7 +151,7 @@ class UserSamrDump: open_user_resp["UserHandle"], samr.USER_INFORMATION_CLASS.UserAllInformation )["Buffer"] - + user_info = info_user_resp["All"] user_name = user_info["UserName"] bad_pwd_count = user_info["BadPasswordCount"] @@ -160,10 +160,10 @@ class UserSamrDump: if last_pw_set == "1601-01-01 00:00:00": last_pw_set = "" users.append({"name": user_name, "description": user_description, "bad_pwd_count": bad_pwd_count, "last_pw_set": last_pw_set}) - + samr.hSamrCloseHandle(self.dce, open_user_resp["UserHandle"]) return users - + def print_user_info(self, users): self.logger.highlight(f"{'Username':<30} {'Last PW Set':<20} {'Bad PW #'} {'Description'}") # header for user in users: From 020ec1758c058ed605bbc0ba6ad0e9fa069e94d3 Mon Sep 17 00:00:00 2001 From: Marshall Hallenbeck Date: Thu, 21 Mar 2024 19:43:00 -0400 Subject: [PATCH 9/9] samruser: update --user output header --- nxc/protocols/smb/samruser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nxc/protocols/smb/samruser.py b/nxc/protocols/smb/samruser.py index ec86bfc7..1eec1828 100644 --- a/nxc/protocols/smb/samruser.py +++ b/nxc/protocols/smb/samruser.py @@ -165,10 +165,10 @@ class UserSamrDump: return users def print_user_info(self, users): - self.logger.highlight(f"{'Username':<30} {'Last PW Set':<20} {'Bad PW #'} {'Description'}") # header + self.logger.highlight(f"{'-Username-':<30}{'-Last PW Set-':<20}{'-BadPW-':<8}{'-Description-':<60}") for user in users: self.logger.debug(f"Full user info: {user}") - self.logger.highlight(f"{user['name']:<30} {user['last_pw_set']:<20} {user['bad_pwd_count']:<8} {user['description']} ") + self.logger.highlight(f"{user['name']:<30}{user['last_pw_set']:<20}{user['bad_pwd_count']:<8}{user['description']} ") def old_large_int_to_datetime(large_int):