From c3f10eff87e1c01a57582a91c37d7ff9b4176aad Mon Sep 17 00:00:00 2001 From: y0no Date: Wed, 16 Oct 2024 18:02:13 +0200 Subject: [PATCH 1/4] Add --enum-shares options to SMB protocol --- nxc/protocols/smb.py | 61 ++++++++++++++++++++++++++++++++- nxc/protocols/smb/proto_args.py | 1 + 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index f404c305..076200cf 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -60,7 +60,7 @@ from dploot.triage.sccm import SCCMTriage from pywerview.cli.helpers import get_localdisks, get_netsession, get_netgroupmember, get_netgroup, get_netcomputer, get_netloggedon, get_netlocalgroup -from time import time +from time import time, ctime from datetime import datetime from functools import wraps from traceback import format_exc @@ -903,6 +903,65 @@ class smb(connection): self.logger.highlight(f"{name:<15} {','.join(perms):<15} {remark}") return permissions + + def enum_shares(self): + try: + shares = self.conn.listShares() + self.logger.info(f"Shares returned: {shares}") + except SessionError as e: + error = get_error_string(e) + self.logger.fail( + f"Error enumerating shares: {error}", + color="magenta" if error in smb_error_status else "red", + ) + return + except Exception as e: + error = get_error_string(e) + self.logger.fail( + f"Error enumerating shares: {error}", + color="magenta" if error in smb_error_status else "red", + ) + return + + self.logger.display("Enumerating SMB Shares Directories") + for share in shares: + share_name = share["shi1_netname"][:-1] + depth = 1 + contents = self.conn.listPath(share_name, "*") + + self.logger.success(share_name) + + if contents and depth == 1: + self.logger.highlight(f"{'Perms':<9}{'File Size':<15}{'Date':<30}{'File Path':<45}") + self.logger.highlight(f"{'-----':<9}{'---------':<15}{'----':<30}{'---------':<45}") + self.list_share(share_name, "") + + + def list_share(self, share_name, path_dir, depth=1): + search_path = ntpath.join(path_dir, "*") + + try: + contents = self.conn.listPath(share_name, search_path) + except SessionError as e: + error = get_error_string(e) + self.logger.fail( + f"Error enumerating '{search_path}': {error}", + color="magenta" if error in smb_error_status else "red", + ) + return + + for content in contents: + path_name = content.get_longname() + full_path = ntpath.join(path_dir, path_name) + + if path_name in [".", ".."]: + continue + + if path_name != path_dir: + self.logger.highlight(f"{'d' if content.is_directory() else 'f'}{'rw-' if content.is_readonly() > 0 else 'r--':<8}{content.get_filesize():<15}{ctime(float(content.get_mtime_epoch())):<30}{full_path:<45}") + if content.is_directory() and depth < self.args.enum_shares and path_name not in [ ".", ".."]: + self.list_share(share_name, full_path, depth+1) + @requires_admin def interfaces(self): """ diff --git a/nxc/protocols/smb/proto_args.py b/nxc/protocols/smb/proto_args.py index 35dd8fe2..77f09e51 100644 --- a/nxc/protocols/smb/proto_args.py +++ b/nxc/protocols/smb/proto_args.py @@ -34,6 +34,7 @@ def proto_args(parser, parents): mapping_enum_group = smb_parser.add_argument_group("Mapping/Enumeration", "Options for Mapping/Enumerating") mapping_enum_group.add_argument("--shares", action="store_true", help="enumerate shares and access") + mapping_enum_group.add_argument("--enum-shares", nargs="?", type=int, const=3, help="Authenticate and enumerate exposed shares recursively (default depth: %(const)s)") mapping_enum_group.add_argument("--interfaces", action="store_true", help="enumerate network interfaces") mapping_enum_group.add_argument("--no-write-check", action="store_true", help="Skip write check on shares (avoid leaving traces when missing delete permissions)") mapping_enum_group.add_argument("--filter-shares", nargs="+", help="Filter share by access, option 'read' 'write' or 'read,write'") From 2bf95cc899715dbfb432db563ae86cc6cf712f1f Mon Sep 17 00:00:00 2001 From: y0no Date: Sat, 19 Oct 2024 11:24:38 +0200 Subject: [PATCH 2/4] Move from --enum-share to --dir --- nxc/protocols/smb.py | 61 ++++++++------------------------- nxc/protocols/smb/proto_args.py | 2 +- 2 files changed, 16 insertions(+), 47 deletions(-) diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index 076200cf..f1069962 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -904,44 +904,15 @@ class smb(connection): return permissions - def enum_shares(self): - try: - shares = self.conn.listShares() - self.logger.info(f"Shares returned: {shares}") - except SessionError as e: - error = get_error_string(e) - self.logger.fail( - f"Error enumerating shares: {error}", - color="magenta" if error in smb_error_status else "red", - ) + def dir(self): + # Seems defined by default, do we have to keep this check ? + if not self.args.share: + self.logger.error("You must define --share option") return - except Exception as e: - error = get_error_string(e) - self.logger.fail( - f"Error enumerating shares: {error}", - color="magenta" if error in smb_error_status else "red", - ) - return - - self.logger.display("Enumerating SMB Shares Directories") - for share in shares: - share_name = share["shi1_netname"][:-1] - depth = 1 - contents = self.conn.listPath(share_name, "*") - - self.logger.success(share_name) - - if contents and depth == 1: - self.logger.highlight(f"{'Perms':<9}{'File Size':<15}{'Date':<30}{'File Path':<45}") - self.logger.highlight(f"{'-----':<9}{'---------':<15}{'----':<30}{'---------':<45}") - self.list_share(share_name, "") - - - def list_share(self, share_name, path_dir, depth=1): - search_path = ntpath.join(path_dir, "*") - - try: - contents = self.conn.listPath(share_name, search_path) + + search_path = ntpath.join(self.args.dir, "*") + try: + contents = self.conn.listPath(self.args.share, search_path) except SessionError as e: error = get_error_string(e) self.logger.fail( @@ -949,18 +920,16 @@ class smb(connection): color="magenta" if error in smb_error_status else "red", ) return + + if not contents: + return + self.logger.highlight(f"{'Perms':<9}{'File Size':<15}{'Date':<30}{'File Path':<45}") + self.logger.highlight(f"{'-----':<9}{'---------':<15}{'----':<30}{'---------':<45}") for content in contents: - path_name = content.get_longname() - full_path = ntpath.join(path_dir, path_name) + full_path = ntpath.join(self.args.dir, content.get_longname()) + self.logger.highlight(f"{'d' if content.is_directory() else 'f'}{'rw-' if content.is_readonly() > 0 else 'r--':<8}{content.get_filesize():<15}{ctime(float(content.get_mtime_epoch())):<30}{full_path:<45}") - if path_name in [".", ".."]: - continue - - if path_name != path_dir: - self.logger.highlight(f"{'d' if content.is_directory() else 'f'}{'rw-' if content.is_readonly() > 0 else 'r--':<8}{content.get_filesize():<15}{ctime(float(content.get_mtime_epoch())):<30}{full_path:<45}") - if content.is_directory() and depth < self.args.enum_shares and path_name not in [ ".", ".."]: - self.list_share(share_name, full_path, depth+1) @requires_admin def interfaces(self): diff --git a/nxc/protocols/smb/proto_args.py b/nxc/protocols/smb/proto_args.py index 77f09e51..d3af77ae 100644 --- a/nxc/protocols/smb/proto_args.py +++ b/nxc/protocols/smb/proto_args.py @@ -34,7 +34,7 @@ def proto_args(parser, parents): mapping_enum_group = smb_parser.add_argument_group("Mapping/Enumeration", "Options for Mapping/Enumerating") mapping_enum_group.add_argument("--shares", action="store_true", help="enumerate shares and access") - mapping_enum_group.add_argument("--enum-shares", nargs="?", type=int, const=3, help="Authenticate and enumerate exposed shares recursively (default depth: %(const)s)") + mapping_enum_group.add_argument("--dir", nargs="?", type=str, const="", help="List the content of a path (default path: '%(const)s')") mapping_enum_group.add_argument("--interfaces", action="store_true", help="enumerate network interfaces") mapping_enum_group.add_argument("--no-write-check", action="store_true", help="Skip write check on shares (avoid leaving traces when missing delete permissions)") mapping_enum_group.add_argument("--filter-shares", nargs="+", help="Filter share by access, option 'read' 'write' or 'read,write'") From fd378f66756a17ab352b9ba94b78d569208709d2 Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Wed, 6 Nov 2024 06:21:41 -0500 Subject: [PATCH 3/4] Removing unnecessary check --- nxc/protocols/smb.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index f1069962..471bf805 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -905,11 +905,6 @@ class smb(connection): def dir(self): - # Seems defined by default, do we have to keep this check ? - if not self.args.share: - self.logger.error("You must define --share option") - return - search_path = ntpath.join(self.args.dir, "*") try: contents = self.conn.listPath(self.args.share, search_path) From 92c4f014a6ae0de3943fbda01336877428cd1e18 Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Wed, 6 Nov 2024 06:24:36 -0500 Subject: [PATCH 4/4] Add ruff exception for function name "dir" --- nxc/protocols/smb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index 471bf805..fdf7ac35 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -904,7 +904,7 @@ class smb(connection): return permissions - def dir(self): + def dir(self): # noqa: A003 search_path = ntpath.join(self.args.dir, "*") try: contents = self.conn.listPath(self.args.share, search_path)