diff --git a/smbclientng/core/CommandCompleter.py b/smbclientng/core/CommandCompleter.py index 250a8ef..e3004d2 100644 --- a/smbclientng/core/CommandCompleter.py +++ b/smbclientng/core/CommandCompleter.py @@ -255,7 +255,7 @@ class CommandCompleter(object): "Lists the SMB shares served by the remote machine.", "Syntax: 'shares'" ], - "subcommands": [] + "subcommands": ["rights"] }, "tree": { "description": [ diff --git a/smbclientng/core/InteractiveShell.py b/smbclientng/core/InteractiveShell.py index e719ff8..9a0e275 100644 --- a/smbclientng/core/InteractiveShell.py +++ b/smbclientng/core/InteractiveShell.py @@ -825,21 +825,53 @@ def command_shares(self, arguments, command): # Active SMB connection needed : Yes # SMB share needed : No + do_check_rights = False + if len(arguments) != 0: + if arguments[0] == "rights": + do_check_rights = True + shares = self.smbSession.list_shares() if len(shares.keys()) != 0: table = Table(title=None) table.add_column("Share") - table.add_column("Hidden") + table.add_column("Visibility") table.add_column("Type") table.add_column("Description", justify="left") + if do_check_rights: + table.add_column("Rights") for sharename in sorted(shares.keys()): - is_hidden = bool(sharename.endswith('$')) types = ', '.join([s.replace("STYPE_","") for s in shares[sharename]["type"]]) + + is_hidden = bool(sharename.endswith('$')) if is_hidden: - table.add_row(shares[sharename]["name"], str(is_hidden), types, shares[sharename]["comment"]) + str_hidden = "[bold bright_blue]Hidden[/bold bright_blue]" + str_sharename = "[bold bright_blue]" + shares[sharename]["name"] + "[/bold bright_blue]" + str_types = "[bold bright_blue]" + types + "[/bold bright_blue]" + str_comment = "[bold bright_blue]" + shares[sharename]["comment"] + "[/bold bright_blue]" + else: + str_hidden = "[bold bright_yellow]Visible[/bold bright_yellow]" + str_sharename = "[bold bright_yellow]" + shares[sharename]["name"] + "[/bold bright_yellow]" + str_types = "[bold bright_yellow]" + types + "[/bold bright_yellow]" + str_comment = "[bold bright_yellow]" + shares[sharename]["comment"] + "[/bold bright_yellow]" + + if do_check_rights: + access_rights = self.smbSession.test_rights(sharename=shares[sharename]["name"]) + str_access_rights = "[bold yellow]NO ACCESS[/bold yellow]" + if access_rights["readable"] and access_rights["writable"]: + str_access_rights = "[bold green]READ[/bold green], [bold red]WRITE[/bold red]" + elif access_rights["readable"]: + str_access_rights = "[bold green]READ[/bold green]" + elif access_rights["writable"]: + # Without READ?? This should not happen IMHO + str_access_rights = "[bold red]WRITE[/bold red]" + else: + str_access_rights = "[bold yellow]NO ACCESS[/bold yellow]" + + if do_check_rights: + table.add_row(str_sharename, str_hidden, str_types, str_comment, str_access_rights) else: - table.add_row(shares[sharename]["name"], str(is_hidden), types, shares[sharename]["comment"]) + table.add_row(str_sharename, str_hidden, str_types, str_comment) Console().print(table) else: diff --git a/smbclientng/core/SMBSession.py b/smbclientng/core/SMBSession.py index 8cc732b..dde4f75 100644 --- a/smbclientng/core/SMBSession.py +++ b/smbclientng/core/SMBSession.py @@ -9,6 +9,7 @@ import impacket.smbconnection import ntpath import os +import random import re import sys import traceback @@ -1041,6 +1042,44 @@ def umount(self, local_mount_point): else: print("[!] Cannot unmount a non existing path.") + # Other functions + + def test_rights(self, sharename): + """ + Tests the read and write access rights of the current SMB session. + + This method checks the read and write access rights of the current SMB session by attempting to list paths and create/delete temporary directories. + + Returns: + dict: A dictionary containing the read and write access rights status. + - "readable" (bool): Indicates if the session has read access rights. + - "writable" (bool): Indicates if the session has write access rights. + """ + + # Restore the current share + current_share = self.smb_share + self.set_share(shareName=sharename) + + access_rights = {"readable": False, "writable": False} + try: + self.smbClient.listPath(self.smb_share, '*', password=None) + access_rights["readable"] = True + except impacket.smbconnection.SessionError as e: + access_rights["readable"] = False + + try: + temp_dir = ntpath.normpath("\\" + ''.join([random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ0123456759") for k in range(16)])) + self.smbClient.createDirectory(self.smb_share, temp_dir) + self.smbClient.deleteDirectory(self.smb_share, temp_dir) + access_rights["writable"] = True + except impacket.smbconnection.SessionError as e: + access_rights["writable"] = False + + # Restore the current share + self.set_share(shareName=current_share) + + return access_rights + # Setter / Getter def set_share(self, shareName): @@ -1066,7 +1105,9 @@ def set_share(self, shareName): self.smb_tree_id = self.smbClient.connectTree(self.smb_share) else: print("[!] Could not set share '%s', it does not exist remotely." % shareName) - + else: + self.smb_share = None + def set_cwd(self, path=None): """ Sets the current working directory on the SMB share to the specified path.