Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[enhancement] - Find module - Adding directory exclusion logic with depth-based exclusion control #107

Merged
merged 2 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions smbclientng/core/SMBSession.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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.
Expand All @@ -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:
Expand Down
23 changes: 12 additions & 11 deletions smbclientng/modules/Find.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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()



Loading