From 5143b350c9f5103e7e19b3d78e1101943e28a527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordan=20Ovr=C3=A8?= Date: Thu, 10 Oct 2024 11:15:50 +0200 Subject: [PATCH 1/2] Adding exclusion logic for find method --- smbclientng/core/SMBSession.py | 35 +++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/smbclientng/core/SMBSession.py b/smbclientng/core/SMBSession.py index 019af58..784d3ca 100644 --- a/smbclientng/core/SMBSession.py +++ b/smbclientng/core/SMBSession.py @@ -238,7 +238,7 @@ def ping_smb_session(self): # Operations - def find(self, paths=[], callback=None): + def find(self, paths=[], callback=None, excluded_dirs=[], exclude_dir_depth=0): """ Finds files and directories on the SMB share based on the provided paths and executes a callback function on each entry. @@ -250,6 +250,7 @@ def find(self, paths=[], callback=None): paths (list, optional): A list of paths to start the search from. Defaults to an empty list. callback (function, optional): A function to be called on each entry found. The function should accept three arguments: the entry object, the full path of the entry, and the current depth of recursion. Defaults to None. + excluded_dirs (list, optional): A list of directories to exclude from the search. Defaults to None. Note: If the callback function is None, the method will print an error message and return without performing any action. @@ -262,32 +263,44 @@ def recurse_action(paths=[], depth=0, callback=None): next_directories_to_explore = [] for path in paths: + normalized_path = ntpath.normpath(path) + # Exclude paths that are in the exclude list based on depth + if exclude_dir_depth == -1 or depth == exclude_dir_depth: + if any(excluded.lower() == ntpath.basename(normalized_path).lower() for excluded in excluded_dirs): + continue # Skip this path + remote_smb_path = ntpath.normpath(self.smb_cwd + ntpath.sep + path) entries = [] - + try: entries = self.smbClient.listPath( - shareName=self.smb_share, + shareName=self.smb_share, path=(remote_smb_path + ntpath.sep + '*') ) except impacket.smbconnection.SessionError as err: - continue + continue # Remove dot names entries = [e for e in entries if e.get_longname() not in [".", ".."]] # Sort the entries ignoring case - entries = sorted(entries, key=lambda x:x.get_longname().lower()) - + entries = sorted(entries, key=lambda x: x.get_longname().lower()) + for entry in entries: + fullpath = ntpath.join(path, entry.get_longname()) + if entry.is_directory(): - fullpath = path + ntpath.sep + entry.get_longname() + ntpath.sep + # Exclude directories during traversal based on exclude_dir_depth + if exclude_dir_depth == -1 or depth + 1 == exclude_dir_depth: + if any(excluded.lower() == entry.get_longname().lower() for excluded in excluded_dirs): + continue # Skip this directory + next_directories_to_explore.append(fullpath) - else: - fullpath = path + ntpath.sep + entry.get_longname() + + # Process the entry fullpath = re.sub(r'\\\\+', r'\\', fullpath) callback(entry, fullpath, depth) - + return next_directories_to_explore - # + if callback is not None: depth = 0 while len(paths) != 0: From 6dcd51fd0c3d0cbc0ca4c71f5b6fc42ed61873d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordan=20Ovr=C3=A8?= Date: Thu, 10 Oct 2024 11:18:52 +0200 Subject: [PATCH 2/2] Adding directory exclusion logic --- smbclientng/modules/Find.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/smbclientng/modules/Find.py b/smbclientng/modules/Find.py index a7ae1eb..4be2770 100644 --- a/smbclientng/modules/Find.py +++ b/smbclientng/modules/Find.py @@ -47,10 +47,12 @@ def parseArgs(self, arguments): parser.add_argument("-iname", type=str, help="Like -name, but the match is case insensitive.") parser.add_argument("-type", type=str, default=None, help="File type (e.g., f for regular file, d for directory).") parser.add_argument("-size", type=str, help="File uses n units of space.") + parser.add_argument("-exclude-dir", type=str, action='append', default=[], help="Subdirectories to exclude from the search.") + parser.add_argument("-exclude-dir-depth", type=int, default=0, help="Specify the depth at which to exclude directories. Use -1 to exclude directories at all levels. Default is 0 (initial level only).") # parser.add_argument("-mtime", type=str, help="File's data was last modified n*24 hours ago") # parser.add_argument("-ctime", type=str, help="File's status was last changed n*24 hours ago") # parser.add_argument("-atime", type=str, help="File was last accessed n*24 hours ago") - + # Adding actions parser.add_argument("-ls", action="store_true", default=False, help="List current file in ls -dils format on standard output.") parser.add_argument("-download", action="store_true", default=False, help="List current file in ls -dils format on standard output.") @@ -93,7 +95,7 @@ def __find_callback(self, entry, fullpath, depth): if self.options.maxdepth is not None: if depth > self.options.maxdepth: do_print_results = False - + if do_print_results: do_print_entry = False # Print directory @@ -102,7 +104,7 @@ def __find_callback(self, entry, fullpath, depth): # No name filtering if self.options.name is None and self.options.iname is None: do_print_entry = True - + # Filtering on names case sensitive elif self.options.name is not None: if '*' in self.options.name: @@ -130,7 +132,7 @@ def __find_callback(self, entry, fullpath, depth): do_print_entry = False else: do_print_entry = (entry.get_longname().lower() == self.options.iname.lower()) - + # Print file else: if (self.options.type == 'f' or self.options.type is None): @@ -175,7 +177,7 @@ def __find_callback(self, entry, fullpath, depth): size = int(size_filter[1:-1]) units = ["B","K","M","G","T"] if size_filter[-1].upper() in units: - size = size * (1024**units.index(size_filter[-1])) + size = size * (1024 ** units.index(size_filter[-1])) else: pass @@ -203,7 +205,7 @@ def __find_callback(self, entry, fullpath, depth): output_str = ("%s" % fullpath.replace(ntpath.sep, '/')) else: output_str = ("%s" % fullpath.replace(ntpath.sep, '/')) - + if self.options.outputfile is not None: with open(self.options.outputfile, 'a') as f: f.write(output_str + '\n') @@ -240,16 +242,15 @@ def run(self, arguments): for path in list(set(self.options.paths)): next_directories_to_explore.append(ntpath.normpath(path) + ntpath.sep) next_directories_to_explore = sorted(list(set(next_directories_to_explore))) - + self.smbSession.find( paths=next_directories_to_explore, - callback=self.__find_callback + callback=self.__find_callback, + excluded_dirs=self.options.exclude_dir, + exclude_dir_depth=self.options.exclude_dir_depth ) except (BrokenPipeError, KeyboardInterrupt) as e: print("[!] Interrupted.") self.smbSession.close_smb_session() self.smbSession.init_smb_session() - - -