A class to handle command completion for the smbclient-ng shell.
\n\n
This class provides a command completion feature that suggests possible command names based on the current input.\nIt uses a dictionary to store commands and their descriptions, which helps in providing hints during the command line\ninteraction in the smbclient-ng shell.
\n\n
Attributes:\n smbSession (SMBSession): An instance of SMBSession which maintains the current SMB session.\n commands (dict): A dictionary containing command names as keys and their descriptions and subcommands as values.
\n\n
Methods:\n __init__(self, smbSession): Initializes the CommandCompleter with an SMBSession.
\n"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.__init__", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.__init__", "kind": "function", "doc": "\n", "signature": "(smbSession, config)"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.commands", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.commands", "kind": "variable", "doc": "\n", "default_value": "{'cd': {'description': ['Change the current working directory.', "Syntax: 'cd <directory>'"], 'subcommands': []}, 'close': {'description': ['Closes the SMB connection to the remote machine.', "Syntax: 'close'"], 'subcommands': []}, 'connect': {'description': ['Connect to the remote machine (useful if connection timed out).', "Syntax: 'connect'"], 'subcommands': []}, 'dir': {'description': ['List the contents of the current working directory.', "Syntax: 'dir'"], 'subcommands': []}, 'exit': {'description': ['Exits the smbclient-ng script.', "Syntax: 'exit'"], 'subcommands': []}, 'get': {'description': ['Get a remote file.', "Syntax: 'get [-r] <directory or file>'"], 'subcommands': []}, 'help': {'description': ['Displays this help message.', "Syntax: 'help'"], 'subcommands': ['format']}, 'info': {'description': ['Get information about the server and or the share.', "Syntax: 'info [server|share]'"], 'subcommands': ['server', 'share']}, 'lcd': {'description': ['Changes the current local directory.', "Syntax: 'lcd <directory>'"], 'subcommands': []}, 'lls': {'description': ['Lists the contents of the current local directory.', "Syntax: 'lls'"], 'subcommands': []}, 'lmkdir': {'description': ['Creates a new local directory.', "Syntax: 'lmkdir <directory>'"], 'subcommands': []}, 'lpwd': {'description': ['Shows the current local directory.', "Syntax: 'lpwd'"], 'subcommands': []}, 'lrm': {'description': ['Removes a local file.', "Syntax: 'lrm <file>'"], 'subcommands': []}, 'lrmdir': {'description': ['Removes a local directory.', "Syntax: 'lrmdir <directory>'"], 'subcommands': []}, 'ls': {'description': ['List the contents of the current remote working directory.', "Syntax: 'ls'"], 'subcommands': []}, 'ltree': {'description': ['Displays a tree view of the local directories.', "Syntax: 'ltree [directory]'"], 'subcommands': []}, 'mkdir': {'description': ['Creates a new remote directory.', "Syntax: 'mkdir <directory>'"], 'subcommands': []}, 'module': {'description': ['Loads a specific module for additional functionalities.', "Syntax: 'module <name>'"], 'subcommands': []}, 'put': {'description': ['Put a local file or directory in a remote directory.', "Syntax: 'put [-r] <directory or file>'"], 'subcommands': []}, 'reconnect': {'description': ['Reconnect to the remote machine (useful if connection timed out).', "Syntax: 'reconnect'"], 'subcommands': []}, 'reset': {'description': ['Reset the TTY output, useful if it was broken after printing a binary file on stdout.', "Syntax: 'reset'"], 'subcommands': []}, 'rmdir': {'description': ['Removes a remote directory.', "Syntax: 'rmdir <directory>'"], 'subcommands': []}, 'rm': {'description': ['Removes a remote file.', "Syntax: 'rm <file>'"], 'subcommands': []}, 'shares': {'description': ['Lists the SMB shares served by the remote machine.', "Syntax: 'shares'"], 'subcommands': []}, 'use': {'description': ['Use a SMB share.', "Syntax: 'use <sharename>'"], 'subcommands': []}, 'tree': {'description': ['Displays a tree view of the remote directories.', "Syntax: 'tree [directory]'"], 'subcommands': []}}"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.smbSession", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.smbSession", "kind": "variable", "doc": "\n"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.config", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.config", "kind": "variable", "doc": "\n"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.complete", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.complete", "kind": "function", "doc": "
Function to handle command completion in the LDAP console.
\n\n
This function completes the user\"s input based on the available options for commands in the LDAP console.
\n\n
Args:\n text (str): The current text input by the user.\n state (int): The current state of completion.
\n\n
Returns:\n str: The next completion suggestion based on the user\"s input state.
Prints help information for a specific command or all commands if no command is specified.
\n\n
This method displays the help information for the command passed as an argument. If no command is specified,\nit prints the help information for all available commands. The help information includes the command syntax,\ndescription, and any subcommands associated with it. This method is designed to provide users with the necessary\nguidance on how to use the commands in the smbclient-ng shell.
\n\n
Args:\n command (str, optional): The command to display help information for. If None, help for all commands is displayed.
Prints the help information for the 'format' used in remote 'ls' and 'dir' commands.
\n\n
This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning\nof each character in the file attribute string, such as whether a file is read-only, hidden, or a directory.
This class manages the configuration settings for the smbclientng tool, including debug and color output settings.\nIt provides a structured way to access and modify these settings throughout the application.
\n\n
Attributes:\n _debug (bool): Flag to enable or disable debug mode.\n _no_colors (bool): Flag to enable or disable colored output, depending on the platform.
\n\n
Methods:\n debug: Property to get or set the debug mode.\n no_colors: Property to get or set the colored output preference.
Class InteractiveShell is designed to manage the interactive command line interface for smbclient-ng.
\n\n
This class handles user input, executes commands, and manages the state of the SMB session. It provides\na command line interface for users to interact with SMB shares, execute commands like directory listing,\nfile transfer, and more.
\n\n
Attributes:\n smbSession (SMBConnection): The active SMB connection session.\n debug (bool): Flag to enable or disable debug mode.\n smb_share (str): The current SMB share in use.\n smb_path (str): The current path within the SMB share.\n commandCompleterObject (CommandCompleter): Object to handle command completion and help generation.
\n\n
Methods:\n __init__(self, smbSession, debug=False): Initializes the InteractiveShell with the given SMB session and debug mode.\n run(self): Starts the command line interface loop, processing user input until exit.
Class LocalFileIO is designed to handle local file input/output operations within the smbclient-ng tool.\nIt provides functionalities to open, read, write, and manage progress of file operations based on the expected size of the file.
\n\n
Attributes:\n mode (str): The mode in which the file should be opened (e.g., 'rb', 'wb').\n path (str): The path to the file that needs to be handled.\n expected_size (int, optional): The expected size of the file in bytes. This is used to display progress.\n debug (bool): Flag to enable debug mode which provides additional output during operations.
\n\n
Methods:\n __init__(self, mode, path=None, expected_size=None, debug=False): Initializes the LocalFileIO instance.\n write(self, data): Writes data to the file and updates the progress bar if expected size is provided.\n read(self, size): Reads data from the file up to the specified size and updates the progress bar if expected size is provided.
This method reads data from the file based on the size specified. It also updates the progress bar with the amount of data read if the expected size is set.
\n\n
Args:\n size (int): The number of bytes to read from the file.
Closes the file descriptor and optionally removes the file.
\n\n
This method ensures that the file descriptor is properly closed and the file is removed if specified.\nIt also stops the progress bar if it was initiated and cleans up the object by deleting it.
\n\n
Args:\n remove (bool): If True, the file at the path will be removed after closing the file descriptor.
Sets an error message in the progress bar's description and modifies the progress bar to show only essential columns.
\n\n
This method is used to communicate error states or important messages directly in the progress bar interface.\nIt updates the task description with the provided message and simplifies the progress bar to show only the text\nand download columns, removing other elements like speed and time remaining which may not be relevant in an error state.
\n\n
Args:\n message (str): The error or status message to display in the progress bar.
A custom argument parser for handling module-specific command-line arguments in the smbclientng application.
\n\n
This class extends the argparse.ArgumentParser and provides custom error handling specific to the needs of smbclientng modules.\nIt is designed to provide clear and user-friendly command-line interfaces for various modules within the smbclientng suite.
\n\n
Attributes:\n None
\n\n
Methods:\n error(message: str):\n Overrides the default error handling to provide a more informative error message and display the help text.
Overrides the default error handling of argparse.ArgumentParser to provide a custom error message and help display.
\n\n
This method is called when ArgumentParser encounters an error. It writes the error message to stderr,\ndisplays the help message, and then exits the program with a status code of 2.
\n\n
Args:\n message (str): The error message to be displayed.
Class SMBSession is designed to handle the session management for SMB (Server Message Block) protocol connections.\nIt provides functionalities to connect to an SMB server, authenticate using either NTLM or Kerberos, and manage SMB shares.
\n\n
Attributes:\n address (str): The IP address or hostname of the SMB server.\n domain (str): The domain name for SMB server authentication.\n username (str): The username for SMB server authentication.\n password (str): The password for SMB server authentication.\n lmhash (str): The LM hash of the user's password, if available.\n nthash (str): The NT hash of the user's password, if available.\n use_kerberos (bool): A flag to determine whether to use Kerberos for authentication.\n kdcHost (str): The Key Distribution Center (KDC) host for Kerberos authentication.\n debug (bool): A flag to enable debug output.\n smbClient (object): The SMB client object used for the connection.\n connected (bool): A flag to check the status of the connection.\n smb_share (str): The current SMB share in use.\n smb_path (str): The current path within the SMB share.
\n\n
Methods:\n __init__(address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, debug=False):\n Initializes the SMBSession with the specified parameters.\n init_smb_session():\n Initializes the SMB session by connecting to the server and authenticating using the specified method.
Initializes and establishes a session with the SMB server.
\n\n
This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.\nIt attempts to connect to the SMB server specified by the address attribute and authenticate using the credentials provided during the object's initialization.
\n\n
The method will print debug information if the debug attribute is set to True. Upon successful connection and authentication, it sets the connected attribute to True.
\n\n
Returns:\n bool: True if the connection and authentication are successful, False otherwise.
Closes the current SMB session by disconnecting the SMB client.
\n\n
This method ensures that the SMB client connection is properly closed. It checks if the client is connected\nand if so, it closes the connection and resets the connection status.
\n\n
Raises:\n Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
Retrieves a file from the specified path on the SMB share.
\n\n
This method attempts to retrieve a file from the given path within the currently connected SMB share.\nIf the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local\nfile object and writing the contents of the remote file to it using the SMB client's getFile method.
\n\n
Parameters:\n path (str): The path of the file to retrieve. If None, uses the current smb_path.
Recursively retrieves files from a specified path on the SMB share.
\n\n
This method navigates through all directories starting from the given path,\nand downloads all files found. It handles directories recursively, ensuring\nthat all nested files are retrieved. The method skips over directory entries\nand handles errors gracefully, attempting to continue the operation where possible.
\n\n
Parameters:\n path (str): The initial directory path from which to start the recursive file retrieval.\n If None, it starts from the root of the configured SMB share.
Displays information about the server and optionally the shares.
\n\n
This method prints detailed information about the server's characteristics such as NetBIOS names, DNS details, OS information, and SMB capabilities. If the share parameter is set to True and a share is currently set, it will also attempt to display information about the share.
\n\n
Parameters:\n share (bool): If True, display information about the current share.\n server (bool): If True, display information about the server.
Lists the contents of a specified directory on the SMB share.
\n\n
This method retrieves the contents of a directory specified by shareName and path. If shareName or path\nis not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with\nthe long names of the files and directories as keys and their respective SMB entry objects as values.
\n\n
Args:\n shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.\n path (str, optional): The directory path to list contents from. Defaults to the current path if None.
\n\n
Returns:\n dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
Lists all the shares available on the connected SMB server.
\n\n
This method queries the SMB server to retrieve a list of all available shares. It populates the shares dictionary\nwith key-value pairs where the key is the share name and the value is a dictionary containing details about the share\nsuch as its name, type, raw type, and any comments associated with the share.
\n\n
Returns:\n dict: A dictionary containing information about each share available on the server.
Creates a directory at the specified path on the SMB share.
\n\n
This method takes a path and attempts to create the directory structure on the SMB share. If the path includes\nnested directories, it will create each directory in the sequence. If a directory already exists, it will skip\nthe creation for that directory without raising an error.
\n\n
Args:\n path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
\n\n
Note:\n The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
Checks if the specified path exists on the SMB share.
\n\n
This method determines if a given path exists on the SMB share by attempting to list the contents of the path.\nIf the path listing is successful and returns one or more entries, the path is considered to exist.
\n\n
Args:\n path (str, optional): The path to check on the SMB share. Defaults to None.
\n\n
Returns:\n bool: True if the path exists, False otherwise or if an error occurs.
Checks if the specified path is a directory on the SMB share.
\n\n
This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the\ncontents of the path and filtering for entries that match the basename of the path and are marked as directories.
\n\n
Args:\n path (str, optional): The path to check on the SMB share. Defaults to None.
\n\n
Returns:\n bool: True if the path is a directory, False otherwise or if an error occurs.
Checks if the specified path is a file on the SMB share.
\n\n
This method determines if a given path corresponds to a file on the SMB share. It does this by listing the\ncontents of the path and filtering for entries that match the basename of the path and are not marked as directories.
\n\n
Args:\n path (str, optional): The path to check on the SMB share. Defaults to None.
\n\n
Returns:\n bool: True if the path is a file, False otherwise or if an error occurs.
Tests the connectivity to the SMB server by sending an echo command.
\n\n
This method attempts to send an echo command to the SMB server to check if the session is still active.\nIt updates the connected attribute of the class based on the success or failure of the echo command.
\n\n
Returns:\n bool: True if the echo command succeeds (indicating the session is active), False otherwise.
This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.\nIt handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.\nGeneral exceptions are caught and logged, with a traceback provided if debugging is enabled.
\n\n
Args:\n localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
Recursively uploads files from a specified local directory to the SMB share.
\n\n
This method walks through the given local directory and all its subdirectories, uploading each file to the\ncorresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,\nit iterates over all files and directories within the local path, creating necessary directories on the SMB share\nand uploading files. If the local path is not a directory, it prints an error message.
\n\n
Args:\n localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
Removes a directory from the SMB share at the specified path.
\n\n
This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,\nit prints an error message indicating the failure and the reason. If debugging is enabled, it also prints\nthe stack trace of the exception.
\n\n
Args:\n path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
Removes a file from the SMB share at the specified path.
\n\n
This method attempts to delete a file located at the given path on the SMB share. If the operation fails,\nit prints an error message indicating the failure and the reason. If debugging is enabled, it also prints\nthe stack trace of the exception.
\n\n
Args:\n path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
Recursively lists the directory structure of the SMB share starting from the specified path.
\n\n
This function prints a visual representation of the directory tree of the remote SMB share. It uses\nrecursion to navigate through directories and lists all files and subdirectories in each directory.\nThe output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
\n\n
Args:\n path (str, optional): The starting path on the SMB share from which to begin listing the tree.\n Defaults to the root of the current share.
Sets the current SMB share to the specified share name.
\n\n
This method updates the SMB session to use the specified share name. It checks if the share name is valid\nand updates the smb_share attribute of the SMBSession instance.
\n\n
Parameters:\n shareName (str): The name of the share to set as the current SMB share.
\n\n
Raises:\n ValueError: If the shareName is None or an empty string.
Sets the current working directory on the SMB share to the specified path.
\n\n
This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.\nIf the specified path is not a directory, the cwd remains unchanged.
\n\n
Parameters:\n path (str): The path to set as the current working directory.
\n\n
Raises:\n ValueError: If the specified path is not a directory.
Parse the input string containing LM and NT hash values and return them separately.
\n\n
This function takes a string containing LM and NT hash values, typically separated by a colon (:).\nIt returns the LM and NT hash values as separate strings. If only one hash value is provided, it is\nassumed to be the NT hash and the LM hash is set to its default value. If no valid hash values are\nfound, both return values are empty strings.
\n\n
Args:\n lm_nt_hashes_string (str): A string containing LM and NT hash values separated by a colon.
\n\n
Returns:\n tuple: A tuple containing two strings (lm_hash_value, nt_hash_value).\n - lm_hash_value: The LM hash value or its default if not provided.\n - nt_hash_value: The NT hash value or its default if not provided.
Convert a file size from bytes to a more readable format using the largest appropriate unit.
\n\n
This function takes an integer representing a file size in bytes and converts it to a human-readable\nstring using the largest appropriate unit from bytes (B) to petabytes (PB). The result is rounded to\ntwo decimal places.
\n\n
Args:\n l (int): The file size in bytes.
\n\n
Returns:\n str: A string representing the file size in a more readable format, including the appropriate unit.
Generate a string representing the Unix-style permissions for a given file or directory.
\n\n
This function uses the os.lstat() method to retrieve the status of the specified file or directory,\nthen constructs a string that represents the Unix-style permissions based on the mode of the file.
\n\n
Args:\n entryname (str): The path to the file or directory for which permissions are being determined.
\n\n
Returns:\n str: A string of length 10 representing the Unix-style permissions (e.g., '-rwxr-xr--').\n The first character is either 'd' (directory), '-' (not a directory), followed by\n three groups of 'r', 'w', 'x' (read, write, execute permissions) for owner, group,\n and others respectively.
Extracts the share type flags from a given share type value.
\n\n
This function uses bitwise operations to determine which share type flags are set in the provided stype_value.\nIt checks against known share type flags and returns a list of the flags that are set.
\n\n
Parameters:\n stype_value (int): The share type value to analyze, typically obtained from SMB share properties.
\n\n
Returns:\n list: A list of strings, where each string represents a share type flag that is set in the input value.
This function generates a metadata string based on the attributes of the provided entry object.
\n\n
Parameters:\n entry (object): An object representing a file or directory entry.
\n\n
Returns:\n str: A string representing the metadata of the entry, including attributes like directory, archive, compressed, hidden, normal, readonly, system, and temporary.
This function recursively lists the contents of a directory in a tree-like format.
\n\n
Parameters:\n path (str): The path to the directory to list.\n config (object): Configuration settings which may affect the output, such as whether to use colors.
\n\n
Returns:\n None: This function does not return anything but prints the directory tree to the console.
Parses the command line arguments provided to the module.
\n\n
This method initializes the argument parser with the module's name and description, and defines all the necessary arguments that the module accepts. It then parses the provided command line arguments based on these definitions.
\n\n
Args:\n arguments (str): A string of command line arguments.
\n\n
Returns:\n ModuleArgumentParser.Namespace | None: The parsed arguments as a Namespace object if successful, None if there are no arguments or help is requested.
This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
\n\n
Args:\n base_dir (str): The base directory to start the search from.\n paths (list): List of paths to search within the base directory.\n depth (int): The current depth level in the directory hierarchy.
A class to handle command completion for the smbclient-ng shell.
\n\n
This class provides a command completion feature that suggests possible command names based on the current input.\nIt uses a dictionary to store commands and their descriptions, which helps in providing hints during the command line\ninteraction in the smbclient-ng shell.
\n\n
Attributes:\n smbSession (SMBSession): An instance of SMBSession which maintains the current SMB session.\n commands (dict): A dictionary containing command names as keys and their descriptions and subcommands as values.
\n\n
Methods:\n __init__(self, smbSession): Initializes the CommandCompleter with an SMBSession.
\n"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.__init__", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.__init__", "kind": "function", "doc": "\n", "signature": "(smbSession, config)"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.commands", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.commands", "kind": "variable", "doc": "\n", "default_value": "{'bat': {'description': ['Pretty prints the contents of a file.', "Syntax: 'bat <file>'"], 'subcommands': []}, 'cat': {'description': ['Get the contents of a file.', "Syntax: 'cat <file>'"], 'subcommands': []}, 'cd': {'description': ['Change the current working directory.', "Syntax: 'cd <directory>'"], 'subcommands': []}, 'close': {'description': ['Closes the SMB connection to the remote machine.', "Syntax: 'close'"], 'subcommands': []}, 'connect': {'description': ['Connect to the remote machine (useful if connection timed out).', "Syntax: 'connect'"], 'subcommands': []}, 'dir': {'description': ['List the contents of the current working directory.', "Syntax: 'dir'"], 'subcommands': []}, 'exit': {'description': ['Exits the smbclient-ng script.', "Syntax: 'exit'"], 'subcommands': []}, 'get': {'description': ['Get a remote file.', "Syntax: 'get [-r] <directory or file>'"], 'subcommands': []}, 'help': {'description': ['Displays this help message.', "Syntax: 'help'"], 'subcommands': ['format']}, 'info': {'description': ['Get information about the server and or the share.', "Syntax: 'info [server|share]'"], 'subcommands': ['server', 'share']}, 'lcd': {'description': ['Changes the current local directory.', "Syntax: 'lcd <directory>'"], 'subcommands': []}, 'lls': {'description': ['Lists the contents of the current local directory.', "Syntax: 'lls'"], 'subcommands': []}, 'lmkdir': {'description': ['Creates a new local directory.', "Syntax: 'lmkdir <directory>'"], 'subcommands': []}, 'lpwd': {'description': ['Shows the current local directory.', "Syntax: 'lpwd'"], 'subcommands': []}, 'lrm': {'description': ['Removes a local file.', "Syntax: 'lrm <file>'"], 'subcommands': []}, 'lrmdir': {'description': ['Removes a local directory.', "Syntax: 'lrmdir <directory>'"], 'subcommands': []}, 'ls': {'description': ['List the contents of the current remote working directory.', "Syntax: 'ls'"], 'subcommands': []}, 'ltree': {'description': ['Displays a tree view of the local directories.', "Syntax: 'ltree [directory]'"], 'subcommands': []}, 'mkdir': {'description': ['Creates a new remote directory.', "Syntax: 'mkdir <directory>'"], 'subcommands': []}, 'module': {'description': ['Loads a specific module for additional functionalities.', "Syntax: 'module <name>'"], 'subcommands': []}, 'put': {'description': ['Put a local file or directory in a remote directory.', "Syntax: 'put [-r] <directory or file>'"], 'subcommands': []}, 'reconnect': {'description': ['Reconnect to the remote machine (useful if connection timed out).', "Syntax: 'reconnect'"], 'subcommands': []}, 'reset': {'description': ['Reset the TTY output, useful if it was broken after printing a binary file on stdout.', "Syntax: 'reset'"], 'subcommands': []}, 'rmdir': {'description': ['Removes a remote directory.', "Syntax: 'rmdir <directory>'"], 'subcommands': []}, 'rm': {'description': ['Removes a remote file.', "Syntax: 'rm <file>'"], 'subcommands': []}, 'shares': {'description': ['Lists the SMB shares served by the remote machine.', "Syntax: 'shares'"], 'subcommands': []}, 'use': {'description': ['Use a SMB share.', "Syntax: 'use <sharename>'"], 'subcommands': []}, 'tree': {'description': ['Displays a tree view of the remote directories.', "Syntax: 'tree [directory]'"], 'subcommands': []}}"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.smbSession", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.smbSession", "kind": "variable", "doc": "\n"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.config", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.config", "kind": "variable", "doc": "\n"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.complete", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.complete", "kind": "function", "doc": "
Function to handle command completion in the LDAP console.
\n\n
This function completes the user\"s input based on the available options for commands in the LDAP console.
\n\n
Args:\n text (str): The current text input by the user.\n state (int): The current state of completion.
\n\n
Returns:\n str: The next completion suggestion based on the user\"s input state.
Prints help information for a specific command or all commands if no command is specified.
\n\n
This method displays the help information for the command passed as an argument. If no command is specified,\nit prints the help information for all available commands. The help information includes the command syntax,\ndescription, and any subcommands associated with it. This method is designed to provide users with the necessary\nguidance on how to use the commands in the smbclient-ng shell.
\n\n
Args:\n command (str, optional): The command to display help information for. If None, help for all commands is displayed.
Prints the help information for the 'format' used in remote 'ls' and 'dir' commands.
\n\n
This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning\nof each character in the file attribute string, such as whether a file is read-only, hidden, or a directory.
This class manages the configuration settings for the smbclientng tool, including debug and color output settings.\nIt provides a structured way to access and modify these settings throughout the application.
\n\n
Attributes:\n _debug (bool): Flag to enable or disable debug mode.\n _no_colors (bool): Flag to enable or disable colored output, depending on the platform.
\n\n
Methods:\n debug: Property to get or set the debug mode.\n no_colors: Property to get or set the colored output preference.
Class InteractiveShell is designed to manage the interactive command line interface for smbclient-ng.
\n\n
This class handles user input, executes commands, and manages the state of the SMB session. It provides\na command line interface for users to interact with SMB shares, execute commands like directory listing,\nfile transfer, and more.
\n\n
Attributes:\n smbSession (SMBConnection): The active SMB connection session.\n debug (bool): Flag to enable or disable debug mode.\n smb_share (str): The current SMB share in use.\n smb_path (str): The current path within the SMB share.\n commandCompleterObject (CommandCompleter): Object to handle command completion and help generation.
\n\n
Methods:\n __init__(self, smbSession, debug=False): Initializes the InteractiveShell with the given SMB session and debug mode.\n run(self): Starts the command line interface loop, processing user input until exit.
Class LocalFileIO is designed to handle local file input/output operations within the smbclient-ng tool.\nIt provides functionalities to open, read, write, and manage progress of file operations based on the expected size of the file.
\n\n
Attributes:\n mode (str): The mode in which the file should be opened (e.g., 'rb', 'wb').\n path (str): The path to the file that needs to be handled.\n expected_size (int, optional): The expected size of the file in bytes. This is used to display progress.\n debug (bool): Flag to enable debug mode which provides additional output during operations.
\n\n
Methods:\n __init__(self, mode, path=None, expected_size=None, debug=False): Initializes the LocalFileIO instance.\n write(self, data): Writes data to the file and updates the progress bar if expected size is provided.\n read(self, size): Reads data from the file up to the specified size and updates the progress bar if expected size is provided.
This method reads data from the file based on the size specified. It also updates the progress bar with the amount of data read if the expected size is set.
\n\n
Args:\n size (int): The number of bytes to read from the file.
Closes the file descriptor and optionally removes the file.
\n\n
This method ensures that the file descriptor is properly closed and the file is removed if specified.\nIt also stops the progress bar if it was initiated and cleans up the object by deleting it.
\n\n
Args:\n remove (bool): If True, the file at the path will be removed after closing the file descriptor.
Sets an error message in the progress bar's description and modifies the progress bar to show only essential columns.
\n\n
This method is used to communicate error states or important messages directly in the progress bar interface.\nIt updates the task description with the provided message and simplifies the progress bar to show only the text\nand download columns, removing other elements like speed and time remaining which may not be relevant in an error state.
\n\n
Args:\n message (str): The error or status message to display in the progress bar.
A custom argument parser for handling module-specific command-line arguments in the smbclientng application.
\n\n
This class extends the argparse.ArgumentParser and provides custom error handling specific to the needs of smbclientng modules.\nIt is designed to provide clear and user-friendly command-line interfaces for various modules within the smbclientng suite.
\n\n
Attributes:\n None
\n\n
Methods:\n error(message: str):\n Overrides the default error handling to provide a more informative error message and display the help text.
Overrides the default error handling of argparse.ArgumentParser to provide a custom error message and help display.
\n\n
This method is called when ArgumentParser encounters an error. It writes the error message to stderr,\ndisplays the help message, and then exits the program with a status code of 2.
\n\n
Args:\n message (str): The error message to be displayed.
Class SMBSession is designed to handle the session management for SMB (Server Message Block) protocol connections.\nIt provides functionalities to connect to an SMB server, authenticate using either NTLM or Kerberos, and manage SMB shares.
\n\n
Attributes:\n address (str): The IP address or hostname of the SMB server.\n domain (str): The domain name for SMB server authentication.\n username (str): The username for SMB server authentication.\n password (str): The password for SMB server authentication.\n lmhash (str): The LM hash of the user's password, if available.\n nthash (str): The NT hash of the user's password, if available.\n use_kerberos (bool): A flag to determine whether to use Kerberos for authentication.\n kdcHost (str): The Key Distribution Center (KDC) host for Kerberos authentication.\n debug (bool): A flag to enable debug output.\n smbClient (object): The SMB client object used for the connection.\n connected (bool): A flag to check the status of the connection.\n smb_share (str): The current SMB share in use.\n smb_path (str): The current path within the SMB share.
\n\n
Methods:\n __init__(address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, debug=False):\n Initializes the SMBSession with the specified parameters.\n init_smb_session():\n Initializes the SMB session by connecting to the server and authenticating using the specified method.
Initializes and establishes a session with the SMB server.
\n\n
This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.\nIt attempts to connect to the SMB server specified by the address attribute and authenticate using the credentials provided during the object's initialization.
\n\n
The method will print debug information if the debug attribute is set to True. Upon successful connection and authentication, it sets the connected attribute to True.
\n\n
Returns:\n bool: True if the connection and authentication are successful, False otherwise.
Closes the current SMB session by disconnecting the SMB client.
\n\n
This method ensures that the SMB client connection is properly closed. It checks if the client is connected\nand if so, it closes the connection and resets the connection status.
\n\n
Raises:\n Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
Retrieves a file from the specified path on the SMB share.
\n\n
This method attempts to retrieve a file from the given path within the currently connected SMB share.\nIf the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local\nfile object and writing the contents of the remote file to it using the SMB client's getFile method.
\n\n
Parameters:\n path (str): The path of the file to retrieve. If None, uses the current smb_path.
Recursively retrieves files from a specified path on the SMB share.
\n\n
This method navigates through all directories starting from the given path,\nand downloads all files found. It handles directories recursively, ensuring\nthat all nested files are retrieved. The method skips over directory entries\nand handles errors gracefully, attempting to continue the operation where possible.
\n\n
Parameters:\n path (str): The initial directory path from which to start the recursive file retrieval.\n If None, it starts from the root of the configured SMB share.
Displays information about the server and optionally the shares.
\n\n
This method prints detailed information about the server's characteristics such as NetBIOS names, DNS details, OS information, and SMB capabilities. If the share parameter is set to True and a share is currently set, it will also attempt to display information about the share.
\n\n
Parameters:\n share (bool): If True, display information about the current share.\n server (bool): If True, display information about the server.
Lists the contents of a specified directory on the SMB share.
\n\n
This method retrieves the contents of a directory specified by shareName and path. If shareName or path\nis not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with\nthe long names of the files and directories as keys and their respective SMB entry objects as values.
\n\n
Args:\n shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.\n path (str, optional): The directory path to list contents from. Defaults to the current path if None.
\n\n
Returns:\n dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
Lists all the shares available on the connected SMB server.
\n\n
This method queries the SMB server to retrieve a list of all available shares. It populates the shares dictionary\nwith key-value pairs where the key is the share name and the value is a dictionary containing details about the share\nsuch as its name, type, raw type, and any comments associated with the share.
\n\n
Returns:\n dict: A dictionary containing information about each share available on the server.
Creates a directory at the specified path on the SMB share.
\n\n
This method takes a path and attempts to create the directory structure on the SMB share. If the path includes\nnested directories, it will create each directory in the sequence. If a directory already exists, it will skip\nthe creation for that directory without raising an error.
\n\n
Args:\n path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
\n\n
Note:\n The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
Checks if the specified path exists on the SMB share.
\n\n
This method determines if a given path exists on the SMB share by attempting to list the contents of the path.\nIf the path listing is successful and returns one or more entries, the path is considered to exist.
\n\n
Args:\n path (str, optional): The path to check on the SMB share. Defaults to None.
\n\n
Returns:\n bool: True if the path exists, False otherwise or if an error occurs.
Checks if the specified path is a directory on the SMB share.
\n\n
This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the\ncontents of the path and filtering for entries that match the basename of the path and are marked as directories.
\n\n
Args:\n path (str, optional): The path to check on the SMB share. Defaults to None.
\n\n
Returns:\n bool: True if the path is a directory, False otherwise or if an error occurs.
Checks if the specified path is a file on the SMB share.
\n\n
This method determines if a given path corresponds to a file on the SMB share. It does this by listing the\ncontents of the path and filtering for entries that match the basename of the path and are not marked as directories.
\n\n
Args:\n path (str, optional): The path to check on the SMB share. Defaults to None.
\n\n
Returns:\n bool: True if the path is a file, False otherwise or if an error occurs.
Tests the connectivity to the SMB server by sending an echo command.
\n\n
This method attempts to send an echo command to the SMB server to check if the session is still active.\nIt updates the connected attribute of the class based on the success or failure of the echo command.
\n\n
Returns:\n bool: True if the echo command succeeds (indicating the session is active), False otherwise.
This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.\nIt handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.\nGeneral exceptions are caught and logged, with a traceback provided if debugging is enabled.
\n\n
Args:\n localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
Recursively uploads files from a specified local directory to the SMB share.
\n\n
This method walks through the given local directory and all its subdirectories, uploading each file to the\ncorresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,\nit iterates over all files and directories within the local path, creating necessary directories on the SMB share\nand uploading files. If the local path is not a directory, it prints an error message.
\n\n
Args:\n localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
Removes a directory from the SMB share at the specified path.
\n\n
This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,\nit prints an error message indicating the failure and the reason. If debugging is enabled, it also prints\nthe stack trace of the exception.
\n\n
Args:\n path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
Removes a file from the SMB share at the specified path.
\n\n
This method attempts to delete a file located at the given path on the SMB share. If the operation fails,\nit prints an error message indicating the failure and the reason. If debugging is enabled, it also prints\nthe stack trace of the exception.
\n\n
Args:\n path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
Recursively lists the directory structure of the SMB share starting from the specified path.
\n\n
This function prints a visual representation of the directory tree of the remote SMB share. It uses\nrecursion to navigate through directories and lists all files and subdirectories in each directory.\nThe output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
\n\n
Args:\n path (str, optional): The starting path on the SMB share from which to begin listing the tree.\n Defaults to the root of the current share.
Sets the current SMB share to the specified share name.
\n\n
This method updates the SMB session to use the specified share name. It checks if the share name is valid\nand updates the smb_share attribute of the SMBSession instance.
\n\n
Parameters:\n shareName (str): The name of the share to set as the current SMB share.
\n\n
Raises:\n ValueError: If the shareName is None or an empty string.
Sets the current working directory on the SMB share to the specified path.
\n\n
This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.\nIf the specified path is not a directory, the cwd remains unchanged.
\n\n
Parameters:\n path (str): The path to set as the current working directory.
\n\n
Raises:\n ValueError: If the specified path is not a directory.
Parse the input string containing LM and NT hash values and return them separately.
\n\n
This function takes a string containing LM and NT hash values, typically separated by a colon (:).\nIt returns the LM and NT hash values as separate strings. If only one hash value is provided, it is\nassumed to be the NT hash and the LM hash is set to its default value. If no valid hash values are\nfound, both return values are empty strings.
\n\n
Args:\n lm_nt_hashes_string (str): A string containing LM and NT hash values separated by a colon.
\n\n
Returns:\n tuple: A tuple containing two strings (lm_hash_value, nt_hash_value).\n - lm_hash_value: The LM hash value or its default if not provided.\n - nt_hash_value: The NT hash value or its default if not provided.
Convert a file size from bytes to a more readable format using the largest appropriate unit.
\n\n
This function takes an integer representing a file size in bytes and converts it to a human-readable\nstring using the largest appropriate unit from bytes (B) to petabytes (PB). The result is rounded to\ntwo decimal places.
\n\n
Args:\n l (int): The file size in bytes.
\n\n
Returns:\n str: A string representing the file size in a more readable format, including the appropriate unit.
Generate a string representing the Unix-style permissions for a given file or directory.
\n\n
This function uses the os.lstat() method to retrieve the status of the specified file or directory,\nthen constructs a string that represents the Unix-style permissions based on the mode of the file.
\n\n
Args:\n entryname (str): The path to the file or directory for which permissions are being determined.
\n\n
Returns:\n str: A string of length 10 representing the Unix-style permissions (e.g., '-rwxr-xr--').\n The first character is either 'd' (directory), '-' (not a directory), followed by\n three groups of 'r', 'w', 'x' (read, write, execute permissions) for owner, group,\n and others respectively.
Extracts the share type flags from a given share type value.
\n\n
This function uses bitwise operations to determine which share type flags are set in the provided stype_value.\nIt checks against known share type flags and returns a list of the flags that are set.
\n\n
Parameters:\n stype_value (int): The share type value to analyze, typically obtained from SMB share properties.
\n\n
Returns:\n list: A list of strings, where each string represents a share type flag that is set in the input value.
This function generates a metadata string based on the attributes of the provided entry object.
\n\n
Parameters:\n entry (object): An object representing a file or directory entry.
\n\n
Returns:\n str: A string representing the metadata of the entry, including attributes like directory, archive, compressed, hidden, normal, readonly, system, and temporary.
This function recursively lists the contents of a directory in a tree-like format.
\n\n
Parameters:\n path (str): The path to the directory to list.\n config (object): Configuration settings which may affect the output, such as whether to use colors.
\n\n
Returns:\n None: This function does not return anything but prints the directory tree to the console.
Parses the command line arguments provided to the module.
\n\n
This method initializes the argument parser with the module's name and description, and defines all the necessary arguments that the module accepts. It then parses the provided command line arguments based on these definitions.
\n\n
Args:\n arguments (str): A string of command line arguments.
\n\n
Returns:\n ModuleArgumentParser.Namespace | None: The parsed arguments as a Namespace object if successful, None if there are no arguments or help is requested.
This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
\n\n
Args:\n base_dir (str): The base directory to start the search from.\n paths (list): List of paths to search within the base directory.\n depth (int): The current depth level in the directory hierarchy.
GPPPasswords is a module designed to search and retrieve stored Group Policy Preferences (GPP) passwords from specified network shares. \nIt leverages the SMB protocol to access files across the network, parse them, and extract credentials that are often stored within Group Policy Preferences files.
\n\n
This module is particularly useful in penetration testing scenarios where discovering stored credentials can lead to further system access or reveal poor security practices.
\n\n
Attributes:\n name (str): The name of the module, used in command line invocation.\n description (str): A brief description of what the module does.
\n\n
Methods:\n parseArgs(arguments): Parses and handles command line arguments for the module.\n parse_xmlfile_content(pathtofile): Parses the content of an XML file to extract credentials.
Parses the command line arguments provided to the module.
\n\n
This method initializes the argument parser with the module's name and description, and defines all the necessary arguments that the module accepts. It then parses the provided command line arguments based on these definitions.
\n\n
Args:\n arguments (str): A string of command line arguments.
\n\n
Returns:\n ModuleArgumentParser.Namespace | None: The parsed arguments as a Namespace object if successful, None if there are no arguments or help is requested.
Parses the content of an XML file to extract credentials related to Group Policy Preferences.
\n\n
This method attempts to retrieve and parse the content of the specified XML file from the SMB share. It looks for credentials stored within the XML structure, specifically targeting the 'cpassword' attribute which is commonly used for storing encrypted passwords in Group Policy Preferences files.
\n\n
Args:\n pathtofile (str): The path to the XML file on the SMB share.
\n\n
Returns:\n list: A list of dictionaries, each containing details about found credentials such as username, encrypted and decrypted passwords, and other relevant attributes.
Decrypts a password from its Base64 encoded form using a known AES key and IV.
\n\n
This method takes a Base64 encoded string which is encrypted using AES-CBC with a fixed key and IV as per Microsoft's published details. It decodes the Base64 string, decrypts it using the AES key and IV, and returns the plaintext password.
\n\n
Args:\n pw_enc_b64 (str): The Base64 encoded string of the encrypted password.
\n\n
Returns:\n str: The decrypted password in plaintext, or an empty string if input is empty or decryption fails.
This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
\n\n
Args:\n base_dir (str): The base directory to start the search from.\n paths (list): List of paths to search within the base directory.\n depth (int): The current depth level in the directory hierarchy.
\n\n
Returns:\n None
\n", "signature": "(self, arguments):", "funcdef": "def"}];
// mirrored in build-search-index.js (part 1)
// Also split on html tags. this is a cheap heuristic, but good enough.
diff --git a/documentation/smbclientng/core/CommandCompleter.html b/documentation/smbclientng/core/CommandCompleter.html
index 92cb6ea..bf6a824 100644
--- a/documentation/smbclientng/core/CommandCompleter.html
+++ b/documentation/smbclientng/core/CommandCompleter.html
@@ -106,426 +106,440 @@
26 """ 27 28commands={
- 29"cd":{
+ 29"bat":{ 30"description":[
- 31"Change the current working directory.",
- 32"Syntax: 'cd <directory>'"
+ 31"Pretty prints the contents of a file.",
+ 32"Syntax: 'bat <file>'" 33], 34"subcommands":[] 35},
- 36"close":{
+ 36"cat":{ 37"description":[
- 38"Closes the SMB connection to the remote machine.",
- 39"Syntax: 'close'"
+ 38"Get the contents of a file.",
+ 39"Syntax: 'cat <file>'" 40], 41"subcommands":[] 42},
- 43"connect":{
+ 43"cd":{ 44"description":[
- 45"Connect to the remote machine (useful if connection timed out).",
- 46"Syntax: 'connect'"
+ 45"Change the current working directory.",
+ 46"Syntax: 'cd <directory>'" 47], 48"subcommands":[] 49},
- 50"dir":{
+ 50"close":{ 51"description":[
- 52"List the contents of the current working directory.",
- 53"Syntax: 'dir'"
+ 52"Closes the SMB connection to the remote machine.",
+ 53"Syntax: 'close'" 54], 55"subcommands":[] 56},
- 57"exit":{
+ 57"connect":{ 58"description":[
- 59"Exits the smbclient-ng script.",
- 60"Syntax: 'exit'"
+ 59"Connect to the remote machine (useful if connection timed out).",
+ 60"Syntax: 'connect'" 61], 62"subcommands":[] 63},
- 64"get":{
+ 64"dir":{ 65"description":[
- 66"Get a remote file.",
- 67"Syntax: 'get [-r] <directory or file>'"
+ 66"List the contents of the current working directory.",
+ 67"Syntax: 'dir'" 68], 69"subcommands":[] 70},
- 71"help":{
+ 71"exit":{ 72"description":[
- 73"Displays this help message.",
- 74"Syntax: 'help'"
+ 73"Exits the smbclient-ng script.",
+ 74"Syntax: 'exit'" 75],
- 76"subcommands":["format"]
+ 76"subcommands":[] 77},
- 78"info":{
+ 78"get":{ 79"description":[
- 80"Get information about the server and or the share.",
- 81"Syntax: 'info [server|share]'"
+ 80"Get a remote file.",
+ 81"Syntax: 'get [-r] <directory or file>'" 82],
- 83"subcommands":["server","share"]
+ 83"subcommands":[] 84},
- 85"lcd":{
+ 85"help":{ 86"description":[
- 87"Changes the current local directory.",
- 88"Syntax: 'lcd <directory>'"
+ 87"Displays this help message.",
+ 88"Syntax: 'help'" 89],
- 90"subcommands":[]
+ 90"subcommands":["format"] 91},
- 92"lls":{
+ 92"info":{ 93"description":[
- 94"Lists the contents of the current local directory.",
- 95"Syntax: 'lls'"
- 96],
- 97"subcommands":[]
+ 94"Get information about the server and or the share.",
+ 95"Syntax: 'info [server|share]'"
+ 96],
+ 97"subcommands":["server","share"] 98},
- 99"lmkdir":{
+ 99"lcd":{100"description":[
-101"Creates a new local directory.",
-102"Syntax: 'lmkdir <directory>'"
-103],
+101"Changes the current local directory.",
+102"Syntax: 'lcd <directory>'"
+103],104"subcommands":[]105},
-106"lpwd":{
+106"lls":{107"description":[
-108"Shows the current local directory.",
-109"Syntax: 'lpwd'"
+108"Lists the contents of the current local directory.",
+109"Syntax: 'lls'"110],111"subcommands":[]112},
-113"lrm":{
+113"lmkdir":{114"description":[
-115"Removes a local file.",
-116"Syntax: 'lrm <file>'"
-117],
+115"Creates a new local directory.",
+116"Syntax: 'lmkdir <directory>'"
+117],118"subcommands":[]119},
-120"lrmdir":{
+120"lpwd":{121"description":[
-122"Removes a local directory.",
-123"Syntax: 'lrmdir <directory>'"
-124],
+122"Shows the current local directory.",
+123"Syntax: 'lpwd'"
+124],125"subcommands":[]126},
-127"ls":{
+127"lrm":{128"description":[
-129"List the contents of the current remote working directory.",
-130"Syntax: 'ls'"
+129"Removes a local file.",
+130"Syntax: 'lrm <file>'"131],132"subcommands":[]133},
-134"ltree":{
+134"lrmdir":{135"description":[
-136"Displays a tree view of the local directories.",
-137"Syntax: 'ltree [directory]'"
+136"Removes a local directory.",
+137"Syntax: 'lrmdir <directory>'"138],139"subcommands":[]140},
-141"mkdir":{
+141"ls":{142"description":[
-143"Creates a new remote directory.",
-144"Syntax: 'mkdir <directory>'"
+143"List the contents of the current remote working directory.",
+144"Syntax: 'ls'"145],146"subcommands":[]147},
-148"module":{
+148"ltree":{149"description":[
-150"Loads a specific module for additional functionalities.",
-151"Syntax: 'module <name>'"
+150"Displays a tree view of the local directories.",
+151"Syntax: 'ltree [directory]'"152],153"subcommands":[]154},
-155"put":{
+155"mkdir":{156"description":[
-157"Put a local file or directory in a remote directory.",
-158"Syntax: 'put [-r] <directory or file>'"
+157"Creates a new remote directory.",
+158"Syntax: 'mkdir <directory>'"159],160"subcommands":[]161},
-162"reconnect":{
+162"module":{163"description":[
-164"Reconnect to the remote machine (useful if connection timed out).",
-165"Syntax: 'reconnect'"
+164"Loads a specific module for additional functionalities.",
+165"Syntax: 'module <name>'"166],167"subcommands":[]168},
-169"reset":{
+169"put":{170"description":[
-171"Reset the TTY output, useful if it was broken after printing a binary file on stdout.",
-172"Syntax: 'reset'"
+171"Put a local file or directory in a remote directory.",
+172"Syntax: 'put [-r] <directory or file>'"173],174"subcommands":[]175},
-176"rmdir":{
+176"reconnect":{177"description":[
-178"Removes a remote directory.",
-179"Syntax: 'rmdir <directory>'"
+178"Reconnect to the remote machine (useful if connection timed out).",
+179"Syntax: 'reconnect'"180],181"subcommands":[]182},
-183"rm":{
+183"reset":{184"description":[
-185"Removes a remote file.",
-186"Syntax: 'rm <file>'"
+185"Reset the TTY output, useful if it was broken after printing a binary file on stdout.",
+186"Syntax: 'reset'"187],188"subcommands":[]189},
-190"shares":{
+190"rmdir":{191"description":[
-192"Lists the SMB shares served by the remote machine.",
-193"Syntax: 'shares'"
+192"Removes a remote directory.",
+193"Syntax: 'rmdir <directory>'"194],195"subcommands":[]196},
-197"use":{
+197"rm":{198"description":[
-199"Use a SMB share.",
-200"Syntax: 'use <sharename>'"
+199"Removes a remote file.",
+200"Syntax: 'rm <file>'"201],202"subcommands":[]203},
-204"tree":{
+204"shares":{205"description":[
-206"Displays a tree view of the remote directories.",
-207"Syntax: 'tree [directory]'"
+206"Lists the SMB shares served by the remote machine.",
+207"Syntax: 'shares'"208],209"subcommands":[]210},
-211}
-212
-213def__init__(self,smbSession,config):
-214# Objects
-215self.smbSession=smbSession
-216self.config=config
-217# Pre computing for some commands
-218self.commands["help"]["subcommands"]=["format"]+list(self.commands.keys())
-219self.commands["help"]["subcommands"].remove("help")
-220
-221defcomplete(self,text,state):
-222"""
-223 Function to handle command completion in the LDAP console.
-224
-225 This function completes the user"s input based on the available options for commands in the LDAP console.
+211"use":{
+212"description":[
+213"Use a SMB share.",
+214"Syntax: 'use <sharename>'"
+215],
+216"subcommands":[]
+217},
+218"tree":{
+219"description":[
+220"Displays a tree view of the remote directories.",
+221"Syntax: 'tree [directory]'"
+222],
+223"subcommands":[]
+224},
+225}226
-227 Args:
-228 text (str): The current text input by the user.
-229 state (int): The current state of completion.
-230
-231 Returns:
-232 str: The next completion suggestion based on the user"s input state.
-233 """
+227def__init__(self,smbSession,config):
+228# Objects
+229self.smbSession=smbSession
+230self.config=config
+231# Pre computing for some commands
+232self.commands["help"]["subcommands"]=["format"]+list(self.commands.keys())
+233self.commands["help"]["subcommands"].remove("help")234
-235ifstate==0:
-236
-237# No text typed yet, need the list of commands available
-238iflen(text)==0:
-239self.matches=[sforsinself.commands.keys()]
+235defcomplete(self,text,state):
+236"""
+237 Function to handle command completion in the LDAP console.
+238
+239 This function completes the user"s input based on the available options for commands in the LDAP console.240
-241eliflen(text)!=0:
-242# This is for the main command
-243iftext.count(" ")==0:
-244self.matches=[sforsinself.commands.keys()ifsands.startswith(text)]
-245
-246# This is for subcommands
-247eliftext.count(" ")>=1:
-248command,remainder=text.split(" ",1)
-249ifcommandinself.commands.keys():
-250ifcommand=="use":
-251# Choose SMB Share to connect to
-252self.matches=[
-253command+" "+s.lower()
-254forsinself.smbSession.list_shares().keys()
-255ifs.lower().startswith(remainder.lower())
-256]
-257
-258elifcommandin["cd","dir","ls","mkdir","rmdir","tree"]:
-259# Choose remote directory
-260path=""
-261if'\\'inremainder.strip()or'/'inremainder.strip():
-262path=remainder.strip().replace('/',ntpath.sep)
-263path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
-264
-265directory_contents=self.smbSession.list_contents(path=path).items()
-266
-267matching_entries=[]
-268for_,entryindirectory_contents:
-269ifentry.is_directory()andentry.get_longname()notin[".",".."]:
-270iflen(path)!=0:
-271matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
-272else:
-273matching_entries.append(entry.get_longname()+ntpath.sep)
-274
-275self.matches=[
-276command+" "+s
-277forsinmatching_entries
-278ifs.lower().startswith(remainder.lower())
-279]
+241 Args:
+242 text (str): The current text input by the user.
+243 state (int): The current state of completion.
+244
+245 Returns:
+246 str: The next completion suggestion based on the user"s input state.
+247 """
+248
+249ifstate==0:
+250
+251# No text typed yet, need the list of commands available
+252iflen(text)==0:
+253self.matches=[sforsinself.commands.keys()]
+254
+255eliflen(text)!=0:
+256# This is for the main command
+257iftext.count(" ")==0:
+258self.matches=[sforsinself.commands.keys()ifsands.startswith(text)]
+259
+260# This is for subcommands
+261eliftext.count(" ")>=1:
+262command,remainder=text.split(" ",1)
+263ifcommandinself.commands.keys():
+264ifcommand=="use":
+265# Choose SMB Share to connect to
+266self.matches=[
+267command+" "+s.lower()
+268forsinself.smbSession.list_shares().keys()
+269ifs.lower().startswith(remainder.lower())
+270]
+271
+272elifcommandin["cd","dir","ls","mkdir","rmdir","tree"]:
+273# Choose remote directory
+274path=""
+275if'\\'inremainder.strip()or'/'inremainder.strip():
+276path=remainder.strip().replace('/',ntpath.sep)
+277path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
+278
+279directory_contents=self.smbSession.list_contents(path=path).items()280
-281elifcommandin["get","rm"]:
-282# Choose local files and directories
-283path=""
-284if'\\'inremainder.strip()or'/'inremainder.strip():
-285path=remainder.strip().replace('/',ntpath.sep)
-286path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
-287
-288directory_contents=self.smbSession.list_contents(path=path).items()
-289
-290matching_entries=[]
-291for_,entryindirectory_contents:
-292ifentry.get_longname()notin[".",".."]:
-293iflen(path)!=0:
-294ifentry.is_directory():
-295matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
-296else:
-297matching_entries.append(path+ntpath.sep+entry.get_longname())
-298else:
-299ifentry.is_directory():
-300matching_entries.append(entry.get_longname()+ntpath.sep)
-301else:
-302matching_entries.append(entry.get_longname())
+281matching_entries=[]
+282for_,entryindirectory_contents:
+283ifentry.is_directory()andentry.get_longname()notin[".",".."]:
+284iflen(path)!=0:
+285matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
+286else:
+287matching_entries.append(entry.get_longname()+ntpath.sep)
+288
+289self.matches=[
+290command+" "+s
+291forsinmatching_entries
+292ifs.lower().startswith(remainder.lower())
+293]
+294
+295elifcommandin["bat","cat","get","rm"]:
+296# Choose local files and directories
+297path=""
+298if'\\'inremainder.strip()or'/'inremainder.strip():
+299path=remainder.strip().replace('/',ntpath.sep)
+300path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
+301
+302directory_contents=self.smbSession.list_contents(path=path).items()303
-304self.matches=[
-305command+" "+s
-306forsinmatching_entries
-307ifs.lower().startswith(remainder.lower())
-308]
-309
-310elifcommandin["lcd","lls","put","lmkdir","lrm","lrmdir"]:
-311# Choose directory
-312path=""
-313ifos.path.sepinremainder.strip():
-314path=path.split(os.path.sep)[:-1]
-315path=os.path.sep.join(path)
-316
-317# Current dir
-318iflen(path.strip())==0:
-319path="."
-320
-321directory_contents=os.listdir(path=path+os.path.sep)
-322matching_entries=[]
-323forentryindirectory_contents:
-324ifentrynotin[".",".."]:
-325entry_path=path+os.path.sep+entry
-326ifos.path.isdir(entry_path):
-327matching_entries.append(entry_path+os.path.sep)
-328else:
-329matching_entries.append(entry_path)
-330
-331self.matches=[
-332command+" "+s
-333forsinmatching_entries
-334ifs.startswith(remainder)
-335]
-336
-337else:
-338# Generic case for subcommands
-339self.matches=[
-340command+" "+s
-341forsinself.commands[command]["subcommands"]
-342ifs.startswith(remainder)
-343]
-344else:
-345# Unknown subcommand, skipping autocomplete
-346pass
-347else:
-348self.matches=[]
-349else:
-350self.matches=self.commands.keys()[:]
-351
-352try:
-353returnself.matches[state]+" "
-354exceptIndexError:
-355returnNone
-356
-357defprint_help(self,command=None):
-358"""
-359 Prints help information for a specific command or all commands if no command is specified.
-360
-361 This method displays the help information for the command passed as an argument. If no command is specified,
-362 it prints the help information for all available commands. The help information includes the command syntax,
-363 description, and any subcommands associated with it. This method is designed to provide users with the necessary
-364 guidance on how to use the commands in the smbclient-ng shell.
+304matching_entries=[]
+305for_,entryindirectory_contents:
+306ifentry.get_longname()notin[".",".."]:
+307iflen(path)!=0:
+308ifentry.is_directory():
+309matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
+310else:
+311matching_entries.append(path+ntpath.sep+entry.get_longname())
+312else:
+313ifentry.is_directory():
+314matching_entries.append(entry.get_longname()+ntpath.sep)
+315else:
+316matching_entries.append(entry.get_longname())
+317
+318self.matches=[
+319command+" "+s
+320forsinmatching_entries
+321ifs.lower().startswith(remainder.lower())
+322]
+323
+324elifcommandin["lcd","lls","put","lmkdir","lrm","lrmdir"]:
+325# Choose directory
+326path=""
+327ifos.path.sepinremainder.strip():
+328path=path.split(os.path.sep)[:-1]
+329path=os.path.sep.join(path)
+330
+331# Current dir
+332iflen(path.strip())==0:
+333path="."
+334
+335directory_contents=os.listdir(path=path+os.path.sep)
+336matching_entries=[]
+337forentryindirectory_contents:
+338ifentrynotin[".",".."]:
+339entry_path=path+os.path.sep+entry
+340ifos.path.isdir(entry_path):
+341matching_entries.append(entry_path+os.path.sep)
+342else:
+343matching_entries.append(entry_path)
+344
+345self.matches=[
+346command+" "+s
+347forsinmatching_entries
+348ifs.startswith(remainder)
+349]
+350
+351else:
+352# Generic case for subcommands
+353self.matches=[
+354command+" "+s
+355forsinself.commands[command]["subcommands"]
+356ifs.startswith(remainder)
+357]
+358else:
+359# Unknown subcommand, skipping autocomplete
+360pass
+361else:
+362self.matches=[]
+363else:
+364self.matches=self.commands.keys()[:]365
-366 Args:
-367 command (str, optional): The command to display help information for. If None, help for all commands is displayed.
-368
-369 Returns:
-370 None
-371 """
-372
-373ifcommandisnotNone:
-374ifcommandnotinlist(self.commands.keys())+["format"]:
-375command=None
-376
-377# Print help for a specific command
-378ifcommandisnotNone:
-379ifcommand=="format":
-380self.print_help_format()
-381else:
-382print("│")
-383ifself.config.no_colors:
-384command_str=command+"─"*(15-len(command))
-385iflen(self.commands[command]["description"])==0:
-386print("│ ■ %s┤ "%command_str)
-387eliflen(self.commands[command]["description"])==1:
-388print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-389else:
-390print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-391forlineinself.commands[command]["description"][1:]:
-392print("│ %s│ %s "%(" "*(15+3),line))
-393else:
-394command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
-395iflen(self.commands[command]["description"])==0:
-396print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
-397eliflen(self.commands[command]["description"])==1:
-398print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-399else:
-400print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-401forlineinself.commands[command]["description"][1:]:
-402print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+2),line))
-403print("│")
-404# Generic help
-405else:
-406print("│")
-407commands=sorted(self.commands.keys())
-408forcommandincommands:
-409ifself.config.no_colors:
-410command_str=command+"─"*(15-len(command))
-411iflen(self.commands[command]["description"])==0:
-412print("│ ■ %s┤ "%command_str)
-413eliflen(self.commands[command]["description"])==1:
-414print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-415else:
-416print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-417forlineinself.commands[command]["description"][1:]:
-418print("│ %s│ %s "%(" "*(15+2),line))
-419else:
-420command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
-421iflen(self.commands[command]["description"])==0:
-422print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
-423eliflen(self.commands[command]["description"])==1:
-424print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-425else:
-426print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-427forlineinself.commands[command]["description"][1:]:
-428print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+3),line))
-429print("│")
-430
-431defprint_help_format(self):
-432"""
-433 Prints the help information for the 'format' used in remote 'ls' and 'dir' commands.
-434
-435 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning
-436 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory.
-437 """
-438
-439print("File attributes format:\n")
-440print("\x1b[1mdachnrst\x1b[0m")
-441print("\x1b[90m│││││││└──>\x1b[0m Temporary")
-442print("\x1b[90m││││││└───>\x1b[0m System")
-443print("\x1b[90m│││││└────>\x1b[0m Read-Only")
-444print("\x1b[90m││││└─────>\x1b[0m Normal")
-445print("\x1b[90m│││└──────>\x1b[0m Hidden")
-446print("\x1b[90m││└───────>\x1b[0m Compressed")
-447print("\x1b[90m│└────────>\x1b[0m Archived")
-448print("\x1b[90m└─────────>\x1b[0m Directory")
+366try:
+367returnself.matches[state]+" "
+368exceptIndexError:
+369returnNone
+370
+371defprint_help(self,command=None):
+372"""
+373 Prints help information for a specific command or all commands if no command is specified.
+374
+375 This method displays the help information for the command passed as an argument. If no command is specified,
+376 it prints the help information for all available commands. The help information includes the command syntax,
+377 description, and any subcommands associated with it. This method is designed to provide users with the necessary
+378 guidance on how to use the commands in the smbclient-ng shell.
+379
+380 Args:
+381 command (str, optional): The command to display help information for. If None, help for all commands is displayed.
+382
+383 Returns:
+384 None
+385 """
+386
+387ifcommandisnotNone:
+388ifcommandnotinlist(self.commands.keys())+["format"]:
+389command=None
+390
+391# Print help for a specific command
+392ifcommandisnotNone:
+393ifcommand=="format":
+394self.print_help_format()
+395else:
+396print("│")
+397ifself.config.no_colors:
+398command_str=command+"─"*(15-len(command))
+399iflen(self.commands[command]["description"])==0:
+400print("│ ■ %s┤ "%command_str)
+401eliflen(self.commands[command]["description"])==1:
+402print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+403else:
+404print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+405forlineinself.commands[command]["description"][1:]:
+406print("│ %s│ %s "%(" "*(15+2),line))
+407else:
+408command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
+409iflen(self.commands[command]["description"])==0:
+410print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
+411eliflen(self.commands[command]["description"])==1:
+412print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+413else:
+414print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+415forlineinself.commands[command]["description"][1:]:
+416print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+3),line))
+417print("│")
+418# Generic help
+419else:
+420print("│")
+421commands=sorted(self.commands.keys())
+422forcommandincommands:
+423ifself.config.no_colors:
+424command_str=command+"─"*(15-len(command))
+425iflen(self.commands[command]["description"])==0:
+426print("│ ■ %s┤ "%command_str)
+427eliflen(self.commands[command]["description"])==1:
+428print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+429else:
+430print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+431forlineinself.commands[command]["description"][1:]:
+432print("│ %s│ %s "%(" "*(15+2),line))
+433else:
+434command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
+435iflen(self.commands[command]["description"])==0:
+436print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
+437eliflen(self.commands[command]["description"])==1:
+438print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+439else:
+440print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+441forlineinself.commands[command]["description"][1:]:
+442print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+3),line))
+443print("│")
+444
+445defprint_help_format(self):
+446"""
+447 Prints the help information for the 'format' used in remote 'ls' and 'dir' commands.
+448
+449 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning
+450 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory.
+451 """
+452
+453print("File attributes format:\n")
+454print("\x1b[1mdachnrst\x1b[0m")
+455print("\x1b[90m│││││││└──>\x1b[0m Temporary")
+456print("\x1b[90m││││││└───>\x1b[0m System")
+457print("\x1b[90m│││││└────>\x1b[0m Read-Only")
+458print("\x1b[90m││││└─────>\x1b[0m Normal")
+459print("\x1b[90m│││└──────>\x1b[0m Hidden")
+460print("\x1b[90m││└───────>\x1b[0m Compressed")
+461print("\x1b[90m│└────────>\x1b[0m Archived")
+462print("\x1b[90m└─────────>\x1b[0m Directory")
@@ -558,426 +572,440 @@
27 """ 28 29commands={
- 30"cd":{
+ 30"bat":{ 31"description":[
- 32"Change the current working directory.",
- 33"Syntax: 'cd <directory>'"
+ 32"Pretty prints the contents of a file.",
+ 33"Syntax: 'bat <file>'" 34], 35"subcommands":[] 36},
- 37"close":{
+ 37"cat":{ 38"description":[
- 39"Closes the SMB connection to the remote machine.",
- 40"Syntax: 'close'"
+ 39"Get the contents of a file.",
+ 40"Syntax: 'cat <file>'" 41], 42"subcommands":[] 43},
- 44"connect":{
+ 44"cd":{ 45"description":[
- 46"Connect to the remote machine (useful if connection timed out).",
- 47"Syntax: 'connect'"
+ 46"Change the current working directory.",
+ 47"Syntax: 'cd <directory>'" 48], 49"subcommands":[] 50},
- 51"dir":{
+ 51"close":{ 52"description":[
- 53"List the contents of the current working directory.",
- 54"Syntax: 'dir'"
+ 53"Closes the SMB connection to the remote machine.",
+ 54"Syntax: 'close'" 55], 56"subcommands":[] 57},
- 58"exit":{
+ 58"connect":{ 59"description":[
- 60"Exits the smbclient-ng script.",
- 61"Syntax: 'exit'"
+ 60"Connect to the remote machine (useful if connection timed out).",
+ 61"Syntax: 'connect'" 62], 63"subcommands":[] 64},
- 65"get":{
+ 65"dir":{ 66"description":[
- 67"Get a remote file.",
- 68"Syntax: 'get [-r] <directory or file>'"
+ 67"List the contents of the current working directory.",
+ 68"Syntax: 'dir'" 69], 70"subcommands":[] 71},
- 72"help":{
+ 72"exit":{ 73"description":[
- 74"Displays this help message.",
- 75"Syntax: 'help'"
+ 74"Exits the smbclient-ng script.",
+ 75"Syntax: 'exit'" 76],
- 77"subcommands":["format"]
+ 77"subcommands":[] 78},
- 79"info":{
+ 79"get":{ 80"description":[
- 81"Get information about the server and or the share.",
- 82"Syntax: 'info [server|share]'"
+ 81"Get a remote file.",
+ 82"Syntax: 'get [-r] <directory or file>'" 83],
- 84"subcommands":["server","share"]
+ 84"subcommands":[] 85},
- 86"lcd":{
+ 86"help":{ 87"description":[
- 88"Changes the current local directory.",
- 89"Syntax: 'lcd <directory>'"
+ 88"Displays this help message.",
+ 89"Syntax: 'help'" 90],
- 91"subcommands":[]
+ 91"subcommands":["format"] 92},
- 93"lls":{
+ 93"info":{ 94"description":[
- 95"Lists the contents of the current local directory.",
- 96"Syntax: 'lls'"
- 97],
- 98"subcommands":[]
+ 95"Get information about the server and or the share.",
+ 96"Syntax: 'info [server|share]'"
+ 97],
+ 98"subcommands":["server","share"] 99},
-100"lmkdir":{
+100"lcd":{101"description":[
-102"Creates a new local directory.",
-103"Syntax: 'lmkdir <directory>'"
-104],
+102"Changes the current local directory.",
+103"Syntax: 'lcd <directory>'"
+104],105"subcommands":[]106},
-107"lpwd":{
+107"lls":{108"description":[
-109"Shows the current local directory.",
-110"Syntax: 'lpwd'"
+109"Lists the contents of the current local directory.",
+110"Syntax: 'lls'"111],112"subcommands":[]113},
-114"lrm":{
+114"lmkdir":{115"description":[
-116"Removes a local file.",
-117"Syntax: 'lrm <file>'"
-118],
+116"Creates a new local directory.",
+117"Syntax: 'lmkdir <directory>'"
+118],119"subcommands":[]120},
-121"lrmdir":{
+121"lpwd":{122"description":[
-123"Removes a local directory.",
-124"Syntax: 'lrmdir <directory>'"
-125],
+123"Shows the current local directory.",
+124"Syntax: 'lpwd'"
+125],126"subcommands":[]127},
-128"ls":{
+128"lrm":{129"description":[
-130"List the contents of the current remote working directory.",
-131"Syntax: 'ls'"
+130"Removes a local file.",
+131"Syntax: 'lrm <file>'"132],133"subcommands":[]134},
-135"ltree":{
+135"lrmdir":{136"description":[
-137"Displays a tree view of the local directories.",
-138"Syntax: 'ltree [directory]'"
+137"Removes a local directory.",
+138"Syntax: 'lrmdir <directory>'"139],140"subcommands":[]141},
-142"mkdir":{
+142"ls":{143"description":[
-144"Creates a new remote directory.",
-145"Syntax: 'mkdir <directory>'"
+144"List the contents of the current remote working directory.",
+145"Syntax: 'ls'"146],147"subcommands":[]148},
-149"module":{
+149"ltree":{150"description":[
-151"Loads a specific module for additional functionalities.",
-152"Syntax: 'module <name>'"
+151"Displays a tree view of the local directories.",
+152"Syntax: 'ltree [directory]'"153],154"subcommands":[]155},
-156"put":{
+156"mkdir":{157"description":[
-158"Put a local file or directory in a remote directory.",
-159"Syntax: 'put [-r] <directory or file>'"
+158"Creates a new remote directory.",
+159"Syntax: 'mkdir <directory>'"160],161"subcommands":[]162},
-163"reconnect":{
+163"module":{164"description":[
-165"Reconnect to the remote machine (useful if connection timed out).",
-166"Syntax: 'reconnect'"
+165"Loads a specific module for additional functionalities.",
+166"Syntax: 'module <name>'"167],168"subcommands":[]169},
-170"reset":{
+170"put":{171"description":[
-172"Reset the TTY output, useful if it was broken after printing a binary file on stdout.",
-173"Syntax: 'reset'"
+172"Put a local file or directory in a remote directory.",
+173"Syntax: 'put [-r] <directory or file>'"174],175"subcommands":[]176},
-177"rmdir":{
+177"reconnect":{178"description":[
-179"Removes a remote directory.",
-180"Syntax: 'rmdir <directory>'"
+179"Reconnect to the remote machine (useful if connection timed out).",
+180"Syntax: 'reconnect'"181],182"subcommands":[]183},
-184"rm":{
+184"reset":{185"description":[
-186"Removes a remote file.",
-187"Syntax: 'rm <file>'"
+186"Reset the TTY output, useful if it was broken after printing a binary file on stdout.",
+187"Syntax: 'reset'"188],189"subcommands":[]190},
-191"shares":{
+191"rmdir":{192"description":[
-193"Lists the SMB shares served by the remote machine.",
-194"Syntax: 'shares'"
+193"Removes a remote directory.",
+194"Syntax: 'rmdir <directory>'"195],196"subcommands":[]197},
-198"use":{
+198"rm":{199"description":[
-200"Use a SMB share.",
-201"Syntax: 'use <sharename>'"
+200"Removes a remote file.",
+201"Syntax: 'rm <file>'"202],203"subcommands":[]204},
-205"tree":{
+205"shares":{206"description":[
-207"Displays a tree view of the remote directories.",
-208"Syntax: 'tree [directory]'"
+207"Lists the SMB shares served by the remote machine.",
+208"Syntax: 'shares'"209],210"subcommands":[]211},
-212}
-213
-214def__init__(self,smbSession,config):
-215# Objects
-216self.smbSession=smbSession
-217self.config=config
-218# Pre computing for some commands
-219self.commands["help"]["subcommands"]=["format"]+list(self.commands.keys())
-220self.commands["help"]["subcommands"].remove("help")
-221
-222defcomplete(self,text,state):
-223"""
-224 Function to handle command completion in the LDAP console.
-225
-226 This function completes the user"s input based on the available options for commands in the LDAP console.
+212"use":{
+213"description":[
+214"Use a SMB share.",
+215"Syntax: 'use <sharename>'"
+216],
+217"subcommands":[]
+218},
+219"tree":{
+220"description":[
+221"Displays a tree view of the remote directories.",
+222"Syntax: 'tree [directory]'"
+223],
+224"subcommands":[]
+225},
+226}227
-228 Args:
-229 text (str): The current text input by the user.
-230 state (int): The current state of completion.
-231
-232 Returns:
-233 str: The next completion suggestion based on the user"s input state.
-234 """
+228def__init__(self,smbSession,config):
+229# Objects
+230self.smbSession=smbSession
+231self.config=config
+232# Pre computing for some commands
+233self.commands["help"]["subcommands"]=["format"]+list(self.commands.keys())
+234self.commands["help"]["subcommands"].remove("help")235
-236ifstate==0:
-237
-238# No text typed yet, need the list of commands available
-239iflen(text)==0:
-240self.matches=[sforsinself.commands.keys()]
+236defcomplete(self,text,state):
+237"""
+238 Function to handle command completion in the LDAP console.
+239
+240 This function completes the user"s input based on the available options for commands in the LDAP console.241
-242eliflen(text)!=0:
-243# This is for the main command
-244iftext.count(" ")==0:
-245self.matches=[sforsinself.commands.keys()ifsands.startswith(text)]
-246
-247# This is for subcommands
-248eliftext.count(" ")>=1:
-249command,remainder=text.split(" ",1)
-250ifcommandinself.commands.keys():
-251ifcommand=="use":
-252# Choose SMB Share to connect to
-253self.matches=[
-254command+" "+s.lower()
-255forsinself.smbSession.list_shares().keys()
-256ifs.lower().startswith(remainder.lower())
-257]
-258
-259elifcommandin["cd","dir","ls","mkdir","rmdir","tree"]:
-260# Choose remote directory
-261path=""
-262if'\\'inremainder.strip()or'/'inremainder.strip():
-263path=remainder.strip().replace('/',ntpath.sep)
-264path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
-265
-266directory_contents=self.smbSession.list_contents(path=path).items()
-267
-268matching_entries=[]
-269for_,entryindirectory_contents:
-270ifentry.is_directory()andentry.get_longname()notin[".",".."]:
-271iflen(path)!=0:
-272matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
-273else:
-274matching_entries.append(entry.get_longname()+ntpath.sep)
-275
-276self.matches=[
-277command+" "+s
-278forsinmatching_entries
-279ifs.lower().startswith(remainder.lower())
-280]
+242 Args:
+243 text (str): The current text input by the user.
+244 state (int): The current state of completion.
+245
+246 Returns:
+247 str: The next completion suggestion based on the user"s input state.
+248 """
+249
+250ifstate==0:
+251
+252# No text typed yet, need the list of commands available
+253iflen(text)==0:
+254self.matches=[sforsinself.commands.keys()]
+255
+256eliflen(text)!=0:
+257# This is for the main command
+258iftext.count(" ")==0:
+259self.matches=[sforsinself.commands.keys()ifsands.startswith(text)]
+260
+261# This is for subcommands
+262eliftext.count(" ")>=1:
+263command,remainder=text.split(" ",1)
+264ifcommandinself.commands.keys():
+265ifcommand=="use":
+266# Choose SMB Share to connect to
+267self.matches=[
+268command+" "+s.lower()
+269forsinself.smbSession.list_shares().keys()
+270ifs.lower().startswith(remainder.lower())
+271]
+272
+273elifcommandin["cd","dir","ls","mkdir","rmdir","tree"]:
+274# Choose remote directory
+275path=""
+276if'\\'inremainder.strip()or'/'inremainder.strip():
+277path=remainder.strip().replace('/',ntpath.sep)
+278path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
+279
+280directory_contents=self.smbSession.list_contents(path=path).items()281
-282elifcommandin["get","rm"]:
-283# Choose local files and directories
-284path=""
-285if'\\'inremainder.strip()or'/'inremainder.strip():
-286path=remainder.strip().replace('/',ntpath.sep)
-287path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
-288
-289directory_contents=self.smbSession.list_contents(path=path).items()
-290
-291matching_entries=[]
-292for_,entryindirectory_contents:
-293ifentry.get_longname()notin[".",".."]:
-294iflen(path)!=0:
-295ifentry.is_directory():
-296matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
-297else:
-298matching_entries.append(path+ntpath.sep+entry.get_longname())
-299else:
-300ifentry.is_directory():
-301matching_entries.append(entry.get_longname()+ntpath.sep)
-302else:
-303matching_entries.append(entry.get_longname())
+282matching_entries=[]
+283for_,entryindirectory_contents:
+284ifentry.is_directory()andentry.get_longname()notin[".",".."]:
+285iflen(path)!=0:
+286matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
+287else:
+288matching_entries.append(entry.get_longname()+ntpath.sep)
+289
+290self.matches=[
+291command+" "+s
+292forsinmatching_entries
+293ifs.lower().startswith(remainder.lower())
+294]
+295
+296elifcommandin["bat","cat","get","rm"]:
+297# Choose local files and directories
+298path=""
+299if'\\'inremainder.strip()or'/'inremainder.strip():
+300path=remainder.strip().replace('/',ntpath.sep)
+301path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
+302
+303directory_contents=self.smbSession.list_contents(path=path).items()304
-305self.matches=[
-306command+" "+s
-307forsinmatching_entries
-308ifs.lower().startswith(remainder.lower())
-309]
-310
-311elifcommandin["lcd","lls","put","lmkdir","lrm","lrmdir"]:
-312# Choose directory
-313path=""
-314ifos.path.sepinremainder.strip():
-315path=path.split(os.path.sep)[:-1]
-316path=os.path.sep.join(path)
-317
-318# Current dir
-319iflen(path.strip())==0:
-320path="."
-321
-322directory_contents=os.listdir(path=path+os.path.sep)
-323matching_entries=[]
-324forentryindirectory_contents:
-325ifentrynotin[".",".."]:
-326entry_path=path+os.path.sep+entry
-327ifos.path.isdir(entry_path):
-328matching_entries.append(entry_path+os.path.sep)
-329else:
-330matching_entries.append(entry_path)
-331
-332self.matches=[
-333command+" "+s
-334forsinmatching_entries
-335ifs.startswith(remainder)
-336]
-337
-338else:
-339# Generic case for subcommands
-340self.matches=[
-341command+" "+s
-342forsinself.commands[command]["subcommands"]
-343ifs.startswith(remainder)
-344]
-345else:
-346# Unknown subcommand, skipping autocomplete
-347pass
-348else:
-349self.matches=[]
-350else:
-351self.matches=self.commands.keys()[:]
-352
-353try:
-354returnself.matches[state]+" "
-355exceptIndexError:
-356returnNone
-357
-358defprint_help(self,command=None):
-359"""
-360 Prints help information for a specific command or all commands if no command is specified.
-361
-362 This method displays the help information for the command passed as an argument. If no command is specified,
-363 it prints the help information for all available commands. The help information includes the command syntax,
-364 description, and any subcommands associated with it. This method is designed to provide users with the necessary
-365 guidance on how to use the commands in the smbclient-ng shell.
+305matching_entries=[]
+306for_,entryindirectory_contents:
+307ifentry.get_longname()notin[".",".."]:
+308iflen(path)!=0:
+309ifentry.is_directory():
+310matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
+311else:
+312matching_entries.append(path+ntpath.sep+entry.get_longname())
+313else:
+314ifentry.is_directory():
+315matching_entries.append(entry.get_longname()+ntpath.sep)
+316else:
+317matching_entries.append(entry.get_longname())
+318
+319self.matches=[
+320command+" "+s
+321forsinmatching_entries
+322ifs.lower().startswith(remainder.lower())
+323]
+324
+325elifcommandin["lcd","lls","put","lmkdir","lrm","lrmdir"]:
+326# Choose directory
+327path=""
+328ifos.path.sepinremainder.strip():
+329path=path.split(os.path.sep)[:-1]
+330path=os.path.sep.join(path)
+331
+332# Current dir
+333iflen(path.strip())==0:
+334path="."
+335
+336directory_contents=os.listdir(path=path+os.path.sep)
+337matching_entries=[]
+338forentryindirectory_contents:
+339ifentrynotin[".",".."]:
+340entry_path=path+os.path.sep+entry
+341ifos.path.isdir(entry_path):
+342matching_entries.append(entry_path+os.path.sep)
+343else:
+344matching_entries.append(entry_path)
+345
+346self.matches=[
+347command+" "+s
+348forsinmatching_entries
+349ifs.startswith(remainder)
+350]
+351
+352else:
+353# Generic case for subcommands
+354self.matches=[
+355command+" "+s
+356forsinself.commands[command]["subcommands"]
+357ifs.startswith(remainder)
+358]
+359else:
+360# Unknown subcommand, skipping autocomplete
+361pass
+362else:
+363self.matches=[]
+364else:
+365self.matches=self.commands.keys()[:]366
-367 Args:
-368 command (str, optional): The command to display help information for. If None, help for all commands is displayed.
-369
-370 Returns:
-371 None
-372 """
-373
-374ifcommandisnotNone:
-375ifcommandnotinlist(self.commands.keys())+["format"]:
-376command=None
-377
-378# Print help for a specific command
-379ifcommandisnotNone:
-380ifcommand=="format":
-381self.print_help_format()
-382else:
-383print("│")
-384ifself.config.no_colors:
-385command_str=command+"─"*(15-len(command))
-386iflen(self.commands[command]["description"])==0:
-387print("│ ■ %s┤ "%command_str)
-388eliflen(self.commands[command]["description"])==1:
-389print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-390else:
-391print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-392forlineinself.commands[command]["description"][1:]:
-393print("│ %s│ %s "%(" "*(15+3),line))
-394else:
-395command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
-396iflen(self.commands[command]["description"])==0:
-397print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
-398eliflen(self.commands[command]["description"])==1:
-399print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-400else:
-401print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-402forlineinself.commands[command]["description"][1:]:
-403print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+2),line))
-404print("│")
-405# Generic help
-406else:
-407print("│")
-408commands=sorted(self.commands.keys())
-409forcommandincommands:
-410ifself.config.no_colors:
-411command_str=command+"─"*(15-len(command))
-412iflen(self.commands[command]["description"])==0:
-413print("│ ■ %s┤ "%command_str)
-414eliflen(self.commands[command]["description"])==1:
-415print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-416else:
-417print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-418forlineinself.commands[command]["description"][1:]:
-419print("│ %s│ %s "%(" "*(15+2),line))
-420else:
-421command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
-422iflen(self.commands[command]["description"])==0:
-423print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
-424eliflen(self.commands[command]["description"])==1:
-425print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-426else:
-427print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-428forlineinself.commands[command]["description"][1:]:
-429print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+3),line))
-430print("│")
-431
-432defprint_help_format(self):
-433"""
-434 Prints the help information for the 'format' used in remote 'ls' and 'dir' commands.
-435
-436 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning
-437 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory.
-438 """
-439
-440print("File attributes format:\n")
-441print("\x1b[1mdachnrst\x1b[0m")
-442print("\x1b[90m│││││││└──>\x1b[0m Temporary")
-443print("\x1b[90m││││││└───>\x1b[0m System")
-444print("\x1b[90m│││││└────>\x1b[0m Read-Only")
-445print("\x1b[90m││││└─────>\x1b[0m Normal")
-446print("\x1b[90m│││└──────>\x1b[0m Hidden")
-447print("\x1b[90m││└───────>\x1b[0m Compressed")
-448print("\x1b[90m│└────────>\x1b[0m Archived")
-449print("\x1b[90m└─────────>\x1b[0m Directory")
+367try:
+368returnself.matches[state]+" "
+369exceptIndexError:
+370returnNone
+371
+372defprint_help(self,command=None):
+373"""
+374 Prints help information for a specific command or all commands if no command is specified.
+375
+376 This method displays the help information for the command passed as an argument. If no command is specified,
+377 it prints the help information for all available commands. The help information includes the command syntax,
+378 description, and any subcommands associated with it. This method is designed to provide users with the necessary
+379 guidance on how to use the commands in the smbclient-ng shell.
+380
+381 Args:
+382 command (str, optional): The command to display help information for. If None, help for all commands is displayed.
+383
+384 Returns:
+385 None
+386 """
+387
+388ifcommandisnotNone:
+389ifcommandnotinlist(self.commands.keys())+["format"]:
+390command=None
+391
+392# Print help for a specific command
+393ifcommandisnotNone:
+394ifcommand=="format":
+395self.print_help_format()
+396else:
+397print("│")
+398ifself.config.no_colors:
+399command_str=command+"─"*(15-len(command))
+400iflen(self.commands[command]["description"])==0:
+401print("│ ■ %s┤ "%command_str)
+402eliflen(self.commands[command]["description"])==1:
+403print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+404else:
+405print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+406forlineinself.commands[command]["description"][1:]:
+407print("│ %s│ %s "%(" "*(15+2),line))
+408else:
+409command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
+410iflen(self.commands[command]["description"])==0:
+411print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
+412eliflen(self.commands[command]["description"])==1:
+413print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+414else:
+415print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+416forlineinself.commands[command]["description"][1:]:
+417print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+3),line))
+418print("│")
+419# Generic help
+420else:
+421print("│")
+422commands=sorted(self.commands.keys())
+423forcommandincommands:
+424ifself.config.no_colors:
+425command_str=command+"─"*(15-len(command))
+426iflen(self.commands[command]["description"])==0:
+427print("│ ■ %s┤ "%command_str)
+428eliflen(self.commands[command]["description"])==1:
+429print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+430else:
+431print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+432forlineinself.commands[command]["description"][1:]:
+433print("│ %s│ %s "%(" "*(15+2),line))
+434else:
+435command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
+436iflen(self.commands[command]["description"])==0:
+437print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
+438eliflen(self.commands[command]["description"])==1:
+439print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+440else:
+441print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+442forlineinself.commands[command]["description"][1:]:
+443print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+3),line))
+444print("│")
+445
+446defprint_help_format(self):
+447"""
+448 Prints the help information for the 'format' used in remote 'ls' and 'dir' commands.
+449
+450 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning
+451 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory.
+452 """
+453
+454print("File attributes format:\n")
+455print("\x1b[1mdachnrst\x1b[0m")
+456print("\x1b[90m│││││││└──>\x1b[0m Temporary")
+457print("\x1b[90m││││││└───>\x1b[0m System")
+458print("\x1b[90m│││││└────>\x1b[0m Read-Only")
+459print("\x1b[90m││││└─────>\x1b[0m Normal")
+460print("\x1b[90m│││└──────>\x1b[0m Hidden")
+461print("\x1b[90m││└───────>\x1b[0m Compressed")
+462print("\x1b[90m│└────────>\x1b[0m Archived")
+463print("\x1b[90m└─────────>\x1b[0m Directory")
@@ -1006,13 +1034,13 @@
-
214def__init__(self,smbSession,config):
-215# Objects
-216self.smbSession=smbSession
-217self.config=config
-218# Pre computing for some commands
-219self.commands["help"]["subcommands"]=["format"]+list(self.commands.keys())
-220self.commands["help"]["subcommands"].remove("help")
+
228def__init__(self,smbSession,config):
+229# Objects
+230self.smbSession=smbSession
+231self.config=config
+232# Pre computing for some commands
+233self.commands["help"]["subcommands"]=["format"]+list(self.commands.keys())
+234self.commands["help"]["subcommands"].remove("help")
@@ -1023,7 +1051,7 @@
commands =
- {'cd': {'description': ['Change the current working directory.', "Syntax: 'cd <directory>'"], 'subcommands': []}, 'close': {'description': ['Closes the SMB connection to the remote machine.', "Syntax: 'close'"], 'subcommands': []}, 'connect': {'description': ['Connect to the remote machine (useful if connection timed out).', "Syntax: 'connect'"], 'subcommands': []}, 'dir': {'description': ['List the contents of the current working directory.', "Syntax: 'dir'"], 'subcommands': []}, 'exit': {'description': ['Exits the smbclient-ng script.', "Syntax: 'exit'"], 'subcommands': []}, 'get': {'description': ['Get a remote file.', "Syntax: 'get [-r] <directory or file>'"], 'subcommands': []}, 'help': {'description': ['Displays this help message.', "Syntax: 'help'"], 'subcommands': ['format']}, 'info': {'description': ['Get information about the server and or the share.', "Syntax: 'info [server|share]'"], 'subcommands': ['server', 'share']}, 'lcd': {'description': ['Changes the current local directory.', "Syntax: 'lcd <directory>'"], 'subcommands': []}, 'lls': {'description': ['Lists the contents of the current local directory.', "Syntax: 'lls'"], 'subcommands': []}, 'lmkdir': {'description': ['Creates a new local directory.', "Syntax: 'lmkdir <directory>'"], 'subcommands': []}, 'lpwd': {'description': ['Shows the current local directory.', "Syntax: 'lpwd'"], 'subcommands': []}, 'lrm': {'description': ['Removes a local file.', "Syntax: 'lrm <file>'"], 'subcommands': []}, 'lrmdir': {'description': ['Removes a local directory.', "Syntax: 'lrmdir <directory>'"], 'subcommands': []}, 'ls': {'description': ['List the contents of the current remote working directory.', "Syntax: 'ls'"], 'subcommands': []}, 'ltree': {'description': ['Displays a tree view of the local directories.', "Syntax: 'ltree [directory]'"], 'subcommands': []}, 'mkdir': {'description': ['Creates a new remote directory.', "Syntax: 'mkdir <directory>'"], 'subcommands': []}, 'module': {'description': ['Loads a specific module for additional functionalities.', "Syntax: 'module <name>'"], 'subcommands': []}, 'put': {'description': ['Put a local file or directory in a remote directory.', "Syntax: 'put [-r] <directory or file>'"], 'subcommands': []}, 'reconnect': {'description': ['Reconnect to the remote machine (useful if connection timed out).', "Syntax: 'reconnect'"], 'subcommands': []}, 'reset': {'description': ['Reset the TTY output, useful if it was broken after printing a binary file on stdout.', "Syntax: 'reset'"], 'subcommands': []}, 'rmdir': {'description': ['Removes a remote directory.', "Syntax: 'rmdir <directory>'"], 'subcommands': []}, 'rm': {'description': ['Removes a remote file.', "Syntax: 'rm <file>'"], 'subcommands': []}, 'shares': {'description': ['Lists the SMB shares served by the remote machine.', "Syntax: 'shares'"], 'subcommands': []}, 'use': {'description': ['Use a SMB share.', "Syntax: 'use <sharename>'"], 'subcommands': []}, 'tree': {'description': ['Displays a tree view of the remote directories.', "Syntax: 'tree [directory]'"], 'subcommands': []}}
+ {'bat': {'description': ['Pretty prints the contents of a file.', "Syntax: 'bat <file>'"], 'subcommands': []}, 'cat': {'description': ['Get the contents of a file.', "Syntax: 'cat <file>'"], 'subcommands': []}, 'cd': {'description': ['Change the current working directory.', "Syntax: 'cd <directory>'"], 'subcommands': []}, 'close': {'description': ['Closes the SMB connection to the remote machine.', "Syntax: 'close'"], 'subcommands': []}, 'connect': {'description': ['Connect to the remote machine (useful if connection timed out).', "Syntax: 'connect'"], 'subcommands': []}, 'dir': {'description': ['List the contents of the current working directory.', "Syntax: 'dir'"], 'subcommands': []}, 'exit': {'description': ['Exits the smbclient-ng script.', "Syntax: 'exit'"], 'subcommands': []}, 'get': {'description': ['Get a remote file.', "Syntax: 'get [-r] <directory or file>'"], 'subcommands': []}, 'help': {'description': ['Displays this help message.', "Syntax: 'help'"], 'subcommands': ['format']}, 'info': {'description': ['Get information about the server and or the share.', "Syntax: 'info [server|share]'"], 'subcommands': ['server', 'share']}, 'lcd': {'description': ['Changes the current local directory.', "Syntax: 'lcd <directory>'"], 'subcommands': []}, 'lls': {'description': ['Lists the contents of the current local directory.', "Syntax: 'lls'"], 'subcommands': []}, 'lmkdir': {'description': ['Creates a new local directory.', "Syntax: 'lmkdir <directory>'"], 'subcommands': []}, 'lpwd': {'description': ['Shows the current local directory.', "Syntax: 'lpwd'"], 'subcommands': []}, 'lrm': {'description': ['Removes a local file.', "Syntax: 'lrm <file>'"], 'subcommands': []}, 'lrmdir': {'description': ['Removes a local directory.', "Syntax: 'lrmdir <directory>'"], 'subcommands': []}, 'ls': {'description': ['List the contents of the current remote working directory.', "Syntax: 'ls'"], 'subcommands': []}, 'ltree': {'description': ['Displays a tree view of the local directories.', "Syntax: 'ltree [directory]'"], 'subcommands': []}, 'mkdir': {'description': ['Creates a new remote directory.', "Syntax: 'mkdir <directory>'"], 'subcommands': []}, 'module': {'description': ['Loads a specific module for additional functionalities.', "Syntax: 'module <name>'"], 'subcommands': []}, 'put': {'description': ['Put a local file or directory in a remote directory.', "Syntax: 'put [-r] <directory or file>'"], 'subcommands': []}, 'reconnect': {'description': ['Reconnect to the remote machine (useful if connection timed out).', "Syntax: 'reconnect'"], 'subcommands': []}, 'reset': {'description': ['Reset the TTY output, useful if it was broken after printing a binary file on stdout.', "Syntax: 'reset'"], 'subcommands': []}, 'rmdir': {'description': ['Removes a remote directory.', "Syntax: 'rmdir <directory>'"], 'subcommands': []}, 'rm': {'description': ['Removes a remote file.', "Syntax: 'rm <file>'"], 'subcommands': []}, 'shares': {'description': ['Lists the SMB shares served by the remote machine.', "Syntax: 'shares'"], 'subcommands': []}, 'use': {'description': ['Use a SMB share.', "Syntax: 'use <sharename>'"], 'subcommands': []}, 'tree': {'description': ['Displays a tree view of the remote directories.', "Syntax: 'tree [directory]'"], 'subcommands': []}}
@@ -1065,141 +1093,141 @@
-
222defcomplete(self,text,state):
-223"""
-224 Function to handle command completion in the LDAP console.
-225
-226 This function completes the user"s input based on the available options for commands in the LDAP console.
-227
-228 Args:
-229 text (str): The current text input by the user.
-230 state (int): The current state of completion.
-231
-232 Returns:
-233 str: The next completion suggestion based on the user"s input state.
-234 """
-235
-236ifstate==0:
-237
-238# No text typed yet, need the list of commands available
-239iflen(text)==0:
-240self.matches=[sforsinself.commands.keys()]
+
236defcomplete(self,text,state):
+237"""
+238 Function to handle command completion in the LDAP console.
+239
+240 This function completes the user"s input based on the available options for commands in the LDAP console.241
-242eliflen(text)!=0:
-243# This is for the main command
-244iftext.count(" ")==0:
-245self.matches=[sforsinself.commands.keys()ifsands.startswith(text)]
-246
-247# This is for subcommands
-248eliftext.count(" ")>=1:
-249command,remainder=text.split(" ",1)
-250ifcommandinself.commands.keys():
-251ifcommand=="use":
-252# Choose SMB Share to connect to
-253self.matches=[
-254command+" "+s.lower()
-255forsinself.smbSession.list_shares().keys()
-256ifs.lower().startswith(remainder.lower())
-257]
-258
-259elifcommandin["cd","dir","ls","mkdir","rmdir","tree"]:
-260# Choose remote directory
-261path=""
-262if'\\'inremainder.strip()or'/'inremainder.strip():
-263path=remainder.strip().replace('/',ntpath.sep)
-264path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
-265
-266directory_contents=self.smbSession.list_contents(path=path).items()
-267
-268matching_entries=[]
-269for_,entryindirectory_contents:
-270ifentry.is_directory()andentry.get_longname()notin[".",".."]:
-271iflen(path)!=0:
-272matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
-273else:
-274matching_entries.append(entry.get_longname()+ntpath.sep)
-275
-276self.matches=[
-277command+" "+s
-278forsinmatching_entries
-279ifs.lower().startswith(remainder.lower())
-280]
+242 Args:
+243 text (str): The current text input by the user.
+244 state (int): The current state of completion.
+245
+246 Returns:
+247 str: The next completion suggestion based on the user"s input state.
+248 """
+249
+250ifstate==0:
+251
+252# No text typed yet, need the list of commands available
+253iflen(text)==0:
+254self.matches=[sforsinself.commands.keys()]
+255
+256eliflen(text)!=0:
+257# This is for the main command
+258iftext.count(" ")==0:
+259self.matches=[sforsinself.commands.keys()ifsands.startswith(text)]
+260
+261# This is for subcommands
+262eliftext.count(" ")>=1:
+263command,remainder=text.split(" ",1)
+264ifcommandinself.commands.keys():
+265ifcommand=="use":
+266# Choose SMB Share to connect to
+267self.matches=[
+268command+" "+s.lower()
+269forsinself.smbSession.list_shares().keys()
+270ifs.lower().startswith(remainder.lower())
+271]
+272
+273elifcommandin["cd","dir","ls","mkdir","rmdir","tree"]:
+274# Choose remote directory
+275path=""
+276if'\\'inremainder.strip()or'/'inremainder.strip():
+277path=remainder.strip().replace('/',ntpath.sep)
+278path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
+279
+280directory_contents=self.smbSession.list_contents(path=path).items()281
-282elifcommandin["get","rm"]:
-283# Choose local files and directories
-284path=""
-285if'\\'inremainder.strip()or'/'inremainder.strip():
-286path=remainder.strip().replace('/',ntpath.sep)
-287path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
-288
-289directory_contents=self.smbSession.list_contents(path=path).items()
-290
-291matching_entries=[]
-292for_,entryindirectory_contents:
-293ifentry.get_longname()notin[".",".."]:
-294iflen(path)!=0:
-295ifentry.is_directory():
-296matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
-297else:
-298matching_entries.append(path+ntpath.sep+entry.get_longname())
-299else:
-300ifentry.is_directory():
-301matching_entries.append(entry.get_longname()+ntpath.sep)
-302else:
-303matching_entries.append(entry.get_longname())
+282matching_entries=[]
+283for_,entryindirectory_contents:
+284ifentry.is_directory()andentry.get_longname()notin[".",".."]:
+285iflen(path)!=0:
+286matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
+287else:
+288matching_entries.append(entry.get_longname()+ntpath.sep)
+289
+290self.matches=[
+291command+" "+s
+292forsinmatching_entries
+293ifs.lower().startswith(remainder.lower())
+294]
+295
+296elifcommandin["bat","cat","get","rm"]:
+297# Choose local files and directories
+298path=""
+299if'\\'inremainder.strip()or'/'inremainder.strip():
+300path=remainder.strip().replace('/',ntpath.sep)
+301path=ntpath.sep.join(path.split(ntpath.sep)[:-1])
+302
+303directory_contents=self.smbSession.list_contents(path=path).items()304
-305self.matches=[
-306command+" "+s
-307forsinmatching_entries
-308ifs.lower().startswith(remainder.lower())
-309]
-310
-311elifcommandin["lcd","lls","put","lmkdir","lrm","lrmdir"]:
-312# Choose directory
-313path=""
-314ifos.path.sepinremainder.strip():
-315path=path.split(os.path.sep)[:-1]
-316path=os.path.sep.join(path)
-317
-318# Current dir
-319iflen(path.strip())==0:
-320path="."
-321
-322directory_contents=os.listdir(path=path+os.path.sep)
-323matching_entries=[]
-324forentryindirectory_contents:
-325ifentrynotin[".",".."]:
-326entry_path=path+os.path.sep+entry
-327ifos.path.isdir(entry_path):
-328matching_entries.append(entry_path+os.path.sep)
-329else:
-330matching_entries.append(entry_path)
-331
-332self.matches=[
-333command+" "+s
-334forsinmatching_entries
-335ifs.startswith(remainder)
-336]
-337
-338else:
-339# Generic case for subcommands
-340self.matches=[
-341command+" "+s
-342forsinself.commands[command]["subcommands"]
-343ifs.startswith(remainder)
-344]
-345else:
-346# Unknown subcommand, skipping autocomplete
-347pass
-348else:
-349self.matches=[]
-350else:
-351self.matches=self.commands.keys()[:]
-352
-353try:
-354returnself.matches[state]+" "
-355exceptIndexError:
-356returnNone
+305matching_entries=[]
+306for_,entryindirectory_contents:
+307ifentry.get_longname()notin[".",".."]:
+308iflen(path)!=0:
+309ifentry.is_directory():
+310matching_entries.append(path+ntpath.sep+entry.get_longname()+ntpath.sep)
+311else:
+312matching_entries.append(path+ntpath.sep+entry.get_longname())
+313else:
+314ifentry.is_directory():
+315matching_entries.append(entry.get_longname()+ntpath.sep)
+316else:
+317matching_entries.append(entry.get_longname())
+318
+319self.matches=[
+320command+" "+s
+321forsinmatching_entries
+322ifs.lower().startswith(remainder.lower())
+323]
+324
+325elifcommandin["lcd","lls","put","lmkdir","lrm","lrmdir"]:
+326# Choose directory
+327path=""
+328ifos.path.sepinremainder.strip():
+329path=path.split(os.path.sep)[:-1]
+330path=os.path.sep.join(path)
+331
+332# Current dir
+333iflen(path.strip())==0:
+334path="."
+335
+336directory_contents=os.listdir(path=path+os.path.sep)
+337matching_entries=[]
+338forentryindirectory_contents:
+339ifentrynotin[".",".."]:
+340entry_path=path+os.path.sep+entry
+341ifos.path.isdir(entry_path):
+342matching_entries.append(entry_path+os.path.sep)
+343else:
+344matching_entries.append(entry_path)
+345
+346self.matches=[
+347command+" "+s
+348forsinmatching_entries
+349ifs.startswith(remainder)
+350]
+351
+352else:
+353# Generic case for subcommands
+354self.matches=[
+355command+" "+s
+356forsinself.commands[command]["subcommands"]
+357ifs.startswith(remainder)
+358]
+359else:
+360# Unknown subcommand, skipping autocomplete
+361pass
+362else:
+363self.matches=[]
+364else:
+365self.matches=self.commands.keys()[:]
+366
+367try:
+368returnself.matches[state]+" "
+369exceptIndexError:
+370returnNone
@@ -1228,79 +1256,79 @@
-
358defprint_help(self,command=None):
-359"""
-360 Prints help information for a specific command or all commands if no command is specified.
-361
-362 This method displays the help information for the command passed as an argument. If no command is specified,
-363 it prints the help information for all available commands. The help information includes the command syntax,
-364 description, and any subcommands associated with it. This method is designed to provide users with the necessary
-365 guidance on how to use the commands in the smbclient-ng shell.
-366
-367 Args:
-368 command (str, optional): The command to display help information for. If None, help for all commands is displayed.
-369
-370 Returns:
-371 None
-372 """
-373
-374ifcommandisnotNone:
-375ifcommandnotinlist(self.commands.keys())+["format"]:
-376command=None
-377
-378# Print help for a specific command
-379ifcommandisnotNone:
-380ifcommand=="format":
-381self.print_help_format()
-382else:
-383print("│")
-384ifself.config.no_colors:
-385command_str=command+"─"*(15-len(command))
-386iflen(self.commands[command]["description"])==0:
-387print("│ ■ %s┤ "%command_str)
-388eliflen(self.commands[command]["description"])==1:
-389print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-390else:
-391print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-392forlineinself.commands[command]["description"][1:]:
-393print("│ %s│ %s "%(" "*(15+3),line))
-394else:
-395command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
-396iflen(self.commands[command]["description"])==0:
-397print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
-398eliflen(self.commands[command]["description"])==1:
-399print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-400else:
-401print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-402forlineinself.commands[command]["description"][1:]:
-403print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+2),line))
-404print("│")
-405# Generic help
-406else:
-407print("│")
-408commands=sorted(self.commands.keys())
-409forcommandincommands:
-410ifself.config.no_colors:
-411command_str=command+"─"*(15-len(command))
-412iflen(self.commands[command]["description"])==0:
-413print("│ ■ %s┤ "%command_str)
-414eliflen(self.commands[command]["description"])==1:
-415print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-416else:
-417print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
-418forlineinself.commands[command]["description"][1:]:
-419print("│ %s│ %s "%(" "*(15+2),line))
-420else:
-421command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
-422iflen(self.commands[command]["description"])==0:
-423print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
-424eliflen(self.commands[command]["description"])==1:
-425print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-426else:
-427print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
-428forlineinself.commands[command]["description"][1:]:
-429print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+3),line))
-430print("│")
+
372defprint_help(self,command=None):
+373"""
+374 Prints help information for a specific command or all commands if no command is specified.
+375
+376 This method displays the help information for the command passed as an argument. If no command is specified,
+377 it prints the help information for all available commands. The help information includes the command syntax,
+378 description, and any subcommands associated with it. This method is designed to provide users with the necessary
+379 guidance on how to use the commands in the smbclient-ng shell.
+380
+381 Args:
+382 command (str, optional): The command to display help information for. If None, help for all commands is displayed.
+383
+384 Returns:
+385 None
+386 """
+387
+388ifcommandisnotNone:
+389ifcommandnotinlist(self.commands.keys())+["format"]:
+390command=None
+391
+392# Print help for a specific command
+393ifcommandisnotNone:
+394ifcommand=="format":
+395self.print_help_format()
+396else:
+397print("│")
+398ifself.config.no_colors:
+399command_str=command+"─"*(15-len(command))
+400iflen(self.commands[command]["description"])==0:
+401print("│ ■ %s┤ "%command_str)
+402eliflen(self.commands[command]["description"])==1:
+403print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+404else:
+405print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+406forlineinself.commands[command]["description"][1:]:
+407print("│ %s│ %s "%(" "*(15+2),line))
+408else:
+409command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
+410iflen(self.commands[command]["description"])==0:
+411print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
+412eliflen(self.commands[command]["description"])==1:
+413print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+414else:
+415print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+416forlineinself.commands[command]["description"][1:]:
+417print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+3),line))
+418print("│")
+419# Generic help
+420else:
+421print("│")
+422commands=sorted(self.commands.keys())
+423forcommandincommands:
+424ifself.config.no_colors:
+425command_str=command+"─"*(15-len(command))
+426iflen(self.commands[command]["description"])==0:
+427print("│ ■ %s┤ "%command_str)
+428eliflen(self.commands[command]["description"])==1:
+429print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+430else:
+431print("│ ■ %s┤ %s "%(command_str,self.commands[command]["description"][0]))
+432forlineinself.commands[command]["description"][1:]:
+433print("│ %s│ %s "%(" "*(15+2),line))
+434else:
+435command_str=command+" \x1b[90m"+"─"*(15-len(command))+"\x1b[0m"
+436iflen(self.commands[command]["description"])==0:
+437print("│ ■ %s\x1b[90m┤\x1b[0m "%command_str)
+438eliflen(self.commands[command]["description"])==1:
+439print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+440else:
+441print("│ ■ %s\x1b[90m┤\x1b[0m %s "%(command_str,self.commands[command]["description"][0]))
+442forlineinself.commands[command]["description"][1:]:
+443print("│ %s\x1b[90m│\x1b[0m %s "%(" "*(15+3),line))
+444print("│")
@@ -1331,24 +1359,24 @@
-
432defprint_help_format(self):
-433"""
-434 Prints the help information for the 'format' used in remote 'ls' and 'dir' commands.
-435
-436 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning
-437 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory.
-438 """
-439
-440print("File attributes format:\n")
-441print("\x1b[1mdachnrst\x1b[0m")
-442print("\x1b[90m│││││││└──>\x1b[0m Temporary")
-443print("\x1b[90m││││││└───>\x1b[0m System")
-444print("\x1b[90m│││││└────>\x1b[0m Read-Only")
-445print("\x1b[90m││││└─────>\x1b[0m Normal")
-446print("\x1b[90m│││└──────>\x1b[0m Hidden")
-447print("\x1b[90m││└───────>\x1b[0m Compressed")
-448print("\x1b[90m│└────────>\x1b[0m Archived")
-449print("\x1b[90m└─────────>\x1b[0m Directory")
+
446defprint_help_format(self):
+447"""
+448 Prints the help information for the 'format' used in remote 'ls' and 'dir' commands.
+449
+450 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning
+451 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory.
+452 """
+453
+454print("File attributes format:\n")
+455print("\x1b[1mdachnrst\x1b[0m")
+456print("\x1b[90m│││││││└──>\x1b[0m Temporary")
+457print("\x1b[90m││││││└───>\x1b[0m System")
+458print("\x1b[90m│││││└────>\x1b[0m Read-Only")
+459print("\x1b[90m││││└─────>\x1b[0m Normal")
+460print("\x1b[90m│││└──────>\x1b[0m Hidden")
+461print("\x1b[90m││└───────>\x1b[0m Compressed")
+462print("\x1b[90m│└────────>\x1b[0m Archived")
+463print("\x1b[90m└─────────>\x1b[0m Directory")
48defsmb_share_is_set(func):
-49defwrapper(*args,**kwargs):
-50self,arguments,command=args[0],args[1],args[2]
-51ifself.smbSession.smb_shareisnotNone:
-52returnfunc(*args,**kwargs)
-53else:
-54print("[!] You must open a share first, try the 'use <share>' command.")
-55returnNone
-56returnwrapper
+
50defsmb_share_is_set(func):
+51defwrapper(*args,**kwargs):
+52self,arguments,command=args[0],args[1],args[2]
+53ifself.smbSession.smb_shareisnotNone:
+54returnfunc(*args,**kwargs)
+55else:
+56print("[!] You must open a share first, try the 'use <share>' command.")
+57returnNone
+58returnwrapper
@@ -931,629 +997,687 @@
-
59classInteractiveShell(object):
- 60"""
- 61 Class InteractiveShell is designed to manage the interactive command line interface for smbclient-ng.
- 62
- 63 This class handles user input, executes commands, and manages the state of the SMB session. It provides
- 64 a command line interface for users to interact with SMB shares, execute commands like directory listing,
- 65 file transfer, and more.
- 66
- 67 Attributes:
- 68 smbSession (SMBConnection): The active SMB connection session.
- 69 debug (bool): Flag to enable or disable debug mode.
- 70 smb_share (str): The current SMB share in use.
- 71 smb_path (str): The current path within the SMB share.
- 72 commandCompleterObject (CommandCompleter): Object to handle command completion and help generation.
- 73
- 74 Methods:
- 75 __init__(self, smbSession, debug=False): Initializes the InteractiveShell with the given SMB session and debug mode.
- 76 run(self): Starts the command line interface loop, processing user input until exit.
- 77 """
- 78
- 79def__init__(self,smbSession,config):
- 80# Objects
- 81self.smbSession=smbSession
- 82self.config=config
- 83self.commandCompleterObject=CommandCompleter(smbSession=self.smbSession,config=self.config)
- 84readline.set_completer(self.commandCompleterObject.complete)
- 85readline.parse_and_bind("tab: complete")
- 86readline.set_completer_delims("\n")
- 87# Additional modules
- 88self.modules={}
- 89self.__load_modules()
- 90
- 91defrun(self):
- 92running=True
- 93whilerunning:
- 94try:
- 95user_input=input(self.__prompt()).strip().split(" ")
- 96command,arguments=user_input[0].lower(),user_input[1:]
- 97
- 98# Exit the command line
- 99ifcommand=="exit":
-100running=False
-101
-102elifcommandinself.commandCompleterObject.commands.keys():
-103self.process_command(
-104command=command,
-105arguments=arguments
-106)
-107
-108elifcommand.strip()=="":
-109pass
-110
-111# Fallback to unknown command
-112else:
-113print("Unknown command. Type \"help\" for help.")
-114
-115exceptKeyboardInterruptase:
-116print()
-117
-118exceptEOFErrorase:
-119print()
-120running=False
-121
-122exceptExceptionase:
-123ifself.config.debug:
-124traceback.print_exc()
-125print("[!] Error: %s"%str(e))
-126
-127defprocess_command(self,command,arguments=[]):
-128# Skip
-129ifcommand.strip()=="":
-130pass
-131
-132# Display help
-133elifcommand=="help":
-134self.command_help(arguments,command)
-135
-136# Closes the current SMB session
-137elifcommand=="close":
-138self.command_close(arguments,command)
-139
-140# Change directory in the current share
-141elifcommand=="cd":
-142self.command_cd(arguments,command)
-143
-144# Get a file
-145elifcommand=="get":
-146self.command_get(arguments,command)
-147
-148# SMB server info
-149elifcommand=="info":
-150self.command_info(arguments,command)
-151
-152# List directory contents in a share
-153elifcommandin["ls","dir"]:
-154self.command_ls(arguments,command)
-155
-156# Creates a new remote directory
-157elifcommand=="mkdir":
-158self.command_mkdir(arguments,command)
-159
-160# Put a file
-161elifcommand=="put":
-162self.command_put(arguments,command)
-163
-164# Changes the current local directory
-165elifcommand=="lcd":
-166self.command_lcd(arguments,command)
-167
-168# Lists the contents of the current local directory
-169elifcommand=="lls":
-170self.command_lls(arguments,command)
-171
-172# Creates a new local directory
-173elifcommand=="lmkdir":
-174self.command_lmkdir(arguments,command)
-175
-176# Shows the current local directory
-177elifcommand=="lpwd":
-178self.command_lpwd(arguments,command)
-179
-180# Removes a local file
-181elifcommand=="lrm":
-182self.command_lrm(arguments,command)
-183
-184# Removes a local directory
-185elifcommand=="lrmdir":
-186self.command_lrmdir(arguments,command)
-187
-188# Shows the current local directory
-189elifcommand=="ltree":
-190self.command_ltree(arguments,command)
-191
-192# Modules
-193elifcommand=="module":
-194self.command_module(arguments,command)
-195
-196# Reconnects the current SMB session
-197elifcommandin["connect","reconnect"]:
-198self.command_reconnect(arguments,command)
-199
-200# Reset the TTY output
-201elifcommand=="reset":
-202self.command_reset(arguments,command)
-203
-204# Removes a remote file
-205elifcommand=="rm":
-206self.command_rm(arguments,command)
-207
-208# Removes a remote directory
-209elifcommand=="rmdir":
-210self.command_rmdir(arguments,command)
-211
-212# List shares
-213elifcommand=="shares":
-214self.command_shares(arguments,command)
-215
-216# Displays a tree view of the CWD
-217elifcommand=="tree":
-218self.command_tree(arguments,command)
-219
-220# Use a share
-221elifcommand=="use":
-222self.command_use(arguments,command)
-223
-224# Commands ================================================================
-225
-226@command_arguments_required
-227@active_smb_connection_needed
-228@smb_share_is_set
-229defcommand_cd(self,arguments,command):
-230# Command arguments required : Yes
-231# Active SMB connection needed : Yes
-232# SMB share needed : Yes
+
61classInteractiveShell(object):
+ 62"""
+ 63 Class InteractiveShell is designed to manage the interactive command line interface for smbclient-ng.
+ 64
+ 65 This class handles user input, executes commands, and manages the state of the SMB session. It provides
+ 66 a command line interface for users to interact with SMB shares, execute commands like directory listing,
+ 67 file transfer, and more.
+ 68
+ 69 Attributes:
+ 70 smbSession (SMBConnection): The active SMB connection session.
+ 71 debug (bool): Flag to enable or disable debug mode.
+ 72 smb_share (str): The current SMB share in use.
+ 73 smb_path (str): The current path within the SMB share.
+ 74 commandCompleterObject (CommandCompleter): Object to handle command completion and help generation.
+ 75
+ 76 Methods:
+ 77 __init__(self, smbSession, debug=False): Initializes the InteractiveShell with the given SMB session and debug mode.
+ 78 run(self): Starts the command line interface loop, processing user input until exit.
+ 79 """
+ 80
+ 81def__init__(self,smbSession,config):
+ 82# Objects
+ 83self.smbSession=smbSession
+ 84self.config=config
+ 85self.commandCompleterObject=CommandCompleter(smbSession=self.smbSession,config=self.config)
+ 86readline.set_completer(self.commandCompleterObject.complete)
+ 87readline.parse_and_bind("tab: complete")
+ 88readline.set_completer_delims("\n")
+ 89# Additional modules
+ 90self.modules={}
+ 91self.__load_modules()
+ 92
+ 93defrun(self):
+ 94running=True
+ 95whilerunning:
+ 96try:
+ 97user_input=input(self.__prompt()).strip().split(" ")
+ 98command,arguments=user_input[0].lower(),user_input[1:]
+ 99
+100# Exit the command line
+101ifcommand=="exit":
+102running=False
+103
+104elifcommandinself.commandCompleterObject.commands.keys():
+105self.process_command(
+106command=command,
+107arguments=arguments
+108)
+109
+110elifcommand.strip()=="":
+111pass
+112
+113# Fallback to unknown command
+114else:
+115print("Unknown command. Type \"help\" for help.")
+116
+117exceptKeyboardInterruptase:
+118print()
+119
+120exceptEOFErrorase:
+121print()
+122running=False
+123
+124exceptExceptionase:
+125ifself.config.debug:
+126traceback.print_exc()
+127print("[!] Error: %s"%str(e))
+128
+129defprocess_command(self,command,arguments=[]):
+130# Skip
+131ifcommand.strip()=="":
+132pass
+133
+134# Display help
+135elifcommand=="help":
+136self.command_help(arguments,command)
+137
+138# Cat the contents of a file
+139elifcommand=="bat":
+140self.command_bat(arguments,command)
+141
+142# Cat the contents of a file
+143elifcommand=="cat":
+144self.command_cat(arguments,command)
+145
+146# Closes the current SMB session
+147elifcommand=="close":
+148self.command_close(arguments,command)
+149
+150# Change directory in the current share
+151elifcommand=="cd":
+152self.command_cd(arguments,command)
+153
+154# Get a file
+155elifcommand=="get":
+156self.command_get(arguments,command)
+157
+158# SMB server info
+159elifcommand=="info":
+160self.command_info(arguments,command)
+161
+162# List directory contents in a share
+163elifcommandin["ls","dir"]:
+164self.command_ls(arguments,command)
+165
+166# Creates a new remote directory
+167elifcommand=="mkdir":
+168self.command_mkdir(arguments,command)
+169
+170# Put a file
+171elifcommand=="put":
+172self.command_put(arguments,command)
+173
+174# Changes the current local directory
+175elifcommand=="lcd":
+176self.command_lcd(arguments,command)
+177
+178# Lists the contents of the current local directory
+179elifcommand=="lls":
+180self.command_lls(arguments,command)
+181
+182# Creates a new local directory
+183elifcommand=="lmkdir":
+184self.command_lmkdir(arguments,command)
+185
+186# Shows the current local directory
+187elifcommand=="lpwd":
+188self.command_lpwd(arguments,command)
+189
+190# Removes a local file
+191elifcommand=="lrm":
+192self.command_lrm(arguments,command)
+193
+194# Removes a local directory
+195elifcommand=="lrmdir":
+196self.command_lrmdir(arguments,command)
+197
+198# Shows the current local directory
+199elifcommand=="ltree":
+200self.command_ltree(arguments,command)
+201
+202# Modules
+203elifcommand=="module":
+204self.command_module(arguments,command)
+205
+206# Reconnects the current SMB session
+207elifcommandin["connect","reconnect"]:
+208self.command_reconnect(arguments,command)
+209
+210# Reset the TTY output
+211elifcommand=="reset":
+212self.command_reset(arguments,command)
+213
+214# Removes a remote file
+215elifcommand=="rm":
+216self.command_rm(arguments,command)
+217
+218# Removes a remote directory
+219elifcommand=="rmdir":
+220self.command_rmdir(arguments,command)
+221
+222# List shares
+223elifcommand=="shares":
+224self.command_shares(arguments,command)
+225
+226# Displays a tree view of the CWD
+227elifcommand=="tree":
+228self.command_tree(arguments,command)
+229
+230# Use a share
+231elifcommand=="use":
+232self.command_use(arguments,command)233
-234path=' '.join(arguments)
-235try:
-236self.smbSession.set_cwd(path=path)
-237exceptimpacket.smbconnection.SessionErrorase:
-238print("[!] SMB Error: %s"%e)
-239
-240defcommand_close(self,arguments,command):
-241# Command arguments required : No
-242# Active SMB connection needed : No
-243# SMB share needed : No
-244
-245self.smbSession.ping_smb_session()
-246ifself.smbSession.connected:
-247self.smbSession.close_smb_session()
-248
-249@command_arguments_required
-250@active_smb_connection_needed
-251@smb_share_is_set
-252defcommand_get(self,arguments,command):
-253# Command arguments required : Yes
-254# Active SMB connection needed : Yes
-255# SMB share needed : Yes
-256
-257# Get files recursively
-258ifarguments[0]=="-r":
-259path=' '.join(arguments[1:]).replace('/',ntpath.sep)
-260try:
-261self.smbSession.get_file_recursively(path=path)
-262exceptimpacket.smbconnection.SessionErrorase:
-263print("[!] SMB Error: %s"%e)
-264# Get a single file
-265else:
-266path=' '.join(arguments).replace('/',ntpath.sep)
-267try:
-268self.smbSession.get_file(path=path)
-269exceptimpacket.smbconnection.SessionErrorase:
-270print("[!] SMB Error: %s"%e)
-271
-272defcommand_help(self,arguments,command):
-273# Command arguments required : No
-274# Active SMB connection needed : No
-275# SMB share needed : No
-276
-277iflen(arguments)!=0:
-278self.commandCompleterObject.print_help(command=arguments[0])
-279else:
-280self.commandCompleterObject.print_help(command=None)
-281
-282@active_smb_connection_needed
-283defcommand_info(self,arguments,command):
-284# Command arguments required : No
-285# Active SMB connection needed : Yes
-286# SMB share needed : No
-287
-288print_server_info=False
-289print_share_info=False
-290iflen(arguments)!=0:
-291print_server_info=(arguments[0].lower()=="server")
-292print_share_info=(arguments[0].lower()=="share")
-293else:
-294print_server_info=True
-295print_share_info=True
-296
-297try:
-298self.smbSession.info(
-299share=print_share_info,
-300server=print_server_info
-301)
-302exceptimpacket.smbconnection.SessionErrorase:
-303print("[!] SMB Error: %s"%e)
+234# Commands ================================================================
+235
+236@command_arguments_required
+237@active_smb_connection_needed
+238@smb_share_is_set
+239defcommand_bat(self,arguments,command):
+240# Command arguments required : Yes
+241# Active SMB connection needed : Yes
+242# SMB share needed : Yes
+243
+244path=' '.join(arguments)
+245try:
+246rawcontents=self.smbSession.read_file(path=path)
+247ifrawcontentsisnotNone:
+248encoding=charset_normalizer.detect(rawcontents)["encoding"]
+249ifencodingisnotNone:
+250filecontent=rawcontents.decode(encoding).rstrip()
+251lexer=Syntax.guess_lexer(path=ntpath.basename(path),code=filecontent)
+252# Some trickery for the files undetected by the lexer
+253iflexer=="default":
+254if'<?xml'infilecontent:
+255lexer="xml"
+256elif'<html>'infilecontent:
+257lexer="html"
+258syntax=Syntax(code=filecontent,line_numbers=True,lexer=lexer)
+259Console().print(syntax)
+260else:
+261print("[!] Could not detect charset of '%s'."%path)
+262exceptimpacket.smbconnection.SessionErrorase:
+263print("[!] SMB Error: %s"%e)
+264
+265@command_arguments_required
+266@active_smb_connection_needed
+267@smb_share_is_set
+268defcommand_cd(self,arguments,command):
+269# Command arguments required : Yes
+270# Active SMB connection needed : Yes
+271# SMB share needed : Yes
+272
+273path=' '.join(arguments)
+274try:
+275self.smbSession.set_cwd(path=path)
+276exceptimpacket.smbconnection.SessionErrorase:
+277print("[!] SMB Error: %s"%e)
+278
+279@command_arguments_required
+280@active_smb_connection_needed
+281@smb_share_is_set
+282defcommand_cat(self,arguments,command):
+283# Command arguments required : Yes
+284# Active SMB connection needed : Yes
+285# SMB share needed : Yes
+286
+287path=' '.join(arguments)
+288try:
+289rawcontents=self.smbSession.read_file(path=path)
+290ifrawcontentsisnotNone:
+291encoding=charset_normalizer.detect(rawcontents)["encoding"]
+292ifencodingisnotNone:
+293filecontent=rawcontents.decode(encoding).rstrip()
+294print(filecontent)
+295else:
+296print("[!] Could not detect charset of '%s'."%path)
+297exceptimpacket.smbconnection.SessionErrorase:
+298print("[!] SMB Error: %s"%e)
+299
+300defcommand_close(self,arguments,command):
+301# Command arguments required : No
+302# Active SMB connection needed : No
+303# SMB share needed : No304
-305@command_arguments_required
-306defcommand_lcd(self,arguments,command):
-307# Command arguments required : Yes
-308# Active SMB connection needed : No
-309# SMB share needed : No
-310
-311path=' '.join(arguments)
-312ifos.path.exists(path=path):
-313ifos.path.isdir(s=path):
-314os.chdir(path=path)
-315else:
-316print("[!] Path '%s' is not a directory."%path)
-317else:
-318print("[!] Directory '%s' does not exists."%path)
-319
-320defcommand_lls(self,arguments,command):
-321# Command arguments required : No
-322# Active SMB connection needed : No
-323# SMB share needed : No
-324
-325iflen(arguments)==0:
-326path='.'
-327else:
-328path=' '.join(arguments)
-329
-330# lls <directory>
-331ifos.path.isdir(path):
-332directory_contents=os.listdir(path=path)
-333forentrynameinsorted(directory_contents):
-334path_to_file=path+os.path.sep+entryname
-335rights_str=unix_permissions(path_to_file)
-336size_str=b_filesize(os.path.getsize(filename=path_to_file))
-337date_str=datetime.datetime.fromtimestamp(os.path.getmtime(filename=path_to_file)).strftime("%Y-%m-%d %H:%M")
-338
-339ifos.path.isdir(s=entryname):
-340ifself.config.no_colors:
-341print("%s%10s%s%s%s"%(rights_str,size_str,date_str,entryname,os.path.sep))
-342else:
-343print("%s%10s%s\x1b[1;96m%s\x1b[0m%s"%(rights_str,size_str,date_str,entryname,os.path.sep))
-344else:
-345ifself.config.no_colors:
-346print("%s%10s%s%s"%(rights_str,size_str,date_str,entryname))
-347else:
-348print("%s%10s%s\x1b[1m%s\x1b[0m"%(rights_str,size_str,date_str,entryname))
-349# lls <file>
-350elifos.path.isfile(path):
-351rights_str=unix_permissions(path)
-352size_str=b_filesize(os.path.getsize(filename=path))
-353date_str=datetime.datetime.fromtimestamp(os.path.getmtime(filename=path)).strftime("%Y-%m-%d %H:%M")
-354ifself.config.no_colors:
-355print("%s%10s%s%s"%(rights_str,size_str,date_str,os.path.basename(path)))
-356else:
-357print("%s%10s%s\x1b[1m%s\x1b[0m"%(rights_str,size_str,date_str,os.path.basename(path)))
-358else:
-359print("[!] No such file or directory.")
-360
-361@command_arguments_required
-362defcommand_lmkdir(self,arguments,command):
-363# Command arguments required : Yes
-364# Active SMB connection needed : No
-365# SMB share needed : No
-366
-367path=' '.join(arguments)
-368
-369# Split each dir
-370ifos.path.sepinpath:
-371path=path.strip(os.path.sep).split(os.path.sep)
-372else:
-373path=[path]
-374
-375# Create each dir in the path
-376fordepthinrange(1,len(path)+1):
-377tmp_path=os.path.sep.join(path[:depth])
-378ifnotos.path.exists(tmp_path):
-379os.mkdir(path=tmp_path)
-380
-381defcommand_lpwd(self,arguments,command):
-382# Command arguments required : No
-383# Active SMB connection needed : No
-384# SMB share needed : No
-385
-386print(os.getcwd())
-387
-388@command_arguments_required
-389defcommand_lrm(self,arguments,command):
-390# Command arguments required : Yes
-391# Active SMB connection needed : No
-392# SMB share needed : No
-393
-394path=' '.join(arguments)
-395ifos.path.exists(path):
-396ifnotos.path.isdir(s=path):
-397try:
-398os.remove(path=path)
-399exceptExceptionase:
-400print("[!] Error removing file '%s' : %s"%path)
-401else:
-402print("[!] Cannot delete '%s'. It is a directory, use 'lrmdir <directory>' instead."%path)
-403else:
-404print("[!] Path '%s' does not exist."%path)
-405
-406@command_arguments_required
-407defcommand_lrmdir(self,arguments,command):
-408# Command arguments required : Yes
-409# Active SMB connection needed : No
-410# SMB share needed : No
-411
-412path=' '.join(arguments)
-413ifos.path.exists(path):
-414ifos.path.isdir(s=path):
-415try:
-416shutil.rmtree(path=path)
-417exceptExceptionase:
-418print("[!] Error removing directory '%s' : %s"%path)
-419else:
-420print("[!] Cannot delete '%s'. It is a file, use 'lrm <file>' instead."%path)
-421else:
-422print("[!] Path '%s' does not exist."%path)
-423
-424defcommand_ltree(self,arguments,command):
-425# Command arguments required : No
-426# Active SMB connection needed : No
-427# SMB share needed : No
+305self.smbSession.ping_smb_session()
+306ifself.smbSession.connected:
+307self.smbSession.close_smb_session()
+308
+309@command_arguments_required
+310@active_smb_connection_needed
+311@smb_share_is_set
+312defcommand_get(self,arguments,command):
+313# Command arguments required : Yes
+314# Active SMB connection needed : Yes
+315# SMB share needed : Yes
+316
+317# Get files recursively
+318ifarguments[0]=="-r":
+319path=' '.join(arguments[1:]).replace('/',ntpath.sep)
+320try:
+321self.smbSession.get_file_recursively(path=path)
+322exceptimpacket.smbconnection.SessionErrorase:
+323print("[!] SMB Error: %s"%e)
+324# Get a single file
+325else:
+326path=' '.join(arguments).replace('/',ntpath.sep)
+327try:
+328self.smbSession.get_file(path=path)
+329exceptimpacket.smbconnection.SessionErrorase:
+330print("[!] SMB Error: %s"%e)
+331
+332defcommand_help(self,arguments,command):
+333# Command arguments required : No
+334# Active SMB connection needed : No
+335# SMB share needed : No
+336
+337iflen(arguments)!=0:
+338self.commandCompleterObject.print_help(command=arguments[0])
+339else:
+340self.commandCompleterObject.print_help(command=None)
+341
+342@active_smb_connection_needed
+343defcommand_info(self,arguments,command):
+344# Command arguments required : No
+345# Active SMB connection needed : Yes
+346# SMB share needed : No
+347
+348print_server_info=False
+349print_share_info=False
+350iflen(arguments)!=0:
+351print_server_info=(arguments[0].lower()=="server")
+352print_share_info=(arguments[0].lower()=="share")
+353else:
+354print_server_info=True
+355print_share_info=True
+356
+357try:
+358self.smbSession.info(
+359share=print_share_info,
+360server=print_server_info
+361)
+362exceptimpacket.smbconnection.SessionErrorase:
+363print("[!] SMB Error: %s"%e)
+364
+365@command_arguments_required
+366defcommand_lcd(self,arguments,command):
+367# Command arguments required : Yes
+368# Active SMB connection needed : No
+369# SMB share needed : No
+370
+371path=' '.join(arguments)
+372ifos.path.exists(path=path):
+373ifos.path.isdir(s=path):
+374os.chdir(path=path)
+375else:
+376print("[!] Path '%s' is not a directory."%path)
+377else:
+378print("[!] Directory '%s' does not exists."%path)
+379
+380defcommand_lls(self,arguments,command):
+381# Command arguments required : No
+382# Active SMB connection needed : No
+383# SMB share needed : No
+384
+385iflen(arguments)==0:
+386path='.'
+387else:
+388path=' '.join(arguments)
+389
+390# lls <directory>
+391ifos.path.isdir(path):
+392directory_contents=os.listdir(path=path)
+393forentrynameinsorted(directory_contents):
+394path_to_file=path+os.path.sep+entryname
+395rights_str=unix_permissions(path_to_file)
+396size_str=b_filesize(os.path.getsize(filename=path_to_file))
+397date_str=datetime.datetime.fromtimestamp(os.path.getmtime(filename=path_to_file)).strftime("%Y-%m-%d %H:%M")
+398
+399ifos.path.isdir(s=entryname):
+400ifself.config.no_colors:
+401print("%s%10s%s%s%s"%(rights_str,size_str,date_str,entryname,os.path.sep))
+402else:
+403print("%s%10s%s\x1b[1;96m%s\x1b[0m%s"%(rights_str,size_str,date_str,entryname,os.path.sep))
+404else:
+405ifself.config.no_colors:
+406print("%s%10s%s%s"%(rights_str,size_str,date_str,entryname))
+407else:
+408print("%s%10s%s\x1b[1m%s\x1b[0m"%(rights_str,size_str,date_str,entryname))
+409# lls <file>
+410elifos.path.isfile(path):
+411rights_str=unix_permissions(path)
+412size_str=b_filesize(os.path.getsize(filename=path))
+413date_str=datetime.datetime.fromtimestamp(os.path.getmtime(filename=path)).strftime("%Y-%m-%d %H:%M")
+414ifself.config.no_colors:
+415print("%s%10s%s%s"%(rights_str,size_str,date_str,os.path.basename(path)))
+416else:
+417print("%s%10s%s\x1b[1m%s\x1b[0m"%(rights_str,size_str,date_str,os.path.basename(path)))
+418else:
+419print("[!] No such file or directory.")
+420
+421@command_arguments_required
+422defcommand_lmkdir(self,arguments,command):
+423# Command arguments required : Yes
+424# Active SMB connection needed : No
+425# SMB share needed : No
+426
+427path=' '.join(arguments)428
-429iflen(arguments)==0:
-430local_tree(path='.',config=self.config)
-431else:
-432local_tree(path=' '.join(arguments),config=self.config)
-433
-434@active_smb_connection_needed
-435@smb_share_is_set
-436defcommand_ls(self,arguments,command):
-437# Command arguments required : No
-438# Active SMB connection needed : Yes
-439# SMB share needed : Yes
+429# Split each dir
+430ifos.path.sepinpath:
+431path=path.strip(os.path.sep).split(os.path.sep)
+432else:
+433path=[path]
+434
+435# Create each dir in the path
+436fordepthinrange(1,len(path)+1):
+437tmp_path=os.path.sep.join(path[:depth])
+438ifnotos.path.exists(tmp_path):
+439os.mkdir(path=tmp_path)440
-441# Read the files
-442directory_contents=self.smbSession.list_contents(path=' '.join(arguments))
-443
-444forlongnameinsorted(directory_contents.keys(),key=lambdax:x.lower()):
-445windows_ls_entry(directory_contents[longname],self.config)
-446
-447@command_arguments_required
-448@active_smb_connection_needed
-449@smb_share_is_set
-450defcommand_mkdir(self,arguments,command):
-451# Command arguments required : Yes
-452# Active SMB connection needed : Yes
-453# SMB share needed : Yes
-454
-455path=' '.join(arguments)
-456self.smbSession.mkdir(path=path)
-457
-458@command_arguments_required
-459@active_smb_connection_needed
-460@smb_share_is_set
-461defcommand_module(self,arguments,command):
-462module_name=arguments[0]
-463
-464ifmodule_nameinself.modules.keys():
-465module=self.modules[module_name](self.smbSession,self.config)
-466module.run(' '.join(arguments[1:]))
-467else:
-468print("[!] Module '%s' does not exist."%module_name)
-469
-470@command_arguments_required
-471@active_smb_connection_needed
-472@smb_share_is_set
-473defcommand_put(self,arguments,command):
-474# Command arguments required : Yes
-475# Active SMB connection needed : Yes
-476# SMB share needed : Yes
-477
-478# Put files recursively
-479ifarguments[0]=="-r":
-480localpath=' '.join(arguments[1:])
-481try:
-482self.smbSession.put_file_recursively(localpath=localpath)
-483exceptimpacket.smbconnection.SessionErrorase:
-484print("[!] SMB Error: %s"%e)
-485
-486# Put a single file
-487else:
-488localpath=' '.join(arguments)
-489try:
-490self.smbSession.put_file(localpath=localpath)
-491exceptimpacket.smbconnection.SessionErrorase:
-492print("[!] SMB Error: %s"%e)
+441defcommand_lpwd(self,arguments,command):
+442# Command arguments required : No
+443# Active SMB connection needed : No
+444# SMB share needed : No
+445
+446print(os.getcwd())
+447
+448@command_arguments_required
+449defcommand_lrm(self,arguments,command):
+450# Command arguments required : Yes
+451# Active SMB connection needed : No
+452# SMB share needed : No
+453
+454path=' '.join(arguments)
+455ifos.path.exists(path):
+456ifnotos.path.isdir(s=path):
+457try:
+458os.remove(path=path)
+459exceptExceptionase:
+460print("[!] Error removing file '%s' : %s"%path)
+461else:
+462print("[!] Cannot delete '%s'. It is a directory, use 'lrmdir <directory>' instead."%path)
+463else:
+464print("[!] Path '%s' does not exist."%path)
+465
+466@command_arguments_required
+467defcommand_lrmdir(self,arguments,command):
+468# Command arguments required : Yes
+469# Active SMB connection needed : No
+470# SMB share needed : No
+471
+472path=' '.join(arguments)
+473ifos.path.exists(path):
+474ifos.path.isdir(s=path):
+475try:
+476shutil.rmtree(path=path)
+477exceptExceptionase:
+478print("[!] Error removing directory '%s' : %s"%path)
+479else:
+480print("[!] Cannot delete '%s'. It is a file, use 'lrm <file>' instead."%path)
+481else:
+482print("[!] Path '%s' does not exist."%path)
+483
+484defcommand_ltree(self,arguments,command):
+485# Command arguments required : No
+486# Active SMB connection needed : No
+487# SMB share needed : No
+488
+489iflen(arguments)==0:
+490local_tree(path='.',config=self.config)
+491else:
+492local_tree(path=' '.join(arguments),config=self.config)493
-494defcommand_reconnect(self,arguments,command):
-495# Command arguments required : No
-496# Active SMB connection needed : No
-497# SMB share needed : No
-498
-499self.smbSession.ping_smb_session()
-500ifself.smbSession.connected:
-501self.smbSession.close_smb_session()
-502self.smbSession.init_smb_session()
-503else:
-504self.smbSession.init_smb_session()
-505
-506defcommand_reset(self,arguments,command):
-507# Command arguments required : No
-508# Active SMB connection needed : No
-509# SMB share needed : No
-510sys.stdout.write('\x1b[?25h')# Sets the cursor to on
-511sys.stdout.write('\x1b[v')
-512sys.stdout.write('\x1b[o')# Reset
-513sys.stdout.flush()
+494@active_smb_connection_needed
+495@smb_share_is_set
+496defcommand_ls(self,arguments,command):
+497# Command arguments required : No
+498# Active SMB connection needed : Yes
+499# SMB share needed : Yes
+500
+501# Read the files
+502directory_contents=self.smbSession.list_contents(path=' '.join(arguments))
+503
+504forlongnameinsorted(directory_contents.keys(),key=lambdax:x.lower()):
+505windows_ls_entry(directory_contents[longname],self.config)
+506
+507@command_arguments_required
+508@active_smb_connection_needed
+509@smb_share_is_set
+510defcommand_mkdir(self,arguments,command):
+511# Command arguments required : Yes
+512# Active SMB connection needed : Yes
+513# SMB share needed : Yes514
-515@command_arguments_required
-516@active_smb_connection_needed
-517@smb_share_is_set
-518defcommand_rm(self,arguments,command):
-519# Command arguments required : Yes
-520# Active SMB connection needed : Yes
-521# SMB share needed : Yes
-522
-523path=' '.join(arguments)
-524ifself.smbSession.path_exists(path):
-525ifself.smbSession.path_isfile(path):
-526try:
-527self.smbSession.rm(path=path)
-528exceptExceptionase:
-529print("[!] Error removing file '%s' : %s"%path)
-530else:
-531print("[!] Cannot delete '%s': This is a directory, use 'rmdir <directory>' instead."%path)
-532else:
-533print("[!] Remote file '%s' does not exist."%path)
-534
-535@command_arguments_required
-536@active_smb_connection_needed
-537@smb_share_is_set
-538defcommand_rmdir(self,arguments,command):
-539# Command arguments required : Yes
-540# Active SMB connection needed : Yes
-541# SMB share needed : Yes
-542
-543path=' '.join(arguments)
-544ifself.smbSession.path_exists(path):
-545ifself.smbSession.path_isdir(path):
-546try:
-547self.smbSession.rmdir(path=path)
-548exceptExceptionase:
-549print("[!] Error removing directory '%s' : %s"%path)
-550else:
-551print("[!] Cannot delete '%s': This is a file, use 'rm <file>' instead."%path)
-552else:
-553print("[!] Remote directory '%s' does not exist."%path)
-554
-555@active_smb_connection_needed
-556defcommand_shares(self,arguments,command):
-557# Command arguments required : No
-558# Active SMB connection needed : Yes
-559# SMB share needed : No
-560
-561shares=self.smbSession.list_shares()
-562iflen(shares.keys())!=0:
-563table=Table(title=None)
-564table.add_column("Share")
-565table.add_column("Hidden")
-566table.add_column("Type")
-567table.add_column("Description",justify="left")
-568
-569forsharenameinsorted(shares.keys()):
-570is_hidden=bool(sharename.endswith('$'))
-571types=', '.join([s.replace("STYPE_","")forsinshares[sharename]["type"]])
-572ifis_hidden:
-573table.add_row(sharename,str(is_hidden),types,shares[sharename]["comment"])
-574else:
-575table.add_row(sharename,str(is_hidden),types,shares[sharename]["comment"])
-576
-577Console().print(table)
-578else:
-579print("[!] No share served on '%s'"%self.smbSession.address)
-580
-581@active_smb_connection_needed
-582@smb_share_is_set
-583defcommand_tree(self,arguments,command):
-584# Command arguments required : No
-585# Active SMB connection needed : Yes
-586# SMB share needed : Yes
-587
-588iflen(arguments)==0:
-589self.smbSession.tree(path='.')
-590else:
-591self.smbSession.tree(path=' '.join(arguments))
-592
-593@command_arguments_required
-594@active_smb_connection_needed
-595defcommand_use(self,arguments,command):
-596# Command arguments required : Yes
-597# Active SMB connection needed : Yes
-598# SMB share needed : No
-599
-600sharename=' '.join(arguments)
-601# Reload the list of shares
-602shares=self.smbSession.list_shares()
-603shares=[s.lower()forsinshares.keys()]
-604ifsharename.lower()inshares:
-605self.smbSession.set_share(sharename)
-606else:
-607print("[!] No share named '%s' on '%s'"%(sharename,self.smbSession.address))
-608
-609# Private functions =======================================================
-610
-611def__load_modules(self):
-612
-613
-614self.modules.clear()
-615
-616modules_dir=os.path.normpath(os.path.dirname(__file__)+os.path.sep+".."+os.path.sep+"modules")
-617ifself.config.debug:
-618print("[debug] Loading modules from %s ..."%modules_dir)
-619sys.path.extend([modules_dir])
+515path=' '.join(arguments)
+516self.smbSession.mkdir(path=path)
+517
+518@command_arguments_required
+519@active_smb_connection_needed
+520@smb_share_is_set
+521defcommand_module(self,arguments,command):
+522module_name=arguments[0]
+523
+524ifmodule_nameinself.modules.keys():
+525module=self.modules[module_name](self.smbSession,self.config)
+526module.run(' '.join(arguments[1:]))
+527else:
+528print("[!] Module '%s' does not exist."%module_name)
+529
+530@command_arguments_required
+531@active_smb_connection_needed
+532@smb_share_is_set
+533defcommand_put(self,arguments,command):
+534# Command arguments required : Yes
+535# Active SMB connection needed : Yes
+536# SMB share needed : Yes
+537
+538# Put files recursively
+539ifarguments[0]=="-r":
+540localpath=' '.join(arguments[1:])
+541try:
+542self.smbSession.put_file_recursively(localpath=localpath)
+543exceptimpacket.smbconnection.SessionErrorase:
+544print("[!] SMB Error: %s"%e)
+545
+546# Put a single file
+547else:
+548localpath=' '.join(arguments)
+549try:
+550self.smbSession.put_file(localpath=localpath)
+551exceptimpacket.smbconnection.SessionErrorase:
+552print("[!] SMB Error: %s"%e)
+553
+554defcommand_reconnect(self,arguments,command):
+555# Command arguments required : No
+556# Active SMB connection needed : No
+557# SMB share needed : No
+558
+559self.smbSession.ping_smb_session()
+560ifself.smbSession.connected:
+561self.smbSession.close_smb_session()
+562self.smbSession.init_smb_session()
+563else:
+564self.smbSession.init_smb_session()
+565
+566defcommand_reset(self,arguments,command):
+567# Command arguments required : No
+568# Active SMB connection needed : No
+569# SMB share needed : No
+570sys.stdout.write('\x1b[?25h')# Sets the cursor to on
+571sys.stdout.write('\x1b[v')
+572sys.stdout.write('\x1b[o')# Reset
+573sys.stdout.flush()
+574
+575@command_arguments_required
+576@active_smb_connection_needed
+577@smb_share_is_set
+578defcommand_rm(self,arguments,command):
+579# Command arguments required : Yes
+580# Active SMB connection needed : Yes
+581# SMB share needed : Yes
+582
+583path=' '.join(arguments)
+584ifself.smbSession.path_exists(path):
+585ifself.smbSession.path_isfile(path):
+586try:
+587self.smbSession.rm(path=path)
+588exceptExceptionase:
+589print("[!] Error removing file '%s' : %s"%path)
+590else:
+591print("[!] Cannot delete '%s': This is a directory, use 'rmdir <directory>' instead."%path)
+592else:
+593print("[!] Remote file '%s' does not exist."%path)
+594
+595@command_arguments_required
+596@active_smb_connection_needed
+597@smb_share_is_set
+598defcommand_rmdir(self,arguments,command):
+599# Command arguments required : Yes
+600# Active SMB connection needed : Yes
+601# SMB share needed : Yes
+602
+603path=' '.join(arguments)
+604ifself.smbSession.path_exists(path):
+605ifself.smbSession.path_isdir(path):
+606try:
+607self.smbSession.rmdir(path=path)
+608exceptExceptionase:
+609print("[!] Error removing directory '%s' : %s"%path)
+610else:
+611print("[!] Cannot delete '%s': This is a file, use 'rm <file>' instead."%path)
+612else:
+613print("[!] Remote directory '%s' does not exist."%path)
+614
+615@active_smb_connection_needed
+616defcommand_shares(self,arguments,command):
+617# Command arguments required : No
+618# Active SMB connection needed : Yes
+619# SMB share needed : No620
-621forfileinos.listdir(modules_dir):
-622filepath=os.path.normpath(modules_dir+os.path.sep+file)
-623iffile.endswith('.py'):
-624ifos.path.isfile(filepath)andfilenotin["__init__.py"]:
-625try:
-626module_file=import_module('smbclientng.modules.%s'%(file[:-3]))
-627module=module_file.__getattribute__(file[:-3])
-628self.modules[module.name.lower()]=module
-629exceptAttributeErrorase:
-630pass
-631
-632ifself.config.debug:
-633iflen(self.modules.keys())==0:
-634print("[debug] Loaded 0 modules.")
-635eliflen(self.modules.keys())==1:
-636print("[debug] Loaded 1 module:")
-637else:
-638print("[debug] Loaded %d modules:"%len(self.modules.keys()))
-639formodulenameinsorted(self.modules.keys()):
-640print("[debug] %s : \"%s\""%(module.name,module.description))
-641
-642ifself.commandCompleterObjectisnotNone:
-643self.commandCompleterObject.commands["module"]["subcommands"]=list(self.modules.keys())
-644
-645def__prompt(self):
-646"""
-647 Prints the command prompt for the interactive shell.
-648
-649 This method constructs and returns the command prompt string based on the current state of the SMB session.
-650 The prompt indicates the connection status with a visual symbol and displays the current working directory
-651 or the SMB share path. The prompt appearance changes based on whether colors are enabled in the configuration.
+621shares=self.smbSession.list_shares()
+622iflen(shares.keys())!=0:
+623table=Table(title=None)
+624table.add_column("Share")
+625table.add_column("Hidden")
+626table.add_column("Type")
+627table.add_column("Description",justify="left")
+628
+629forsharenameinsorted(shares.keys()):
+630is_hidden=bool(sharename.endswith('$'))
+631types=', '.join([s.replace("STYPE_","")forsinshares[sharename]["type"]])
+632ifis_hidden:
+633table.add_row(sharename,str(is_hidden),types,shares[sharename]["comment"])
+634else:
+635table.add_row(sharename,str(is_hidden),types,shares[sharename]["comment"])
+636
+637Console().print(table)
+638else:
+639print("[!] No share served on '%s'"%self.smbSession.address)
+640
+641@active_smb_connection_needed
+642@smb_share_is_set
+643defcommand_tree(self,arguments,command):
+644# Command arguments required : No
+645# Active SMB connection needed : Yes
+646# SMB share needed : Yes
+647
+648iflen(arguments)==0:
+649self.smbSession.tree(path='.')
+650else:
+651self.smbSession.tree(path=' '.join(arguments))652
-653 Returns:
-654 str: The formatted command prompt string.
-655 """
-656
-657self.smbSession.ping_smb_session()
-658ifself.smbSession.connected:
-659ifself.config.no_colors:
-660connected_dot="[v]"
-661else:
-662connected_dot="\x1b[1;92m⏺\x1b[0m"
-663else:
-664ifself.config.no_colors:
-665connected_dot="[x]"
-666else:
-667connected_dot="\x1b[1;91m⏺\x1b[0m"
-668
-669ifself.smbSession.smb_shareisNone:
-670ifself.config.no_colors:
-671str_prompt="%s[\\\\%s\\]> "%(connected_dot,self.smbSession.address)
-672else:
-673str_prompt="%s[\x1b[1;94m\\\\%s\\\x1b[0m]> "%(connected_dot,self.smbSession.address)
-674else:
-675str_path="\\\\%s\\%s\\%s"%(self.smbSession.address,self.smbSession.smb_share,self.smbSession.smb_cwd.lstrip(ntpath.sep))
-676ifself.config.no_colors:
-677str_prompt="%s[%s]> "%(connected_dot,str_path)
-678else:
-679str_prompt="%s[\x1b[1;94m%s\x1b[0m]> "%(connected_dot,str_path)
+653@command_arguments_required
+654@active_smb_connection_needed
+655defcommand_use(self,arguments,command):
+656# Command arguments required : Yes
+657# Active SMB connection needed : Yes
+658# SMB share needed : No
+659
+660sharename=' '.join(arguments)
+661# Reload the list of shares
+662shares=self.smbSession.list_shares()
+663shares=[s.lower()forsinshares.keys()]
+664ifsharename.lower()inshares:
+665self.smbSession.set_share(sharename)
+666else:
+667print("[!] No share named '%s' on '%s'"%(sharename,self.smbSession.address))
+668
+669# Private functions =======================================================
+670
+671def__load_modules(self):
+672
+673
+674self.modules.clear()
+675
+676modules_dir=os.path.normpath(os.path.dirname(__file__)+os.path.sep+".."+os.path.sep+"modules")
+677ifself.config.debug:
+678print("[debug] Loading modules from %s ..."%modules_dir)
+679sys.path.extend([modules_dir])680
-681returnstr_prompt
+681forfileinos.listdir(modules_dir):
+682filepath=os.path.normpath(modules_dir+os.path.sep+file)
+683iffile.endswith('.py'):
+684ifos.path.isfile(filepath)andfilenotin["__init__.py"]:
+685try:
+686module_file=import_module('smbclientng.modules.%s'%(file[:-3]))
+687module=module_file.__getattribute__(file[:-3])
+688self.modules[module.name.lower()]=module
+689exceptAttributeErrorase:
+690pass
+691
+692ifself.config.debug:
+693iflen(self.modules.keys())==0:
+694print("[debug] Loaded 0 modules.")
+695eliflen(self.modules.keys())==1:
+696print("[debug] Loaded 1 module:")
+697else:
+698print("[debug] Loaded %d modules:"%len(self.modules.keys()))
+699formodulenameinsorted(self.modules.keys()):
+700print("[debug] %s : \"%s\" (%s)"%(self.modules[modulename].name,self.modules[modulename].description,self.modules[modulename]))
+701
+702ifself.commandCompleterObjectisnotNone:
+703self.commandCompleterObject.commands["module"]["subcommands"]=list(self.modules.keys())
+704
+705def__prompt(self):
+706"""
+707 Prints the command prompt for the interactive shell.
+708
+709 This method constructs and returns the command prompt string based on the current state of the SMB session.
+710 The prompt indicates the connection status with a visual symbol and displays the current working directory
+711 or the SMB share path. The prompt appearance changes based on whether colors are enabled in the configuration.
+712
+713 Returns:
+714 str: The formatted command prompt string.
+715 """
+716
+717self.smbSession.ping_smb_session()
+718ifself.smbSession.connected:
+719ifself.config.no_colors:
+720connected_dot="[v]"
+721else:
+722connected_dot="\x1b[1;92m⏺\x1b[0m"
+723else:
+724ifself.config.no_colors:
+725connected_dot="[x]"
+726else:
+727connected_dot="\x1b[1;91m⏺\x1b[0m"
+728
+729ifself.smbSession.smb_shareisNone:
+730ifself.config.no_colors:
+731str_prompt="%s[\\\\%s\\]> "%(connected_dot,self.smbSession.address)
+732else:
+733str_prompt="%s[\x1b[1;94m\\\\%s\\\x1b[0m]> "%(connected_dot,self.smbSession.address)
+734else:
+735str_path="\\\\%s\\%s\\%s"%(self.smbSession.address,self.smbSession.smb_share,self.smbSession.smb_cwd.lstrip(ntpath.sep))
+736ifself.config.no_colors:
+737str_prompt="%s[%s]> "%(connected_dot,str_path)
+738else:
+739str_prompt="%s[\x1b[1;94m%s\x1b[0m]> "%(connected_dot,str_path)
+740
+741returnstr_prompt
127defprocess_command(self,command,arguments=[]):
-128# Skip
-129ifcommand.strip()=="":
-130pass
-131
-132# Display help
-133elifcommand=="help":
-134self.command_help(arguments,command)
-135
-136# Closes the current SMB session
-137elifcommand=="close":
-138self.command_close(arguments,command)
-139
-140# Change directory in the current share
-141elifcommand=="cd":
-142self.command_cd(arguments,command)
-143
-144# Get a file
-145elifcommand=="get":
-146self.command_get(arguments,command)
-147
-148# SMB server info
-149elifcommand=="info":
-150self.command_info(arguments,command)
-151
-152# List directory contents in a share
-153elifcommandin["ls","dir"]:
-154self.command_ls(arguments,command)
-155
-156# Creates a new remote directory
-157elifcommand=="mkdir":
-158self.command_mkdir(arguments,command)
-159
-160# Put a file
-161elifcommand=="put":
-162self.command_put(arguments,command)
-163
-164# Changes the current local directory
-165elifcommand=="lcd":
-166self.command_lcd(arguments,command)
-167
-168# Lists the contents of the current local directory
-169elifcommand=="lls":
-170self.command_lls(arguments,command)
-171
-172# Creates a new local directory
-173elifcommand=="lmkdir":
-174self.command_lmkdir(arguments,command)
-175
-176# Shows the current local directory
-177elifcommand=="lpwd":
-178self.command_lpwd(arguments,command)
-179
-180# Removes a local file
-181elifcommand=="lrm":
-182self.command_lrm(arguments,command)
-183
-184# Removes a local directory
-185elifcommand=="lrmdir":
-186self.command_lrmdir(arguments,command)
-187
-188# Shows the current local directory
-189elifcommand=="ltree":
-190self.command_ltree(arguments,command)
-191
-192# Modules
-193elifcommand=="module":
-194self.command_module(arguments,command)
-195
-196# Reconnects the current SMB session
-197elifcommandin["connect","reconnect"]:
-198self.command_reconnect(arguments,command)
-199
-200# Reset the TTY output
-201elifcommand=="reset":
-202self.command_reset(arguments,command)
-203
-204# Removes a remote file
-205elifcommand=="rm":
-206self.command_rm(arguments,command)
-207
-208# Removes a remote directory
-209elifcommand=="rmdir":
-210self.command_rmdir(arguments,command)
-211
-212# List shares
-213elifcommand=="shares":
-214self.command_shares(arguments,command)
-215
-216# Displays a tree view of the CWD
-217elifcommand=="tree":
-218self.command_tree(arguments,command)
-219
-220# Use a share
-221elifcommand=="use":
-222self.command_use(arguments,command)
+
129defprocess_command(self,command,arguments=[]):
+130# Skip
+131ifcommand.strip()=="":
+132pass
+133
+134# Display help
+135elifcommand=="help":
+136self.command_help(arguments,command)
+137
+138# Cat the contents of a file
+139elifcommand=="bat":
+140self.command_bat(arguments,command)
+141
+142# Cat the contents of a file
+143elifcommand=="cat":
+144self.command_cat(arguments,command)
+145
+146# Closes the current SMB session
+147elifcommand=="close":
+148self.command_close(arguments,command)
+149
+150# Change directory in the current share
+151elifcommand=="cd":
+152self.command_cd(arguments,command)
+153
+154# Get a file
+155elifcommand=="get":
+156self.command_get(arguments,command)
+157
+158# SMB server info
+159elifcommand=="info":
+160self.command_info(arguments,command)
+161
+162# List directory contents in a share
+163elifcommandin["ls","dir"]:
+164self.command_ls(arguments,command)
+165
+166# Creates a new remote directory
+167elifcommand=="mkdir":
+168self.command_mkdir(arguments,command)
+169
+170# Put a file
+171elifcommand=="put":
+172self.command_put(arguments,command)
+173
+174# Changes the current local directory
+175elifcommand=="lcd":
+176self.command_lcd(arguments,command)
+177
+178# Lists the contents of the current local directory
+179elifcommand=="lls":
+180self.command_lls(arguments,command)
+181
+182# Creates a new local directory
+183elifcommand=="lmkdir":
+184self.command_lmkdir(arguments,command)
+185
+186# Shows the current local directory
+187elifcommand=="lpwd":
+188self.command_lpwd(arguments,command)
+189
+190# Removes a local file
+191elifcommand=="lrm":
+192self.command_lrm(arguments,command)
+193
+194# Removes a local directory
+195elifcommand=="lrmdir":
+196self.command_lrmdir(arguments,command)
+197
+198# Shows the current local directory
+199elifcommand=="ltree":
+200self.command_ltree(arguments,command)
+201
+202# Modules
+203elifcommand=="module":
+204self.command_module(arguments,command)
+205
+206# Reconnects the current SMB session
+207elifcommandin["connect","reconnect"]:
+208self.command_reconnect(arguments,command)
+209
+210# Reset the TTY output
+211elifcommand=="reset":
+212self.command_reset(arguments,command)
+213
+214# Removes a remote file
+215elifcommand=="rm":
+216self.command_rm(arguments,command)
+217
+218# Removes a remote directory
+219elifcommand=="rmdir":
+220self.command_rmdir(arguments,command)
+221
+222# List shares
+223elifcommand=="shares":
+224self.command_shares(arguments,command)
+225
+226# Displays a tree view of the CWD
+227elifcommand=="tree":
+228self.command_tree(arguments,command)
+229
+230# Use a share
+231elifcommand=="use":
+232self.command_use(arguments,command)
+
494defcommand_reconnect(self,arguments,command):
-495# Command arguments required : No
-496# Active SMB connection needed : No
-497# SMB share needed : No
-498
-499self.smbSession.ping_smb_session()
-500ifself.smbSession.connected:
-501self.smbSession.close_smb_session()
-502self.smbSession.init_smb_session()
-503else:
-504self.smbSession.init_smb_session()
+
554defcommand_reconnect(self,arguments,command):
+555# Command arguments required : No
+556# Active SMB connection needed : No
+557# SMB share needed : No
+558
+559self.smbSession.ping_smb_session()
+560ifself.smbSession.connected:
+561self.smbSession.close_smb_session()
+562self.smbSession.init_smb_session()
+563else:
+564self.smbSession.init_smb_session()
@@ -2276,14 +2456,14 @@
-
506defcommand_reset(self,arguments,command):
-507# Command arguments required : No
-508# Active SMB connection needed : No
-509# SMB share needed : No
-510sys.stdout.write('\x1b[?25h')# Sets the cursor to on
-511sys.stdout.write('\x1b[v')
-512sys.stdout.write('\x1b[o')# Reset
-513sys.stdout.flush()
+
566defcommand_reset(self,arguments,command):
+567# Command arguments required : No
+568# Active SMB connection needed : No
+569# SMB share needed : No
+570sys.stdout.write('\x1b[?25h')# Sets the cursor to on
+571sys.stdout.write('\x1b[v')
+572sys.stdout.write('\x1b[o')# Reset
+573sys.stdout.flush()
5# Date created : 20 may 2024 6 7
- 8importimpacket.smbconnection
- 9importntpath
- 10importos
- 11importre
- 12importtraceback
- 13fromsmbclientng.core.LocalFileIOimportLocalFileIO
- 14fromsmbclientng.core.utilsimportb_filesize,STYPE_MASK
- 15
+ 8importio
+ 9importimpacket.smbconnection
+ 10importntpath
+ 11importos
+ 12importre
+ 13importtraceback
+ 14fromsmbclientng.core.LocalFileIOimportLocalFileIO
+ 15fromsmbclientng.core.utilsimportb_filesize,STYPE_MASK 16
- 17classSMBSession(object):
- 18"""
- 19 Class SMBSession is designed to handle the session management for SMB (Server Message Block) protocol connections.
- 20 It provides functionalities to connect to an SMB server, authenticate using either NTLM or Kerberos, and manage SMB shares.
- 21
- 22 Attributes:
- 23 address (str): The IP address or hostname of the SMB server.
- 24 domain (str): The domain name for SMB server authentication.
- 25 username (str): The username for SMB server authentication.
- 26 password (str): The password for SMB server authentication.
- 27 lmhash (str): The LM hash of the user's password, if available.
- 28 nthash (str): The NT hash of the user's password, if available.
- 29 use_kerberos (bool): A flag to determine whether to use Kerberos for authentication.
- 30 kdcHost (str): The Key Distribution Center (KDC) host for Kerberos authentication.
- 31 debug (bool): A flag to enable debug output.
- 32 smbClient (object): The SMB client object used for the connection.
- 33 connected (bool): A flag to check the status of the connection.
- 34 smb_share (str): The current SMB share in use.
- 35 smb_path (str): The current path within the SMB share.
- 36
- 37 Methods:
- 38 __init__(address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, debug=False):
- 39 Initializes the SMBSession with the specified parameters.
- 40 init_smb_session():
- 41 Initializes the SMB session by connecting to the server and authenticating using the specified method.
- 42 """
- 43
- 44def__init__(self,address,domain,username,password,lmhash,nthash,use_kerberos=False,kdcHost=None,config=None):
- 45super(SMBSession,self).__init__()
- 46# Objects
- 47self.config=config
- 48
- 49# Target server
- 50self.address=address
- 51
- 52# Credentials
- 53self.domain=domain
- 54self.username=username
- 55self.password=password
- 56self.lmhash=lmhash
- 57self.nthash=nthash
- 58self.use_kerberos=use_kerberos
- 59self.kdcHost=kdcHost
- 60
- 61self.smbClient=None
- 62self.connected=False
- 63
- 64self.available_shares={}
- 65self.smb_share=None
- 66self.smb_cwd=""
- 67
- 68self.list_shares()
- 69
- 70# Connect and disconnect SMB session
- 71
- 72definit_smb_session(self):
- 73"""
- 74 Initializes and establishes a session with the SMB server.
- 75
- 76 This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.
- 77 It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization.
- 78
- 79 The method will print debug information if the `debug` attribute is set to True. Upon successful connection and authentication, it sets the `connected` attribute to True.
- 80
- 81 Returns:
- 82 bool: True if the connection and authentication are successful, False otherwise.
- 83 """
- 84
- 85ifself.config.debug:
- 86print("[debug] [>] Connecting to remote SMB server '%s' ... "%self.address)
- 87try:
- 88self.smbClient=impacket.smbconnection.SMBConnection(
- 89remoteName=self.address,
- 90remoteHost=self.address,
- 91sess_port=int(445)
- 92)
- 93exceptOSErroraserr:
- 94print("[!] %s"%err)
- 95self.smbClient=None
- 96
- 97self.connected=False
- 98ifself.smbClientisnotNone:
- 99ifself.use_kerberos:
-100ifself.config.debug:
-101print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... "%(self.domain,self.username))
-102self.connected=self.smbClient.kerberosLogin(
-103user=self.username,
-104password=self.password,
-105domain=self.domain,
-106lmhash=self.lmhash,
-107nthash=self.nthash,
-108aesKey=self.aesKey,
-109kdcHost=self.kdcHost
-110)
-111
-112else:
-113ifself.config.debug:
-114print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... "%(self.domain,self.username))
-115self.connected=self.smbClient.login(
-116user=self.username,
-117password=self.password,
-118domain=self.domain,
-119lmhash=self.lmhash,
-120nthash=self.nthash
-121)
-122
-123ifself.connected:
-124print("[+] Successfully authenticated to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
-125else:
-126print("[!] Failed to authenticate to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
-127
-128returnself.connected
-129
-130defclose_smb_session(self):
-131"""
-132 Closes the current SMB session by disconnecting the SMB client.
-133
-134 This method ensures that the SMB client connection is properly closed. It checks if the client is connected
-135 and if so, it closes the connection and resets the connection status.
+ 17
+ 18classSMBSession(object):
+ 19"""
+ 20 Class SMBSession is designed to handle the session management for SMB (Server Message Block) protocol connections.
+ 21 It provides functionalities to connect to an SMB server, authenticate using either NTLM or Kerberos, and manage SMB shares.
+ 22
+ 23 Attributes:
+ 24 address (str): The IP address or hostname of the SMB server.
+ 25 domain (str): The domain name for SMB server authentication.
+ 26 username (str): The username for SMB server authentication.
+ 27 password (str): The password for SMB server authentication.
+ 28 lmhash (str): The LM hash of the user's password, if available.
+ 29 nthash (str): The NT hash of the user's password, if available.
+ 30 use_kerberos (bool): A flag to determine whether to use Kerberos for authentication.
+ 31 kdcHost (str): The Key Distribution Center (KDC) host for Kerberos authentication.
+ 32 debug (bool): A flag to enable debug output.
+ 33 smbClient (object): The SMB client object used for the connection.
+ 34 connected (bool): A flag to check the status of the connection.
+ 35 smb_share (str): The current SMB share in use.
+ 36 smb_path (str): The current path within the SMB share.
+ 37
+ 38 Methods:
+ 39 __init__(address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, debug=False):
+ 40 Initializes the SMBSession with the specified parameters.
+ 41 init_smb_session():
+ 42 Initializes the SMB session by connecting to the server and authenticating using the specified method.
+ 43 """
+ 44
+ 45def__init__(self,address,domain,username,password,lmhash,nthash,use_kerberos=False,kdcHost=None,config=None):
+ 46super(SMBSession,self).__init__()
+ 47# Objects
+ 48self.config=config
+ 49
+ 50# Target server
+ 51self.address=address
+ 52
+ 53# Credentials
+ 54self.domain=domain
+ 55self.username=username
+ 56self.password=password
+ 57self.lmhash=lmhash
+ 58self.nthash=nthash
+ 59self.use_kerberos=use_kerberos
+ 60self.kdcHost=kdcHost
+ 61
+ 62self.smbClient=None
+ 63self.connected=False
+ 64
+ 65self.available_shares={}
+ 66self.smb_share=None
+ 67self.smb_cwd=""
+ 68
+ 69self.list_shares()
+ 70
+ 71# Connect and disconnect SMB session
+ 72
+ 73definit_smb_session(self):
+ 74"""
+ 75 Initializes and establishes a session with the SMB server.
+ 76
+ 77 This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.
+ 78 It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization.
+ 79
+ 80 The method will print debug information if the `debug` attribute is set to True. Upon successful connection and authentication, it sets the `connected` attribute to True.
+ 81
+ 82 Returns:
+ 83 bool: True if the connection and authentication are successful, False otherwise.
+ 84 """
+ 85
+ 86self.connected=False
+ 87
+ 88ifself.config.debug:
+ 89print("[debug] [>] Connecting to remote SMB server '%s' ... "%self.address)
+ 90try:
+ 91self.smbClient=impacket.smbconnection.SMBConnection(
+ 92remoteName=self.address,
+ 93remoteHost=self.address,
+ 94sess_port=int(445)
+ 95)
+ 96exceptOSErroraserr:
+ 97print("[!] %s"%err)
+ 98self.smbClient=None
+ 99
+100ifself.smbClientisnotNone:
+101ifself.use_kerberos:
+102ifself.config.debug:
+103print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... "%(self.domain,self.username))
+104try:
+105self.connected=self.smbClient.kerberosLogin(
+106user=self.username,
+107password=self.password,
+108domain=self.domain,
+109lmhash=self.lmhash,
+110nthash=self.nthash,
+111aesKey=self.aesKey,
+112kdcHost=self.kdcHost
+113)
+114exceptimpacket.smbconnection.SessionErroraserr:
+115ifself.config.debug:
+116traceback.print_exc()
+117print("[!] Could not login: %s"%err)
+118self.connected=False
+119
+120else:
+121ifself.config.debug:
+122print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... "%(self.domain,self.username))
+123try:
+124self.connected=self.smbClient.login(
+125user=self.username,
+126password=self.password,
+127domain=self.domain,
+128lmhash=self.lmhash,
+129nthash=self.nthash
+130)
+131exceptimpacket.smbconnection.SessionErroraserr:
+132ifself.config.debug:
+133traceback.print_exc()
+134print("[!] Could not login: %s"%err)
+135self.connected=False136
-137 Raises:
-138 Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
-139 """
-140
-141ifself.smbClientisnotNone:
-142ifself.connected:
-143self.smbClient.close()
-144self.connected=False
-145print("[+] SMB connection closed successfully.")
-146else:
-147print("[!] No active SMB connection to close.")
-148else:
-149raiseException("SMB client is not initialized.")
+137ifself.connected:
+138print("[+] Successfully authenticated to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
+139else:
+140print("[!] Failed to authenticate to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
+141
+142returnself.connected
+143
+144defclose_smb_session(self):
+145"""
+146 Closes the current SMB session by disconnecting the SMB client.
+147
+148 This method ensures that the SMB client connection is properly closed. It checks if the client is connected
+149 and if so, it closes the connection and resets the connection status.150
-151# Operations
-152
-153defget_file(self,path=None,keepRemotePath=False):
-154"""
-155 Retrieves a file from the specified path on the SMB share.
-156
-157 This method attempts to retrieve a file from the given path within the currently connected SMB share.
-158 If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local
-159 file object and writing the contents of the remote file to it using the SMB client's getFile method.
-160
-161 Parameters:
-162 path (str): The path of the file to retrieve. If None, uses the current smb_path.
-163
-164 Returns:
-165 None
-166 """
-167
-168tmp_file_path=self.smb_cwd+ntpath.sep+path
-169matches=self.smbClient.listPath(
-170shareName=self.smb_share,
-171path=tmp_file_path
-172)
-173
-174forentryinmatches:
-175ifentry.is_directory():
-176print("[>] Skipping '%s' because it is a directory."%tmp_file_path)
-177else:
-178try:
-179ifntpath.sepinpath:
-180outputfile=ntpath.dirname(path)+ntpath.sep+entry.get_longname()
-181else:
-182outputfile=entry.get_longname()
-183f=LocalFileIO(
-184mode="wb",
-185path=outputfile,
-186expected_size=entry.get_filesize(),
-187debug=self.config.debug,
-188keepRemotePath=keepRemotePath
-189)
-190self.smbClient.getFile(
-191shareName=self.smb_share,
-192pathName=tmp_file_path,
-193callback=f.write
-194)
-195f.close()
-196except(BrokenPipeError,KeyboardInterrupt)ase:
-197f.close()
-198print("\x1b[v\x1b[o\r[!] Interrupted.")
-199self.close_smb_session()
-200self.init_smb_session()
-201
-202returnNone
-203
-204defget_file_recursively(self,path=None):
-205"""
-206 Recursively retrieves files from a specified path on the SMB share.
-207
-208 This method navigates through all directories starting from the given path,
-209 and downloads all files found. It handles directories recursively, ensuring
-210 that all nested files are retrieved. The method skips over directory entries
-211 and handles errors gracefully, attempting to continue the operation where possible.
-212
-213 Parameters:
-214 path (str): The initial directory path from which to start the recursive file retrieval.
-215 If None, it starts from the root of the configured SMB share.
-216 """
-217
-218defrecurse_action(base_dir="",path=[]):
-219remote_smb_path=base_dir+ntpath.sep.join(path)
-220entries=self.smbClient.listPath(
-221shareName=self.smb_share,
-222path=remote_smb_path+'\\*'
-223)
-224iflen(entries)!=0:
-225files=[entryforentryinentriesifnotentry.is_directory()]
-226directories=[entryforentryinentriesifentry.is_directory()andentry.get_longname()notin[".",".."]]
-227
-228# Files
-229iflen(files)!=0:
-230print("[>] Retrieving files of '%s'"%remote_smb_path)
-231forentry_fileinfiles:
-232ifnotentry_file.is_directory():
-233f=LocalFileIO(
-234mode="wb",
-235path=remote_smb_path+ntpath.sep+entry_file.get_longname(),
-236expected_size=entry_file.get_filesize(),
-237debug=self.config.debug
-238)
-239try:
-240self.smbClient.getFile(
-241shareName=self.smb_share,
-242pathName=remote_smb_path+ntpath.sep+entry_file.get_longname(),
-243callback=f.write
-244)
-245f.close()
-246exceptBrokenPipeErroraserr:
-247f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
-248f.close(remove=True)
-249break
-250exceptExceptionaserr:
-251f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
-252f.close(remove=True)
-253
-254# Directories
-255forentry_directoryindirectories:
-256ifentry_directory.is_directory():
-257recurse_action(
-258base_dir=self.smb_cwd,
-259path=path+[entry_directory.get_longname()]
-260)
-261# Entrypoint
-262try:
-263recurse_action(
-264base_dir=self.smb_cwd,
-265path=[path]
-266)
-267except(BrokenPipeError,KeyboardInterrupt)ase:
-268print("\x1b[v\x1b[o\r[!] Interrupted.")
-269self.close_smb_session()
-270self.init_smb_session()
-271
-272definfo(self,share=True,server=True):
-273"""
-274 Displays information about the server and optionally the shares.
-275
-276 This method prints detailed information about the server's characteristics such as NetBIOS names, DNS details, OS information, and SMB capabilities. If the `share` parameter is set to True and a share is currently set, it will also attempt to display information about the share.
-277
-278 Parameters:
-279 share (bool): If True, display information about the current share.
-280 server (bool): If True, display information about the server.
-281
-282 Returns:
-283 None
-284 """
-285
-286ifserver:
-287ifself.config.no_colors:
-288print("[+] Server:")
-289print(" ├─NetBIOS:")
-290print(" │ ├─ NetBIOS Hostname ──────── : %s"%(self.smbClient.getServerName()))
-291print(" │ └─ NetBIOS Domain ────────── : %s"%(self.smbClient.getServerDomain()))
-292print(" ├─DNS:")
-293print(" │ ├─ DNS Hostname ──────────── : %s"%(self.smbClient.getServerDNSHostName()))
-294print(" │ └─ DNS Domain ────────────── : %s"%(self.smbClient.getServerDNSDomainName()))
-295print(" ├─OS:")
-296print(" │ ├─ OS Name ───────────────── : %s"%(self.smbClient.getServerOS()))
-297print(" │ └─ OS Version ────────────── : %s.%s.%s"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
-298print(" ├─Server:")
-299print(" │ ├─ Signing Required ──────── : %s"%(self.smbClient.isSigningRequired()))
-300print(" │ ├─ Login Required ────────── : %s"%(self.smbClient.isLoginRequired()))
-301print(" │ ├─ Supports NTLMv2 ───────── : %s"%(self.smbClient.doesSupportNTLMv2()))
-302MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
-303print(" │ ├─ Max size of read chunk ── : %d bytes (%s)"%(MaxReadSize,b_filesize(MaxReadSize)))
-304MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
-305print(" │ └─ Max size of write chunk ─ : %d bytes (%s)"%(MaxWriteSize,b_filesize(MaxWriteSize)))
-306print(" └─")
-307else:
-308print("[+] Server:")
-309print(" ├─NetBIOS:")
-310print(" │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerName()))
-311print(" │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDomain()))
-312print(" ├─DNS:")
-313print(" │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSHostName()))
-314print(" │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSDomainName()))
-315print(" ├─OS:")
-316print(" │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerOS()))
-317print(" │ └─ \x1b[94mOS Version\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s.%s.%s\x1b[0m"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
-318print(" ├─Server:")
-319print(" │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isSigningRequired()))
-320print(" │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isLoginRequired()))
-321print(" │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.doesSupportNTLMv2()))
-322MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
-323print(" │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxReadSize,b_filesize(MaxReadSize)))
-324MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
-325print(" │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxWriteSize,b_filesize(MaxWriteSize)))
-326print(" └─")
-327
-328ifshareandself.smb_shareisnotNone:
-329share_name=self.available_shares.get(self.smb_share.lower(),"")["name"]
-330share_comment=self.available_shares.get(self.smb_share.lower(),"")["comment"]
-331share_type=self.available_shares.get(self.smb_share.lower(),"")["type"]
-332share_type=', '.join([s.replace("STYPE_","")forsinshare_type])
-333share_rawtype=self.available_shares.get(self.smb_share.lower(),"")["rawtype"]
-334ifself.config.no_colors:
-335print("\n[+] Share:")
-336print(" ├─ Name ──────────── : %s"%(share_name))
-337print(" ├─ Description ───── : %s"%(share_comment))
-338print(" ├─ Type ──────────── : %s"%(share_type))
-339print(" └─ Raw type value ── : %s"%(share_rawtype))
-340else:
-341print("\n[+] Share:")
-342print(" ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_name))
-343print(" ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_comment))
-344print(" ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_type))
-345print(" └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m"%(share_rawtype))
-346
-347deflist_contents(self,path=None):
-348"""
-349 Lists the contents of a specified directory on the SMB share.
-350
-351 This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path`
-352 is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with
-353 the long names of the files and directories as keys and their respective SMB entry objects as values.
+151 Raises:
+152 Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
+153 """
+154
+155ifself.smbClientisnotNone:
+156ifself.connected:
+157self.smbClient.close()
+158self.connected=False
+159ifself.config.debug:
+160print("[+] SMB connection closed successfully.")
+161else:
+162ifself.config.debug:
+163print("[!] No active SMB connection to close.")
+164else:
+165raiseException("SMB client is not initialized.")
+166
+167# Operations
+168
+169defread_file(self,path=None):
+170ifself.path_isfile(path=path):
+171tmp_file_path=self.smb_cwd+ntpath.sep+path
+172matches=self.smbClient.listPath(
+173shareName=self.smb_share,
+174path=tmp_file_path
+175)
+176
+177fh=io.BytesIO()
+178try:
+179# opening the files in streams instead of mounting shares allows
+180# for running the script from unprivileged containers
+181self.smbClient.getFile(self.smb_share,tmp_file_path,fh.write)
+182exceptimpacket.smbconnection.SessionErrorase:
+183returnNone
+184rawdata=fh.getvalue()
+185fh.close()
+186returnrawdata
+187else:
+188print("[!] Remote path '%s' is not a file."%path)
+189
+190deffind(self,paths=[],callback=None):
+191defrecurse_action(paths=[],depth=0,callback=None):
+192ifcallbackisNone:
+193return[]
+194next_directories_to_explore=[]
+195forpathinpaths:
+196remote_smb_path=ntpath.normpath(self.smb_cwd+ntpath.sep+path)
+197entries=[]
+198
+199try:
+200entries=self.smbClient.listPath(
+201shareName=self.smb_share,
+202path=(remote_smb_path+ntpath.sep+'*')
+203)
+204exceptimpacket.smbconnection.SessionErroraserr:
+205continue
+206# Remove dot names
+207entries=[eforeinentriesife.get_longname()notin[".",".."]]
+208# Sort the entries ignoring case
+209entries=sorted(entries,key=lambdax:x.get_longname().lower())
+210
+211forentryinentries:
+212ifentry.is_directory():
+213callback(entry,path+entry.get_longname()+ntpath.sep,depth)
+214else:
+215callback(entry,path+entry.get_longname(),depth)
+216
+217# Next directories to explore
+218forentryinentries:
+219ifentry.is_directory():
+220next_directories_to_explore.append(path+entry.get_longname()+ntpath.sep)
+221
+222returnnext_directories_to_explore
+223#
+224ifcallbackisnotNone:
+225depth=0
+226whilelen(paths)!=0:
+227paths=recurse_action(
+228paths=paths,
+229depth=depth,
+230callback=callback
+231)
+232depth=depth+1
+233else:
+234print("[!] SMBSession.find(), callback function cannot be None.")
+235
+236defget_file(self,path=None,keepRemotePath=False):
+237"""
+238 Retrieves a file from the specified path on the SMB share.
+239
+240 This method attempts to retrieve a file from the given path within the currently connected SMB share.
+241 If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local
+242 file object and writing the contents of the remote file to it using the SMB client's getFile method.
+243
+244 Parameters:
+245 path (str): The path of the file to retrieve. If None, uses the current smb_path.
+246
+247 Returns:
+248 None
+249 """
+250
+251tmp_file_path=self.smb_cwd+ntpath.sep+path
+252matches=self.smbClient.listPath(
+253shareName=self.smb_share,
+254path=tmp_file_path
+255)
+256
+257forentryinmatches:
+258ifentry.is_directory():
+259print("[>] Skipping '%s' because it is a directory."%tmp_file_path)
+260else:
+261try:
+262ifntpath.sepinpath:
+263outputfile=ntpath.dirname(path)+ntpath.sep+entry.get_longname()
+264else:
+265outputfile=entry.get_longname()
+266f=LocalFileIO(
+267mode="wb",
+268path=outputfile,
+269expected_size=entry.get_filesize(),
+270debug=self.config.debug,
+271keepRemotePath=keepRemotePath
+272)
+273self.smbClient.getFile(
+274shareName=self.smb_share,
+275pathName=tmp_file_path,
+276callback=f.write
+277)
+278f.close()
+279except(BrokenPipeError,KeyboardInterrupt)ase:
+280f.close()
+281print("\x1b[v\x1b[o\r[!] Interrupted.")
+282self.close_smb_session()
+283self.init_smb_session()
+284
+285returnNone
+286
+287defget_file_recursively(self,path=None):
+288"""
+289 Recursively retrieves files from a specified path on the SMB share.
+290
+291 This method navigates through all directories starting from the given path,
+292 and downloads all files found. It handles directories recursively, ensuring
+293 that all nested files are retrieved. The method skips over directory entries
+294 and handles errors gracefully, attempting to continue the operation where possible.
+295
+296 Parameters:
+297 path (str): The initial directory path from which to start the recursive file retrieval.
+298 If None, it starts from the root of the configured SMB share.
+299 """
+300
+301defrecurse_action(base_dir="",path=[]):
+302remote_smb_path=base_dir+ntpath.sep.join(path)
+303entries=self.smbClient.listPath(
+304shareName=self.smb_share,
+305path=remote_smb_path+'\\*'
+306)
+307iflen(entries)!=0:
+308files=[entryforentryinentriesifnotentry.is_directory()]
+309directories=[entryforentryinentriesifentry.is_directory()andentry.get_longname()notin[".",".."]]
+310
+311# Files
+312iflen(files)!=0:
+313print("[>] Retrieving files of '%s'"%remote_smb_path)
+314forentry_fileinfiles:
+315ifnotentry_file.is_directory():
+316f=LocalFileIO(
+317mode="wb",
+318path=remote_smb_path+ntpath.sep+entry_file.get_longname(),
+319expected_size=entry_file.get_filesize(),
+320debug=self.config.debug
+321)
+322try:
+323self.smbClient.getFile(
+324shareName=self.smb_share,
+325pathName=remote_smb_path+ntpath.sep+entry_file.get_longname(),
+326callback=f.write
+327)
+328f.close()
+329exceptBrokenPipeErroraserr:
+330f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
+331f.close(remove=True)
+332break
+333exceptExceptionaserr:
+334f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
+335f.close(remove=True)
+336
+337# Directories
+338forentry_directoryindirectories:
+339ifentry_directory.is_directory():
+340recurse_action(
+341base_dir=self.smb_cwd,
+342path=path+[entry_directory.get_longname()]
+343)
+344# Entrypoint
+345try:
+346recurse_action(
+347base_dir=self.smb_cwd,
+348path=[path]
+349)
+350except(BrokenPipeError,KeyboardInterrupt)ase:
+351print("\x1b[v\x1b[o\r[!] Interrupted.")
+352self.close_smb_session()
+353self.init_smb_session()354
-355 Args:
-356 shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.
-357 path (str, optional): The directory path to list contents from. Defaults to the current path if None.
+355definfo(self,share=True,server=True):
+356"""
+357 Displays information about the server and optionally the shares.358
-359 Returns:
-360 dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
-361 """
-362
-363ifpathisNoneorlen(path)==0:
-364path=self.smb_cwd
-365path=path.rstrip(ntpath.sep)+ntpath.sep+"*"
-366
-367contents={}
-368entries=self.smbClient.listPath(
-369shareName=self.smb_share,
-370path=path
-371)
-372forentryinentries:
-373contents[entry.get_longname()]=entry
-374
-375returncontents
-376
-377deflist_shares(self):
-378"""
-379 Lists all the shares available on the connected SMB server.
-380
-381 This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary
-382 with key-value pairs where the key is the share name and the value is a dictionary containing details about the share
-383 such as its name, type, raw type, and any comments associated with the share.
-384
-385 Returns:
-386 dict: A dictionary containing information about each share available on the server.
-387 """
-388
-389self.available_shares={}
-390
-391ifself.connected:
-392ifself.smbClientisnotNone:
-393resp=self.smbClient.listShares()
-394
-395forshareinresp:
-396# SHARE_INFO_1 structure (lmshare.h)
-397# https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1
-398sharename=share["shi1_netname"][:-1]
-399sharecomment=share["shi1_remark"][:-1]
-400sharetype=share["shi1_type"]
-401
-402self.available_shares[sharename.lower()]={
-403"name":sharename,
-404"type":STYPE_MASK(sharetype),
-405"rawtype":sharetype,
-406"comment":sharecomment
-407}
-408else:
-409print("[!] Error: SMBSession.smbClient is None.")
+359 This method prints detailed information about the server's characteristics such as NetBIOS names, DNS details, OS information, and SMB capabilities. If the `share` parameter is set to True and a share is currently set, it will also attempt to display information about the share.
+360
+361 Parameters:
+362 share (bool): If True, display information about the current share.
+363 server (bool): If True, display information about the server.
+364
+365 Returns:
+366 None
+367 """
+368
+369ifserver:
+370ifself.config.no_colors:
+371print("[+] Server:")
+372print(" ├─NetBIOS:")
+373print(" │ ├─ NetBIOS Hostname ──────── : %s"%(self.smbClient.getServerName()))
+374print(" │ └─ NetBIOS Domain ────────── : %s"%(self.smbClient.getServerDomain()))
+375print(" ├─DNS:")
+376print(" │ ├─ DNS Hostname ──────────── : %s"%(self.smbClient.getServerDNSHostName()))
+377print(" │ └─ DNS Domain ────────────── : %s"%(self.smbClient.getServerDNSDomainName()))
+378print(" ├─OS:")
+379print(" │ ├─ OS Name ───────────────── : %s"%(self.smbClient.getServerOS()))
+380print(" │ └─ OS Version ────────────── : %s.%s.%s"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
+381print(" ├─Server:")
+382print(" │ ├─ Signing Required ──────── : %s"%(self.smbClient.isSigningRequired()))
+383print(" │ ├─ Login Required ────────── : %s"%(self.smbClient.isLoginRequired()))
+384print(" │ ├─ Supports NTLMv2 ───────── : %s"%(self.smbClient.doesSupportNTLMv2()))
+385MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
+386print(" │ ├─ Max size of read chunk ── : %d bytes (%s)"%(MaxReadSize,b_filesize(MaxReadSize)))
+387MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
+388print(" │ └─ Max size of write chunk ─ : %d bytes (%s)"%(MaxWriteSize,b_filesize(MaxWriteSize)))
+389print(" └─")
+390else:
+391print("[+] Server:")
+392print(" ├─NetBIOS:")
+393print(" │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerName()))
+394print(" │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDomain()))
+395print(" ├─DNS:")
+396print(" │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSHostName()))
+397print(" │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSDomainName()))
+398print(" ├─OS:")
+399print(" │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerOS()))
+400print(" │ └─ \x1b[94mOS Version\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s.%s.%s\x1b[0m"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
+401print(" ├─Server:")
+402print(" │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isSigningRequired()))
+403print(" │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isLoginRequired()))
+404print(" │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.doesSupportNTLMv2()))
+405MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
+406print(" │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxReadSize,b_filesize(MaxReadSize)))
+407MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
+408print(" │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxWriteSize,b_filesize(MaxWriteSize)))
+409print(" └─")410
-411returnself.available_shares
-412
-413defmkdir(self,path=None):
-414"""
-415 Creates a directory at the specified path on the SMB share.
-416
-417 This method takes a path and attempts to create the directory structure on the SMB share. If the path includes
-418 nested directories, it will create each directory in the sequence. If a directory already exists, it will skip
-419 the creation for that directory without raising an error.
-420
-421 Args:
-422 path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
-423
-424 Note:
-425 The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
-426 """
-427
-428ifpathisnotNone:
-429# Prepare path
-430path=path.replace('/',ntpath.sep)
-431ifntpath.sepinpath:
-432path=path.strip(ntpath.sep).split(ntpath.sep)
-433else:
-434path=[path]
-435
-436# Create each dir in the path
-437fordepthinrange(1,len(path)+1):
-438tmp_path=ntpath.sep.join(path[:depth])
-439try:
-440self.smbClient.createDirectory(
-441shareName=self.smb_share,
-442pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+tmp_path+ntpath.sep)
-443)
-444exceptimpacket.smbconnection.SessionErroraserr:
-445iferr.getErrorCode()==0xc0000035:
-446# STATUS_OBJECT_NAME_COLLISION
-447# Remote directory already created, this is normal
-448# Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19
-449pass
-450else:
-451print("[!] Failed to create directory '%s': %s"%(tmp_path,err))
-452ifself.config.debug:
-453traceback.print_exc()
-454else:
-455pass
-456
-457defpath_exists(self,path=None):
-458"""
-459 Checks if the specified path exists on the SMB share.
-460
-461 This method determines if a given path exists on the SMB share by attempting to list the contents of the path.
-462 If the path listing is successful and returns one or more entries, the path is considered to exist.
+411ifshareandself.smb_shareisnotNone:
+412share_name=self.available_shares.get(self.smb_share.lower(),"")["name"]
+413share_comment=self.available_shares.get(self.smb_share.lower(),"")["comment"]
+414share_type=self.available_shares.get(self.smb_share.lower(),"")["type"]
+415share_type=', '.join([s.replace("STYPE_","")forsinshare_type])
+416share_rawtype=self.available_shares.get(self.smb_share.lower(),"")["rawtype"]
+417ifself.config.no_colors:
+418print("\n[+] Share:")
+419print(" ├─ Name ──────────── : %s"%(share_name))
+420print(" ├─ Description ───── : %s"%(share_comment))
+421print(" ├─ Type ──────────── : %s"%(share_type))
+422print(" └─ Raw type value ── : %s"%(share_rawtype))
+423else:
+424print("\n[+] Share:")
+425print(" ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_name))
+426print(" ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_comment))
+427print(" ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_type))
+428print(" └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m"%(share_rawtype))
+429
+430deflist_contents(self,path=None):
+431"""
+432 Lists the contents of a specified directory on the SMB share.
+433
+434 This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path`
+435 is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with
+436 the long names of the files and directories as keys and their respective SMB entry objects as values.
+437
+438 Args:
+439 shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.
+440 path (str, optional): The directory path to list contents from. Defaults to the current path if None.
+441
+442 Returns:
+443 dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
+444 """
+445
+446ifpathisNoneorlen(path)==0:
+447path=self.smb_cwd
+448path=path.rstrip(ntpath.sep)+ntpath.sep+"*"
+449
+450contents={}
+451entries=self.smbClient.listPath(
+452shareName=self.smb_share,
+453path=path
+454)
+455forentryinentries:
+456contents[entry.get_longname()]=entry
+457
+458returncontents
+459
+460deflist_shares(self):
+461"""
+462 Lists all the shares available on the connected SMB server.463
-464 Args:
-465 path (str, optional): The path to check on the SMB share. Defaults to None.
-466
-467 Returns:
-468 bool: True if the path exists, False otherwise or if an error occurs.
-469 """
-470
-471ifpathisnotNone:
-472path=path.replace('*','')
-473try:
-474contents=self.smbClient.listPath(
-475shareName=self.smb_share,
-476path=ntpath.normpath(self.smb_cwd+ntpath.sep+path+ntpath.sep)
-477)
-478return(len(contents)!=0)
-479exceptExceptionase:
-480returnFalse
-481else:
-482returnFalse
-483
-484defpath_isdir(self,pathFromRoot=None):
-485"""
-486 Checks if the specified path is a directory on the SMB share.
-487
-488 This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the
-489 contents of the path and filtering for entries that match the basename of the path and are marked as directories.
-490
-491 Args:
-492 path (str, optional): The path to check on the SMB share. Defaults to None.
+464 This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary
+465 with key-value pairs where the key is the share name and the value is a dictionary containing details about the share
+466 such as its name, type, raw type, and any comments associated with the share.
+467
+468 Returns:
+469 dict: A dictionary containing information about each share available on the server.
+470 """
+471
+472self.available_shares={}
+473
+474ifself.connected:
+475ifself.smbClientisnotNone:
+476resp=self.smbClient.listShares()
+477
+478forshareinresp:
+479# SHARE_INFO_1 structure (lmshare.h)
+480# https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1
+481sharename=share["shi1_netname"][:-1]
+482sharecomment=share["shi1_remark"][:-1]
+483sharetype=share["shi1_type"]
+484
+485self.available_shares[sharename.lower()]={
+486"name":sharename,
+487"type":STYPE_MASK(sharetype),
+488"rawtype":sharetype,
+489"comment":sharecomment
+490}
+491else:
+492print("[!] Error: SMBSession.smbClient is None.")493
-494 Returns:
-495 bool: True if the path is a directory, False otherwise or if an error occurs.
-496 """
-497
-498ifpathFromRootisnotNone:
-499# Replace slashes if any
-500path=pathFromRoot.replace('/',ntpath.sep)
-501
-502# Strip wildcards to avoid injections
-503path=path.replace('*','')
-504
-505# Normalize path and strip leading backslash
-506path=ntpath.normpath(path+ntpath.sep).lstrip(ntpath.sep)
-507
-508ifpath.strip()in['','.','..']:
-509# By defininition they exist on the filesystem
-510returnTrue
-511else:
-512try:
-513contents=self.smbClient.listPath(
-514shareName=self.smb_share,
-515path=path+'*'
-516)
-517# Filter on directories
-518contents=[
-519cforcincontents
-520ifc.get_longname()==ntpath.basename(path)andc.is_directory()
-521]
-522return(len(contents)!=0)
-523exceptExceptionase:
-524returnFalse
-525else:
-526returnFalse
-527
-528defpath_isfile(self,path=None):
-529"""
-530 Checks if the specified path is a file on the SMB share.
-531
-532 This method determines if a given path corresponds to a file on the SMB share. It does this by listing the
-533 contents of the path and filtering for entries that match the basename of the path and are not marked as directories.
-534
-535 Args:
-536 path (str, optional): The path to check on the SMB share. Defaults to None.
-537
-538 Returns:
-539 bool: True if the path is a file, False otherwise or if an error occurs.
-540 """
-541
-542ifpathisnotNone:
-543path=path.replace('*','')
-544try:
-545contents=self.smbClient.listPath(
-546shareName=self.smb_share,
-547path=ntpath.normpath(self.smb_cwd+ntpath.sep+path+ntpath.sep)
-548)
-549# Filter on files
-550contents=[
-551cforcincontents
-552ifc.get_longname()==ntpath.basename(path)andnotc.is_directory()
-553]
-554return(len(contents)!=0)
-555exceptExceptionase:
-556returnFalse
-557else:
-558returnFalse
-559
-560defping_smb_session(self):
-561"""
-562 Tests the connectivity to the SMB server by sending an echo command.
-563
-564 This method attempts to send an echo command to the SMB server to check if the session is still active.
-565 It updates the `connected` attribute of the class based on the success or failure of the echo command.
-566
-567 Returns:
-568 bool: True if the echo command succeeds (indicating the session is active), False otherwise.
-569 """
+494returnself.available_shares
+495
+496defmkdir(self,path=None):
+497"""
+498 Creates a directory at the specified path on the SMB share.
+499
+500 This method takes a path and attempts to create the directory structure on the SMB share. If the path includes
+501 nested directories, it will create each directory in the sequence. If a directory already exists, it will skip
+502 the creation for that directory without raising an error.
+503
+504 Args:
+505 path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
+506
+507 Note:
+508 The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
+509 """
+510
+511ifpathisnotNone:
+512# Prepare path
+513path=path.replace('/',ntpath.sep)
+514ifntpath.sepinpath:
+515path=path.strip(ntpath.sep).split(ntpath.sep)
+516else:
+517path=[path]
+518
+519# Create each dir in the path
+520fordepthinrange(1,len(path)+1):
+521tmp_path=ntpath.sep.join(path[:depth])
+522try:
+523self.smbClient.createDirectory(
+524shareName=self.smb_share,
+525pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+tmp_path+ntpath.sep)
+526)
+527exceptimpacket.smbconnection.SessionErroraserr:
+528iferr.getErrorCode()==0xc0000035:
+529# STATUS_OBJECT_NAME_COLLISION
+530# Remote directory already created, this is normal
+531# Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19
+532pass
+533else:
+534print("[!] Failed to create directory '%s': %s"%(tmp_path,err))
+535ifself.config.debug:
+536traceback.print_exc()
+537else:
+538pass
+539
+540defpath_exists(self,path=None):
+541"""
+542 Checks if the specified path exists on the SMB share.
+543
+544 This method determines if a given path exists on the SMB share by attempting to list the contents of the path.
+545 If the path listing is successful and returns one or more entries, the path is considered to exist.
+546
+547 Args:
+548 path (str, optional): The path to check on the SMB share. Defaults to None.
+549
+550 Returns:
+551 bool: True if the path exists, False otherwise or if an error occurs.
+552 """
+553
+554ifpathisnotNone:
+555path=path.replace('*','')
+556try:
+557contents=self.smbClient.listPath(
+558shareName=self.smb_share,
+559path=ntpath.normpath(self.smb_cwd+ntpath.sep+path+ntpath.sep)
+560)
+561return(len(contents)!=0)
+562exceptExceptionase:
+563returnFalse
+564else:
+565returnFalse
+566
+567defpath_isdir(self,pathFromRoot=None):
+568"""
+569 Checks if the specified path is a directory on the SMB share.570
-571try:
-572self.smbClient.getSMBServer().echo()
-573self.connected=True
-574exceptExceptionase:
-575self.connected=False
-576returnself.connected
-577
-578defput_file(self,localpath=None):
-579"""
-580 Uploads a single file to the SMB share.
-581
-582 This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.
-583 It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.
-584 General exceptions are caught and logged, with a traceback provided if debugging is enabled.
-585
-586 Args:
-587 localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
-588 """
-589
-590ifos.path.exists(localpath):
-591ifos.path.isfile(localpath):
-592try:
-593localfile=os.path.basename(localpath)
-594f=LocalFileIO(
-595mode="rb",
-596path=localpath,
-597debug=self.config.debug
-598)
-599self.smbClient.putFile(
-600shareName=self.smb_share,
-601pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+localfile+ntpath.sep),
-602callback=f.read
-603)
-604f.close()
-605except(BrokenPipeError,KeyboardInterrupt)aserr:
-606print("[!] Interrupted.")
-607self.close_smb_session()
-608self.init_smb_session()
-609exceptExceptionaserr:
-610print("[!] Failed to upload '%s': %s"%(localfile,err))
-611ifself.config.debug:
-612traceback.print_exc()
-613else:
-614print("[!] The specified localpath is a directory. Use 'put -r <directory>' instead.")
-615else:
-616print("[!] The specified localpath does not exist.")
+571 This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the
+572 contents of the path and filtering for entries that match the basename of the path and are marked as directories.
+573
+574 Args:
+575 path (str, optional): The path to check on the SMB share. Defaults to None.
+576
+577 Returns:
+578 bool: True if the path is a directory, False otherwise or if an error occurs.
+579 """
+580
+581ifpathFromRootisnotNone:
+582# Replace slashes if any
+583path=pathFromRoot.replace('/',ntpath.sep)
+584
+585# Strip wildcards to avoid injections
+586path=path.replace('*','')
+587
+588# Normalize path and strip leading backslash
+589path=ntpath.normpath(path+ntpath.sep).lstrip(ntpath.sep)
+590
+591ifpath.strip()in['','.','..']:
+592# By defininition they exist on the filesystem
+593returnTrue
+594else:
+595try:
+596contents=self.smbClient.listPath(
+597shareName=self.smb_share,
+598path=path+'*'
+599)
+600# Filter on directories
+601contents=[
+602cforcincontents
+603ifc.get_longname()==ntpath.basename(path)andc.is_directory()
+604]
+605return(len(contents)!=0)
+606exceptExceptionase:
+607returnFalse
+608else:
+609returnFalse
+610
+611defpath_isfile(self,path=None):
+612"""
+613 Checks if the specified path is a file on the SMB share.
+614
+615 This method determines if a given path corresponds to a file on the SMB share. It does this by listing the
+616 contents of the path and filtering for entries that match the basename of the path and are not marked as directories.617
-618defput_file_recursively(self,localpath=None):
-619"""
-620 Recursively uploads files from a specified local directory to the SMB share.
-621
-622 This method walks through the given local directory and all its subdirectories, uploading each file to the
-623 corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,
-624 it iterates over all files and directories within the local path, creating necessary directories on the SMB share
-625 and uploading files. If the local path is not a directory, it prints an error message.
-626
-627 Args:
-628 localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
-629 """
-630
-631ifos.path.exists(localpath):
-632ifos.path.isfile(localpath):
-633# Iterate over all files and directories within the local path
-634local_files={}
-635forroot,dirs,filesinos.walk(localpath):
-636iflen(files)!=0:
-637local_files[root]=files
-638
-639# Iterate over the found files
-640forlocal_dir_pathinsorted(local_files.keys()):
-641print("[>] Putting files of '%s'"%local_dir_path)
-642
-643# Create remote directory
-644remote_dir_path=local_dir_path.replace(os.path.sep,ntpath.sep)
-645self.mkdir(
-646path=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep)
-647)
+618 Args:
+619 path (str, optional): The path to check on the SMB share. Defaults to None.
+620
+621 Returns:
+622 bool: True if the path is a file, False otherwise or if an error occurs.
+623 """
+624
+625ifpathisnotNone:
+626path=path.replace('*','')
+627search_dir=ntpath.normpath(self.smb_cwd+ntpath.sep+path)
+628search_dir=ntpath.dirname(search_dir)+ntpath.sep+'*'
+629try:
+630contents=self.smbClient.listPath(
+631shareName=self.smb_share,
+632path=search_dir
+633)
+634# Filter on files
+635contents=[
+636cforcincontents
+637ifc.get_longname()==ntpath.basename(path)andnotc.is_directory()
+638]
+639return(len(contents)!=0)
+640exceptExceptionase:
+641returnFalse
+642else:
+643returnFalse
+644
+645defping_smb_session(self):
+646"""
+647 Tests the connectivity to the SMB server by sending an echo command.648
-649forlocal_file_pathinlocal_files[local_dir_path]:
-650try:
-651f=LocalFileIO(
-652mode="rb",
-653path=local_dir_path+os.path.sep+local_file_path,
-654debug=self.config.debug
-655)
-656self.smbClient.putFile(
-657shareName=self.smb_share,
-658pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep+local_file_path),
-659callback=f.read
-660)
-661f.close()
-662
-663exceptBrokenPipeErroraserr:
-664f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
-665f.close(remove=True)
-666break
-667exceptExceptionaserr:
-668f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
-669f.close(remove=True)
-670else:
-671print("[!] The specified localpath is a file. Use 'put <file>' instead.")
-672else:
-673print("[!] The specified localpath does not exist.")
-674
-675defrmdir(self,path=None):
-676"""
-677 Removes a directory from the SMB share at the specified path.
-678
-679 This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,
-680 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
-681 the stack trace of the exception.
-682
-683 Args:
-684 path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
-685 """
-686try:
-687self.smbClient.deleteDirectory(
-688shareName=self.smb_share,
-689pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
-690)
-691exceptExceptionaserr:
-692print("[!] Failed to remove directory '%s': %s"%(path,err))
-693ifself.config.debug:
-694traceback.print_exc()
-695
-696defrm(self,path=None):
-697"""
-698 Removes a file from the SMB share at the specified path.
-699
-700 This method attempts to delete a file located at the given path on the SMB share. If the operation fails,
-701 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
-702 the stack trace of the exception.
-703
-704 Args:
-705 path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
-706 """
-707try:
-708self.smbClient.deleteFile(
-709shareName=self.smb_share,
-710pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
-711)
-712exceptExceptionaserr:
-713print("[!] Failed to remove file '%s': %s"%(path,err))
-714ifself.config.debug:
-715traceback.print_exc()
-716
-717deftree(self,path=None):
-718"""
-719 Recursively lists the directory structure of the SMB share starting from the specified path.
-720
-721 This function prints a visual representation of the directory tree of the remote SMB share. It uses
-722 recursion to navigate through directories and lists all files and subdirectories in each directory.
-723 The output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
-724
-725 Args:
-726 path (str, optional): The starting path on the SMB share from which to begin listing the tree.
-727 Defaults to the root of the current share.
-728 """
-729
-730defrecurse_action(base_dir="",path=[],prompt=[]):
-731bars=["│ ","├── ","└── "]
+649 This method attempts to send an echo command to the SMB server to check if the session is still active.
+650 It updates the `connected` attribute of the class based on the success or failure of the echo command.
+651
+652 Returns:
+653 bool: True if the echo command succeeds (indicating the session is active), False otherwise.
+654 """
+655
+656try:
+657self.smbClient.getSMBServer().echo()
+658exceptExceptionase:
+659self.connected=False
+660returnself.connected
+661
+662defput_file(self,localpath=None):
+663"""
+664 Uploads a single file to the SMB share.
+665
+666 This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.
+667 It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.
+668 General exceptions are caught and logged, with a traceback provided if debugging is enabled.
+669
+670 Args:
+671 localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
+672 """
+673
+674ifos.path.exists(localpath):
+675ifos.path.isfile(localpath):
+676try:
+677localfile=os.path.basename(localpath)
+678f=LocalFileIO(
+679mode="rb",
+680path=localpath,
+681debug=self.config.debug
+682)
+683self.smbClient.putFile(
+684shareName=self.smb_share,
+685pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+localfile+ntpath.sep),
+686callback=f.read
+687)
+688f.close()
+689except(BrokenPipeError,KeyboardInterrupt)aserr:
+690print("[!] Interrupted.")
+691self.close_smb_session()
+692self.init_smb_session()
+693exceptExceptionaserr:
+694print("[!] Failed to upload '%s': %s"%(localfile,err))
+695ifself.config.debug:
+696traceback.print_exc()
+697else:
+698print("[!] The specified localpath is a directory. Use 'put -r <directory>' instead.")
+699else:
+700print("[!] The specified localpath does not exist.")
+701
+702defput_file_recursively(self,localpath=None):
+703"""
+704 Recursively uploads files from a specified local directory to the SMB share.
+705
+706 This method walks through the given local directory and all its subdirectories, uploading each file to the
+707 corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,
+708 it iterates over all files and directories within the local path, creating necessary directories on the SMB share
+709 and uploading files. If the local path is not a directory, it prints an error message.
+710
+711 Args:
+712 localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
+713 """
+714
+715ifos.path.exists(localpath):
+716ifos.path.isfile(localpath):
+717# Iterate over all files and directories within the local path
+718local_files={}
+719forroot,dirs,filesinos.walk(localpath):
+720iflen(files)!=0:
+721local_files[root]=files
+722
+723# Iterate over the found files
+724forlocal_dir_pathinsorted(local_files.keys()):
+725print("[>] Putting files of '%s'"%local_dir_path)
+726
+727# Create remote directory
+728remote_dir_path=local_dir_path.replace(os.path.sep,ntpath.sep)
+729self.mkdir(
+730path=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep)
+731)732
-733remote_smb_path=ntpath.normpath(base_dir+ntpath.sep+ntpath.sep.join(path))
-734
-735entries=[]
-736try:
-737entries=self.smbClient.listPath(
-738shareName=self.smb_share,
-739path=remote_smb_path+'\\*'
-740)
-741exceptimpacket.smbconnection.SessionErroraserr:
-742code,const,text=err.getErrorCode(),err.getErrorString()[0],err.getErrorString()[1]
-743errmsg="Error 0x%08x (%s): %s"%(code,const,text)
-744ifself.config.no_colors:
-745print("%s%s"%(''.join(prompt+[bars[2]]),errmsg))
-746else:
-747print("%s\x1b[1;91m%s\x1b[0m"%(''.join(prompt+[bars[2]]),errmsg))
-748return
-749
-750entries=[eforeinentriesife.get_longname()notin[".",".."]]
-751entries=sorted(entries,key=lambdax:x.get_longname())
-752
-753#
-754iflen(entries)>1:
-755index=0
-756forentryinentries:
-757index+=1
-758# This is the first entry
-759ifindex==0:
-760ifentry.is_directory():
-761ifself.config.no_colors:
-762print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-763else:
-764print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-765recurse_action(
-766base_dir=base_dir,
-767path=path+[entry.get_longname()],
-768prompt=prompt+["│ "]
-769)
-770else:
-771ifself.config.no_colors:
-772print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-773else:
-774print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-775
-776# This is the last entry
-777elifindex==len(entries):
-778ifentry.is_directory():
-779ifself.config.no_colors:
-780print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-781else:
-782print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-783recurse_action(
-784base_dir=base_dir,
-785path=path+[entry.get_longname()],
-786prompt=prompt+[" "]
-787)
-788else:
-789ifself.config.no_colors:
-790print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-791else:
-792print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-793
-794# These are entries in the middle
-795else:
-796ifentry.is_directory():
-797ifself.config.no_colors:
-798print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-799else:
-800print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-801recurse_action(
-802base_dir=base_dir,
-803path=path+[entry.get_longname()],
-804prompt=prompt+["│ "]
-805)
-806else:
-807ifself.config.no_colors:
-808print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-809else:
-810print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-811
-812#
-813eliflen(entries)==1:
-814entry=entries[0]
-815ifentry.is_directory():
-816ifself.config.no_colors:
-817print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-818else:
-819print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-820recurse_action(
-821base_dir=base_dir,
-822path=path+[entry.get_longname()],
-823prompt=prompt+[" "]
-824)
-825else:
-826ifself.config.no_colors:
-827print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-828else:
-829print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-830
-831# Entrypoint
-832try:
-833ifself.config.no_colors:
-834print("%s\\"%path)
-835else:
-836print("\x1b[1;96m%s\x1b[0m\\"%path)
-837recurse_action(
-838base_dir=self.smb_cwd,
-839path=[path],
-840prompt=[""]
-841)
-842except(BrokenPipeError,KeyboardInterrupt)ase:
-843print("[!] Interrupted.")
-844self.close_smb_session()
-845self.init_smb_session()
-846
-847# Setter / Getter
-848
-849defset_share(self,shareName):
-850"""
-851 Sets the current SMB share to the specified share name.
-852
-853 This method updates the SMB session to use the specified share name. It checks if the share name is valid
-854 and updates the smb_share attribute of the SMBSession instance.
-855
-856 Parameters:
-857 shareName (str): The name of the share to set as the current SMB share.
-858
-859 Raises:
-860 ValueError: If the shareName is None or an empty string.
-861 """
-862
-863ifshareNameisnotNone:
-864self.smb_share=shareName
-865
-866defset_cwd(self,path=None):
-867"""
-868 Sets the current working directory on the SMB share to the specified path.
-869
-870 This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.
-871 If the specified path is not a directory, the cwd remains unchanged.
-872
-873 Parameters:
-874 path (str): The path to set as the current working directory.
-875
-876 Raises:
-877 ValueError: If the specified path is not a directory.
-878 """
-879
-880ifpathisnotNone:
-881# Set path separators to ntpath sep
-882if'/'inpath:
-883path=path.replace('/',ntpath.sep)
-884
-885ifpath.startswith(ntpath.sep):
-886# Absolute path
-887path=path+ntpath.sep
-888else:
-889# Relative path to the CWD
-890iflen(self.smb_cwd)==0:
-891path=path+ntpath.sep
-892else:
-893path=self.smb_cwd+ntpath.sep+path
-894
-895# Path normalization
-896path=ntpath.normpath(path)
-897path=re.sub(r'\\+',r'\\',path)
-898
-899ifpathin["",".",".."]:
-900self.smb_cwd=""
-901else:
-902ifself.path_isdir(pathFromRoot=path.strip(ntpath.sep)):
-903# Path exists on the remote
-904self.smb_cwd=ntpath.normpath(path)
-905else:
-906# Path does not exists or is not a directory on the remote
-907print("[!] Remote directory '%s' does not exist."%path)
+733forlocal_file_pathinlocal_files[local_dir_path]:
+734try:
+735f=LocalFileIO(
+736mode="rb",
+737path=local_dir_path+os.path.sep+local_file_path,
+738debug=self.config.debug
+739)
+740self.smbClient.putFile(
+741shareName=self.smb_share,
+742pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep+local_file_path),
+743callback=f.read
+744)
+745f.close()
+746
+747exceptBrokenPipeErroraserr:
+748f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
+749f.close(remove=True)
+750break
+751exceptExceptionaserr:
+752f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
+753f.close(remove=True)
+754else:
+755print("[!] The specified localpath is a file. Use 'put <file>' instead.")
+756else:
+757print("[!] The specified localpath does not exist.")
+758
+759defrmdir(self,path=None):
+760"""
+761 Removes a directory from the SMB share at the specified path.
+762
+763 This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,
+764 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
+765 the stack trace of the exception.
+766
+767 Args:
+768 path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
+769 """
+770try:
+771self.smbClient.deleteDirectory(
+772shareName=self.smb_share,
+773pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
+774)
+775exceptExceptionaserr:
+776print("[!] Failed to remove directory '%s': %s"%(path,err))
+777ifself.config.debug:
+778traceback.print_exc()
+779
+780defrm(self,path=None):
+781"""
+782 Removes a file from the SMB share at the specified path.
+783
+784 This method attempts to delete a file located at the given path on the SMB share. If the operation fails,
+785 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
+786 the stack trace of the exception.
+787
+788 Args:
+789 path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
+790 """
+791try:
+792self.smbClient.deleteFile(
+793shareName=self.smb_share,
+794pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
+795)
+796exceptExceptionaserr:
+797print("[!] Failed to remove file '%s': %s"%(path,err))
+798ifself.config.debug:
+799traceback.print_exc()
+800
+801deftree(self,path=None):
+802"""
+803 Recursively lists the directory structure of the SMB share starting from the specified path.
+804
+805 This function prints a visual representation of the directory tree of the remote SMB share. It uses
+806 recursion to navigate through directories and lists all files and subdirectories in each directory.
+807 The output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
+808
+809 Args:
+810 path (str, optional): The starting path on the SMB share from which to begin listing the tree.
+811 Defaults to the root of the current share.
+812 """
+813
+814defrecurse_action(base_dir="",path=[],prompt=[]):
+815bars=["│ ","├── ","└── "]
+816
+817remote_smb_path=ntpath.normpath(base_dir+ntpath.sep+ntpath.sep.join(path))
+818
+819entries=[]
+820try:
+821entries=self.smbClient.listPath(
+822shareName=self.smb_share,
+823path=remote_smb_path+'\\*'
+824)
+825exceptimpacket.smbconnection.SessionErroraserr:
+826code,const,text=err.getErrorCode(),err.getErrorString()[0],err.getErrorString()[1]
+827errmsg="Error 0x%08x (%s): %s"%(code,const,text)
+828ifself.config.no_colors:
+829print("%s%s"%(''.join(prompt+[bars[2]]),errmsg))
+830else:
+831print("%s\x1b[1;91m%s\x1b[0m"%(''.join(prompt+[bars[2]]),errmsg))
+832return
+833
+834entries=[eforeinentriesife.get_longname()notin[".",".."]]
+835entries=sorted(entries,key=lambdax:x.get_longname())
+836
+837#
+838iflen(entries)>1:
+839index=0
+840forentryinentries:
+841index+=1
+842# This is the first entry
+843ifindex==0:
+844ifentry.is_directory():
+845ifself.config.no_colors:
+846print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+847else:
+848print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+849recurse_action(
+850base_dir=base_dir,
+851path=path+[entry.get_longname()],
+852prompt=prompt+["│ "]
+853)
+854else:
+855ifself.config.no_colors:
+856print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+857else:
+858print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+859
+860# This is the last entry
+861elifindex==len(entries):
+862ifentry.is_directory():
+863ifself.config.no_colors:
+864print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+865else:
+866print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+867recurse_action(
+868base_dir=base_dir,
+869path=path+[entry.get_longname()],
+870prompt=prompt+[" "]
+871)
+872else:
+873ifself.config.no_colors:
+874print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+875else:
+876print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+877
+878# These are entries in the middle
+879else:
+880ifentry.is_directory():
+881ifself.config.no_colors:
+882print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+883else:
+884print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+885recurse_action(
+886base_dir=base_dir,
+887path=path+[entry.get_longname()],
+888prompt=prompt+["│ "]
+889)
+890else:
+891ifself.config.no_colors:
+892print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+893else:
+894print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+895
+896#
+897eliflen(entries)==1:
+898entry=entries[0]
+899ifentry.is_directory():
+900ifself.config.no_colors:
+901print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+902else:
+903print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+904recurse_action(
+905base_dir=base_dir,
+906path=path+[entry.get_longname()],
+907prompt=prompt+[" "]
+908)
+909else:
+910ifself.config.no_colors:
+911print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+912else:
+913print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+914
+915# Entrypoint
+916try:
+917ifself.config.no_colors:
+918print("%s\\"%path)
+919else:
+920print("\x1b[1;96m%s\x1b[0m\\"%path)
+921recurse_action(
+922base_dir=self.smb_cwd,
+923path=[path],
+924prompt=[""]
+925)
+926except(BrokenPipeError,KeyboardInterrupt)ase:
+927print("[!] Interrupted.")
+928self.close_smb_session()
+929self.init_smb_session()
+930
+931# Setter / Getter
+932
+933defset_share(self,shareName):
+934"""
+935 Sets the current SMB share to the specified share name.
+936
+937 This method updates the SMB session to use the specified share name. It checks if the share name is valid
+938 and updates the smb_share attribute of the SMBSession instance.
+939
+940 Parameters:
+941 shareName (str): The name of the share to set as the current SMB share.
+942
+943 Raises:
+944 ValueError: If the shareName is None or an empty string.
+945 """
+946
+947ifshareNameisnotNone:
+948self.list_shares()
+949ifshareName.lower()inself.available_shares.keys():
+950# Doing this in order to keep the case of the share adevertised by the remote machine
+951self.smb_share=self.available_shares[shareName.lower()]["name"]
+952else:
+953print("[!] Could not set share '%s', it does not exist remotely."%shareName)
+954
+955defset_cwd(self,path=None):
+956"""
+957 Sets the current working directory on the SMB share to the specified path.
+958
+959 This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.
+960 If the specified path is not a directory, the cwd remains unchanged.
+961
+962 Parameters:
+963 path (str): The path to set as the current working directory.
+964
+965 Raises:
+966 ValueError: If the specified path is not a directory.
+967 """
+968
+969ifpathisnotNone:
+970# Set path separators to ntpath sep
+971if'/'inpath:
+972path=path.replace('/',ntpath.sep)
+973
+974ifpath.startswith(ntpath.sep):
+975# Absolute path
+976path=path+ntpath.sep
+977else:
+978# Relative path to the CWD
+979iflen(self.smb_cwd)==0:
+980path=path+ntpath.sep
+981else:
+982path=self.smb_cwd+ntpath.sep+path
+983
+984# Path normalization
+985path=ntpath.normpath(path)
+986path=re.sub(r'\\+',r'\\',path)
+987
+988ifpathin["",".",".."]:
+989self.smb_cwd=""
+990else:
+991ifself.path_isdir(pathFromRoot=path.strip(ntpath.sep)):
+992# Path exists on the remote
+993self.smb_cwd=ntpath.normpath(path)
+994else:
+995# Path does not exists or is not a directory on the remote
+996print("[!] Remote directory '%s' does not exist."%path)
@@ -1081,897 +1176,985 @@
-
18classSMBSession(object):
- 19"""
- 20 Class SMBSession is designed to handle the session management for SMB (Server Message Block) protocol connections.
- 21 It provides functionalities to connect to an SMB server, authenticate using either NTLM or Kerberos, and manage SMB shares.
- 22
- 23 Attributes:
- 24 address (str): The IP address or hostname of the SMB server.
- 25 domain (str): The domain name for SMB server authentication.
- 26 username (str): The username for SMB server authentication.
- 27 password (str): The password for SMB server authentication.
- 28 lmhash (str): The LM hash of the user's password, if available.
- 29 nthash (str): The NT hash of the user's password, if available.
- 30 use_kerberos (bool): A flag to determine whether to use Kerberos for authentication.
- 31 kdcHost (str): The Key Distribution Center (KDC) host for Kerberos authentication.
- 32 debug (bool): A flag to enable debug output.
- 33 smbClient (object): The SMB client object used for the connection.
- 34 connected (bool): A flag to check the status of the connection.
- 35 smb_share (str): The current SMB share in use.
- 36 smb_path (str): The current path within the SMB share.
- 37
- 38 Methods:
- 39 __init__(address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, debug=False):
- 40 Initializes the SMBSession with the specified parameters.
- 41 init_smb_session():
- 42 Initializes the SMB session by connecting to the server and authenticating using the specified method.
- 43 """
- 44
- 45def__init__(self,address,domain,username,password,lmhash,nthash,use_kerberos=False,kdcHost=None,config=None):
- 46super(SMBSession,self).__init__()
- 47# Objects
- 48self.config=config
- 49
- 50# Target server
- 51self.address=address
- 52
- 53# Credentials
- 54self.domain=domain
- 55self.username=username
- 56self.password=password
- 57self.lmhash=lmhash
- 58self.nthash=nthash
- 59self.use_kerberos=use_kerberos
- 60self.kdcHost=kdcHost
- 61
- 62self.smbClient=None
- 63self.connected=False
- 64
- 65self.available_shares={}
- 66self.smb_share=None
- 67self.smb_cwd=""
- 68
- 69self.list_shares()
- 70
- 71# Connect and disconnect SMB session
- 72
- 73definit_smb_session(self):
- 74"""
- 75 Initializes and establishes a session with the SMB server.
- 76
- 77 This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.
- 78 It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization.
- 79
- 80 The method will print debug information if the `debug` attribute is set to True. Upon successful connection and authentication, it sets the `connected` attribute to True.
- 81
- 82 Returns:
- 83 bool: True if the connection and authentication are successful, False otherwise.
- 84 """
- 85
- 86ifself.config.debug:
- 87print("[debug] [>] Connecting to remote SMB server '%s' ... "%self.address)
- 88try:
- 89self.smbClient=impacket.smbconnection.SMBConnection(
- 90remoteName=self.address,
- 91remoteHost=self.address,
- 92sess_port=int(445)
- 93)
- 94exceptOSErroraserr:
- 95print("[!] %s"%err)
- 96self.smbClient=None
- 97
- 98self.connected=False
- 99ifself.smbClientisnotNone:
-100ifself.use_kerberos:
-101ifself.config.debug:
-102print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... "%(self.domain,self.username))
-103self.connected=self.smbClient.kerberosLogin(
-104user=self.username,
-105password=self.password,
-106domain=self.domain,
-107lmhash=self.lmhash,
-108nthash=self.nthash,
-109aesKey=self.aesKey,
-110kdcHost=self.kdcHost
-111)
-112
-113else:
-114ifself.config.debug:
-115print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... "%(self.domain,self.username))
-116self.connected=self.smbClient.login(
-117user=self.username,
-118password=self.password,
-119domain=self.domain,
-120lmhash=self.lmhash,
-121nthash=self.nthash
-122)
-123
-124ifself.connected:
-125print("[+] Successfully authenticated to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
-126else:
-127print("[!] Failed to authenticate to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
-128
-129returnself.connected
-130
-131defclose_smb_session(self):
-132"""
-133 Closes the current SMB session by disconnecting the SMB client.
-134
-135 This method ensures that the SMB client connection is properly closed. It checks if the client is connected
-136 and if so, it closes the connection and resets the connection status.
+
19classSMBSession(object):
+ 20"""
+ 21 Class SMBSession is designed to handle the session management for SMB (Server Message Block) protocol connections.
+ 22 It provides functionalities to connect to an SMB server, authenticate using either NTLM or Kerberos, and manage SMB shares.
+ 23
+ 24 Attributes:
+ 25 address (str): The IP address or hostname of the SMB server.
+ 26 domain (str): The domain name for SMB server authentication.
+ 27 username (str): The username for SMB server authentication.
+ 28 password (str): The password for SMB server authentication.
+ 29 lmhash (str): The LM hash of the user's password, if available.
+ 30 nthash (str): The NT hash of the user's password, if available.
+ 31 use_kerberos (bool): A flag to determine whether to use Kerberos for authentication.
+ 32 kdcHost (str): The Key Distribution Center (KDC) host for Kerberos authentication.
+ 33 debug (bool): A flag to enable debug output.
+ 34 smbClient (object): The SMB client object used for the connection.
+ 35 connected (bool): A flag to check the status of the connection.
+ 36 smb_share (str): The current SMB share in use.
+ 37 smb_path (str): The current path within the SMB share.
+ 38
+ 39 Methods:
+ 40 __init__(address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, debug=False):
+ 41 Initializes the SMBSession with the specified parameters.
+ 42 init_smb_session():
+ 43 Initializes the SMB session by connecting to the server and authenticating using the specified method.
+ 44 """
+ 45
+ 46def__init__(self,address,domain,username,password,lmhash,nthash,use_kerberos=False,kdcHost=None,config=None):
+ 47super(SMBSession,self).__init__()
+ 48# Objects
+ 49self.config=config
+ 50
+ 51# Target server
+ 52self.address=address
+ 53
+ 54# Credentials
+ 55self.domain=domain
+ 56self.username=username
+ 57self.password=password
+ 58self.lmhash=lmhash
+ 59self.nthash=nthash
+ 60self.use_kerberos=use_kerberos
+ 61self.kdcHost=kdcHost
+ 62
+ 63self.smbClient=None
+ 64self.connected=False
+ 65
+ 66self.available_shares={}
+ 67self.smb_share=None
+ 68self.smb_cwd=""
+ 69
+ 70self.list_shares()
+ 71
+ 72# Connect and disconnect SMB session
+ 73
+ 74definit_smb_session(self):
+ 75"""
+ 76 Initializes and establishes a session with the SMB server.
+ 77
+ 78 This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.
+ 79 It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization.
+ 80
+ 81 The method will print debug information if the `debug` attribute is set to True. Upon successful connection and authentication, it sets the `connected` attribute to True.
+ 82
+ 83 Returns:
+ 84 bool: True if the connection and authentication are successful, False otherwise.
+ 85 """
+ 86
+ 87self.connected=False
+ 88
+ 89ifself.config.debug:
+ 90print("[debug] [>] Connecting to remote SMB server '%s' ... "%self.address)
+ 91try:
+ 92self.smbClient=impacket.smbconnection.SMBConnection(
+ 93remoteName=self.address,
+ 94remoteHost=self.address,
+ 95sess_port=int(445)
+ 96)
+ 97exceptOSErroraserr:
+ 98print("[!] %s"%err)
+ 99self.smbClient=None
+100
+101ifself.smbClientisnotNone:
+102ifself.use_kerberos:
+103ifself.config.debug:
+104print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... "%(self.domain,self.username))
+105try:
+106self.connected=self.smbClient.kerberosLogin(
+107user=self.username,
+108password=self.password,
+109domain=self.domain,
+110lmhash=self.lmhash,
+111nthash=self.nthash,
+112aesKey=self.aesKey,
+113kdcHost=self.kdcHost
+114)
+115exceptimpacket.smbconnection.SessionErroraserr:
+116ifself.config.debug:
+117traceback.print_exc()
+118print("[!] Could not login: %s"%err)
+119self.connected=False
+120
+121else:
+122ifself.config.debug:
+123print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... "%(self.domain,self.username))
+124try:
+125self.connected=self.smbClient.login(
+126user=self.username,
+127password=self.password,
+128domain=self.domain,
+129lmhash=self.lmhash,
+130nthash=self.nthash
+131)
+132exceptimpacket.smbconnection.SessionErroraserr:
+133ifself.config.debug:
+134traceback.print_exc()
+135print("[!] Could not login: %s"%err)
+136self.connected=False137
-138 Raises:
-139 Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
-140 """
-141
-142ifself.smbClientisnotNone:
-143ifself.connected:
-144self.smbClient.close()
-145self.connected=False
-146print("[+] SMB connection closed successfully.")
-147else:
-148print("[!] No active SMB connection to close.")
-149else:
-150raiseException("SMB client is not initialized.")
+138ifself.connected:
+139print("[+] Successfully authenticated to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
+140else:
+141print("[!] Failed to authenticate to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
+142
+143returnself.connected
+144
+145defclose_smb_session(self):
+146"""
+147 Closes the current SMB session by disconnecting the SMB client.
+148
+149 This method ensures that the SMB client connection is properly closed. It checks if the client is connected
+150 and if so, it closes the connection and resets the connection status.151
-152# Operations
-153
-154defget_file(self,path=None,keepRemotePath=False):
-155"""
-156 Retrieves a file from the specified path on the SMB share.
-157
-158 This method attempts to retrieve a file from the given path within the currently connected SMB share.
-159 If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local
-160 file object and writing the contents of the remote file to it using the SMB client's getFile method.
-161
-162 Parameters:
-163 path (str): The path of the file to retrieve. If None, uses the current smb_path.
-164
-165 Returns:
-166 None
-167 """
-168
-169tmp_file_path=self.smb_cwd+ntpath.sep+path
-170matches=self.smbClient.listPath(
-171shareName=self.smb_share,
-172path=tmp_file_path
-173)
-174
-175forentryinmatches:
-176ifentry.is_directory():
-177print("[>] Skipping '%s' because it is a directory."%tmp_file_path)
-178else:
-179try:
-180ifntpath.sepinpath:
-181outputfile=ntpath.dirname(path)+ntpath.sep+entry.get_longname()
-182else:
-183outputfile=entry.get_longname()
-184f=LocalFileIO(
-185mode="wb",
-186path=outputfile,
-187expected_size=entry.get_filesize(),
-188debug=self.config.debug,
-189keepRemotePath=keepRemotePath
-190)
-191self.smbClient.getFile(
-192shareName=self.smb_share,
-193pathName=tmp_file_path,
-194callback=f.write
-195)
-196f.close()
-197except(BrokenPipeError,KeyboardInterrupt)ase:
-198f.close()
-199print("\x1b[v\x1b[o\r[!] Interrupted.")
-200self.close_smb_session()
-201self.init_smb_session()
-202
-203returnNone
-204
-205defget_file_recursively(self,path=None):
-206"""
-207 Recursively retrieves files from a specified path on the SMB share.
-208
-209 This method navigates through all directories starting from the given path,
-210 and downloads all files found. It handles directories recursively, ensuring
-211 that all nested files are retrieved. The method skips over directory entries
-212 and handles errors gracefully, attempting to continue the operation where possible.
-213
-214 Parameters:
-215 path (str): The initial directory path from which to start the recursive file retrieval.
-216 If None, it starts from the root of the configured SMB share.
-217 """
-218
-219defrecurse_action(base_dir="",path=[]):
-220remote_smb_path=base_dir+ntpath.sep.join(path)
-221entries=self.smbClient.listPath(
-222shareName=self.smb_share,
-223path=remote_smb_path+'\\*'
-224)
-225iflen(entries)!=0:
-226files=[entryforentryinentriesifnotentry.is_directory()]
-227directories=[entryforentryinentriesifentry.is_directory()andentry.get_longname()notin[".",".."]]
-228
-229# Files
-230iflen(files)!=0:
-231print("[>] Retrieving files of '%s'"%remote_smb_path)
-232forentry_fileinfiles:
-233ifnotentry_file.is_directory():
-234f=LocalFileIO(
-235mode="wb",
-236path=remote_smb_path+ntpath.sep+entry_file.get_longname(),
-237expected_size=entry_file.get_filesize(),
-238debug=self.config.debug
-239)
-240try:
-241self.smbClient.getFile(
-242shareName=self.smb_share,
-243pathName=remote_smb_path+ntpath.sep+entry_file.get_longname(),
-244callback=f.write
-245)
-246f.close()
-247exceptBrokenPipeErroraserr:
-248f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
-249f.close(remove=True)
-250break
-251exceptExceptionaserr:
-252f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
-253f.close(remove=True)
-254
-255# Directories
-256forentry_directoryindirectories:
-257ifentry_directory.is_directory():
-258recurse_action(
-259base_dir=self.smb_cwd,
-260path=path+[entry_directory.get_longname()]
-261)
-262# Entrypoint
-263try:
-264recurse_action(
-265base_dir=self.smb_cwd,
-266path=[path]
-267)
-268except(BrokenPipeError,KeyboardInterrupt)ase:
-269print("\x1b[v\x1b[o\r[!] Interrupted.")
-270self.close_smb_session()
-271self.init_smb_session()
-272
-273definfo(self,share=True,server=True):
-274"""
-275 Displays information about the server and optionally the shares.
-276
-277 This method prints detailed information about the server's characteristics such as NetBIOS names, DNS details, OS information, and SMB capabilities. If the `share` parameter is set to True and a share is currently set, it will also attempt to display information about the share.
-278
-279 Parameters:
-280 share (bool): If True, display information about the current share.
-281 server (bool): If True, display information about the server.
-282
-283 Returns:
-284 None
-285 """
-286
-287ifserver:
-288ifself.config.no_colors:
-289print("[+] Server:")
-290print(" ├─NetBIOS:")
-291print(" │ ├─ NetBIOS Hostname ──────── : %s"%(self.smbClient.getServerName()))
-292print(" │ └─ NetBIOS Domain ────────── : %s"%(self.smbClient.getServerDomain()))
-293print(" ├─DNS:")
-294print(" │ ├─ DNS Hostname ──────────── : %s"%(self.smbClient.getServerDNSHostName()))
-295print(" │ └─ DNS Domain ────────────── : %s"%(self.smbClient.getServerDNSDomainName()))
-296print(" ├─OS:")
-297print(" │ ├─ OS Name ───────────────── : %s"%(self.smbClient.getServerOS()))
-298print(" │ └─ OS Version ────────────── : %s.%s.%s"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
-299print(" ├─Server:")
-300print(" │ ├─ Signing Required ──────── : %s"%(self.smbClient.isSigningRequired()))
-301print(" │ ├─ Login Required ────────── : %s"%(self.smbClient.isLoginRequired()))
-302print(" │ ├─ Supports NTLMv2 ───────── : %s"%(self.smbClient.doesSupportNTLMv2()))
-303MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
-304print(" │ ├─ Max size of read chunk ── : %d bytes (%s)"%(MaxReadSize,b_filesize(MaxReadSize)))
-305MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
-306print(" │ └─ Max size of write chunk ─ : %d bytes (%s)"%(MaxWriteSize,b_filesize(MaxWriteSize)))
-307print(" └─")
-308else:
-309print("[+] Server:")
-310print(" ├─NetBIOS:")
-311print(" │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerName()))
-312print(" │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDomain()))
-313print(" ├─DNS:")
-314print(" │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSHostName()))
-315print(" │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSDomainName()))
-316print(" ├─OS:")
-317print(" │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerOS()))
-318print(" │ └─ \x1b[94mOS Version\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s.%s.%s\x1b[0m"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
-319print(" ├─Server:")
-320print(" │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isSigningRequired()))
-321print(" │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isLoginRequired()))
-322print(" │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.doesSupportNTLMv2()))
-323MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
-324print(" │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxReadSize,b_filesize(MaxReadSize)))
-325MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
-326print(" │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxWriteSize,b_filesize(MaxWriteSize)))
-327print(" └─")
-328
-329ifshareandself.smb_shareisnotNone:
-330share_name=self.available_shares.get(self.smb_share.lower(),"")["name"]
-331share_comment=self.available_shares.get(self.smb_share.lower(),"")["comment"]
-332share_type=self.available_shares.get(self.smb_share.lower(),"")["type"]
-333share_type=', '.join([s.replace("STYPE_","")forsinshare_type])
-334share_rawtype=self.available_shares.get(self.smb_share.lower(),"")["rawtype"]
-335ifself.config.no_colors:
-336print("\n[+] Share:")
-337print(" ├─ Name ──────────── : %s"%(share_name))
-338print(" ├─ Description ───── : %s"%(share_comment))
-339print(" ├─ Type ──────────── : %s"%(share_type))
-340print(" └─ Raw type value ── : %s"%(share_rawtype))
-341else:
-342print("\n[+] Share:")
-343print(" ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_name))
-344print(" ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_comment))
-345print(" ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_type))
-346print(" └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m"%(share_rawtype))
-347
-348deflist_contents(self,path=None):
-349"""
-350 Lists the contents of a specified directory on the SMB share.
-351
-352 This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path`
-353 is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with
-354 the long names of the files and directories as keys and their respective SMB entry objects as values.
+152 Raises:
+153 Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
+154 """
+155
+156ifself.smbClientisnotNone:
+157ifself.connected:
+158self.smbClient.close()
+159self.connected=False
+160ifself.config.debug:
+161print("[+] SMB connection closed successfully.")
+162else:
+163ifself.config.debug:
+164print("[!] No active SMB connection to close.")
+165else:
+166raiseException("SMB client is not initialized.")
+167
+168# Operations
+169
+170defread_file(self,path=None):
+171ifself.path_isfile(path=path):
+172tmp_file_path=self.smb_cwd+ntpath.sep+path
+173matches=self.smbClient.listPath(
+174shareName=self.smb_share,
+175path=tmp_file_path
+176)
+177
+178fh=io.BytesIO()
+179try:
+180# opening the files in streams instead of mounting shares allows
+181# for running the script from unprivileged containers
+182self.smbClient.getFile(self.smb_share,tmp_file_path,fh.write)
+183exceptimpacket.smbconnection.SessionErrorase:
+184returnNone
+185rawdata=fh.getvalue()
+186fh.close()
+187returnrawdata
+188else:
+189print("[!] Remote path '%s' is not a file."%path)
+190
+191deffind(self,paths=[],callback=None):
+192defrecurse_action(paths=[],depth=0,callback=None):
+193ifcallbackisNone:
+194return[]
+195next_directories_to_explore=[]
+196forpathinpaths:
+197remote_smb_path=ntpath.normpath(self.smb_cwd+ntpath.sep+path)
+198entries=[]
+199
+200try:
+201entries=self.smbClient.listPath(
+202shareName=self.smb_share,
+203path=(remote_smb_path+ntpath.sep+'*')
+204)
+205exceptimpacket.smbconnection.SessionErroraserr:
+206continue
+207# Remove dot names
+208entries=[eforeinentriesife.get_longname()notin[".",".."]]
+209# Sort the entries ignoring case
+210entries=sorted(entries,key=lambdax:x.get_longname().lower())
+211
+212forentryinentries:
+213ifentry.is_directory():
+214callback(entry,path+entry.get_longname()+ntpath.sep,depth)
+215else:
+216callback(entry,path+entry.get_longname(),depth)
+217
+218# Next directories to explore
+219forentryinentries:
+220ifentry.is_directory():
+221next_directories_to_explore.append(path+entry.get_longname()+ntpath.sep)
+222
+223returnnext_directories_to_explore
+224#
+225ifcallbackisnotNone:
+226depth=0
+227whilelen(paths)!=0:
+228paths=recurse_action(
+229paths=paths,
+230depth=depth,
+231callback=callback
+232)
+233depth=depth+1
+234else:
+235print("[!] SMBSession.find(), callback function cannot be None.")
+236
+237defget_file(self,path=None,keepRemotePath=False):
+238"""
+239 Retrieves a file from the specified path on the SMB share.
+240
+241 This method attempts to retrieve a file from the given path within the currently connected SMB share.
+242 If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local
+243 file object and writing the contents of the remote file to it using the SMB client's getFile method.
+244
+245 Parameters:
+246 path (str): The path of the file to retrieve. If None, uses the current smb_path.
+247
+248 Returns:
+249 None
+250 """
+251
+252tmp_file_path=self.smb_cwd+ntpath.sep+path
+253matches=self.smbClient.listPath(
+254shareName=self.smb_share,
+255path=tmp_file_path
+256)
+257
+258forentryinmatches:
+259ifentry.is_directory():
+260print("[>] Skipping '%s' because it is a directory."%tmp_file_path)
+261else:
+262try:
+263ifntpath.sepinpath:
+264outputfile=ntpath.dirname(path)+ntpath.sep+entry.get_longname()
+265else:
+266outputfile=entry.get_longname()
+267f=LocalFileIO(
+268mode="wb",
+269path=outputfile,
+270expected_size=entry.get_filesize(),
+271debug=self.config.debug,
+272keepRemotePath=keepRemotePath
+273)
+274self.smbClient.getFile(
+275shareName=self.smb_share,
+276pathName=tmp_file_path,
+277callback=f.write
+278)
+279f.close()
+280except(BrokenPipeError,KeyboardInterrupt)ase:
+281f.close()
+282print("\x1b[v\x1b[o\r[!] Interrupted.")
+283self.close_smb_session()
+284self.init_smb_session()
+285
+286returnNone
+287
+288defget_file_recursively(self,path=None):
+289"""
+290 Recursively retrieves files from a specified path on the SMB share.
+291
+292 This method navigates through all directories starting from the given path,
+293 and downloads all files found. It handles directories recursively, ensuring
+294 that all nested files are retrieved. The method skips over directory entries
+295 and handles errors gracefully, attempting to continue the operation where possible.
+296
+297 Parameters:
+298 path (str): The initial directory path from which to start the recursive file retrieval.
+299 If None, it starts from the root of the configured SMB share.
+300 """
+301
+302defrecurse_action(base_dir="",path=[]):
+303remote_smb_path=base_dir+ntpath.sep.join(path)
+304entries=self.smbClient.listPath(
+305shareName=self.smb_share,
+306path=remote_smb_path+'\\*'
+307)
+308iflen(entries)!=0:
+309files=[entryforentryinentriesifnotentry.is_directory()]
+310directories=[entryforentryinentriesifentry.is_directory()andentry.get_longname()notin[".",".."]]
+311
+312# Files
+313iflen(files)!=0:
+314print("[>] Retrieving files of '%s'"%remote_smb_path)
+315forentry_fileinfiles:
+316ifnotentry_file.is_directory():
+317f=LocalFileIO(
+318mode="wb",
+319path=remote_smb_path+ntpath.sep+entry_file.get_longname(),
+320expected_size=entry_file.get_filesize(),
+321debug=self.config.debug
+322)
+323try:
+324self.smbClient.getFile(
+325shareName=self.smb_share,
+326pathName=remote_smb_path+ntpath.sep+entry_file.get_longname(),
+327callback=f.write
+328)
+329f.close()
+330exceptBrokenPipeErroraserr:
+331f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
+332f.close(remove=True)
+333break
+334exceptExceptionaserr:
+335f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
+336f.close(remove=True)
+337
+338# Directories
+339forentry_directoryindirectories:
+340ifentry_directory.is_directory():
+341recurse_action(
+342base_dir=self.smb_cwd,
+343path=path+[entry_directory.get_longname()]
+344)
+345# Entrypoint
+346try:
+347recurse_action(
+348base_dir=self.smb_cwd,
+349path=[path]
+350)
+351except(BrokenPipeError,KeyboardInterrupt)ase:
+352print("\x1b[v\x1b[o\r[!] Interrupted.")
+353self.close_smb_session()
+354self.init_smb_session()355
-356 Args:
-357 shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.
-358 path (str, optional): The directory path to list contents from. Defaults to the current path if None.
+356definfo(self,share=True,server=True):
+357"""
+358 Displays information about the server and optionally the shares.359
-360 Returns:
-361 dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
-362 """
-363
-364ifpathisNoneorlen(path)==0:
-365path=self.smb_cwd
-366path=path.rstrip(ntpath.sep)+ntpath.sep+"*"
-367
-368contents={}
-369entries=self.smbClient.listPath(
-370shareName=self.smb_share,
-371path=path
-372)
-373forentryinentries:
-374contents[entry.get_longname()]=entry
-375
-376returncontents
-377
-378deflist_shares(self):
-379"""
-380 Lists all the shares available on the connected SMB server.
-381
-382 This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary
-383 with key-value pairs where the key is the share name and the value is a dictionary containing details about the share
-384 such as its name, type, raw type, and any comments associated with the share.
-385
-386 Returns:
-387 dict: A dictionary containing information about each share available on the server.
-388 """
-389
-390self.available_shares={}
-391
-392ifself.connected:
-393ifself.smbClientisnotNone:
-394resp=self.smbClient.listShares()
-395
-396forshareinresp:
-397# SHARE_INFO_1 structure (lmshare.h)
-398# https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1
-399sharename=share["shi1_netname"][:-1]
-400sharecomment=share["shi1_remark"][:-1]
-401sharetype=share["shi1_type"]
-402
-403self.available_shares[sharename.lower()]={
-404"name":sharename,
-405"type":STYPE_MASK(sharetype),
-406"rawtype":sharetype,
-407"comment":sharecomment
-408}
-409else:
-410print("[!] Error: SMBSession.smbClient is None.")
+360 This method prints detailed information about the server's characteristics such as NetBIOS names, DNS details, OS information, and SMB capabilities. If the `share` parameter is set to True and a share is currently set, it will also attempt to display information about the share.
+361
+362 Parameters:
+363 share (bool): If True, display information about the current share.
+364 server (bool): If True, display information about the server.
+365
+366 Returns:
+367 None
+368 """
+369
+370ifserver:
+371ifself.config.no_colors:
+372print("[+] Server:")
+373print(" ├─NetBIOS:")
+374print(" │ ├─ NetBIOS Hostname ──────── : %s"%(self.smbClient.getServerName()))
+375print(" │ └─ NetBIOS Domain ────────── : %s"%(self.smbClient.getServerDomain()))
+376print(" ├─DNS:")
+377print(" │ ├─ DNS Hostname ──────────── : %s"%(self.smbClient.getServerDNSHostName()))
+378print(" │ └─ DNS Domain ────────────── : %s"%(self.smbClient.getServerDNSDomainName()))
+379print(" ├─OS:")
+380print(" │ ├─ OS Name ───────────────── : %s"%(self.smbClient.getServerOS()))
+381print(" │ └─ OS Version ────────────── : %s.%s.%s"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
+382print(" ├─Server:")
+383print(" │ ├─ Signing Required ──────── : %s"%(self.smbClient.isSigningRequired()))
+384print(" │ ├─ Login Required ────────── : %s"%(self.smbClient.isLoginRequired()))
+385print(" │ ├─ Supports NTLMv2 ───────── : %s"%(self.smbClient.doesSupportNTLMv2()))
+386MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
+387print(" │ ├─ Max size of read chunk ── : %d bytes (%s)"%(MaxReadSize,b_filesize(MaxReadSize)))
+388MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
+389print(" │ └─ Max size of write chunk ─ : %d bytes (%s)"%(MaxWriteSize,b_filesize(MaxWriteSize)))
+390print(" └─")
+391else:
+392print("[+] Server:")
+393print(" ├─NetBIOS:")
+394print(" │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerName()))
+395print(" │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDomain()))
+396print(" ├─DNS:")
+397print(" │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSHostName()))
+398print(" │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSDomainName()))
+399print(" ├─OS:")
+400print(" │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerOS()))
+401print(" │ └─ \x1b[94mOS Version\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s.%s.%s\x1b[0m"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
+402print(" ├─Server:")
+403print(" │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isSigningRequired()))
+404print(" │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isLoginRequired()))
+405print(" │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.doesSupportNTLMv2()))
+406MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
+407print(" │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxReadSize,b_filesize(MaxReadSize)))
+408MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
+409print(" │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxWriteSize,b_filesize(MaxWriteSize)))
+410print(" └─")411
-412returnself.available_shares
-413
-414defmkdir(self,path=None):
-415"""
-416 Creates a directory at the specified path on the SMB share.
-417
-418 This method takes a path and attempts to create the directory structure on the SMB share. If the path includes
-419 nested directories, it will create each directory in the sequence. If a directory already exists, it will skip
-420 the creation for that directory without raising an error.
-421
-422 Args:
-423 path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
-424
-425 Note:
-426 The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
-427 """
-428
-429ifpathisnotNone:
-430# Prepare path
-431path=path.replace('/',ntpath.sep)
-432ifntpath.sepinpath:
-433path=path.strip(ntpath.sep).split(ntpath.sep)
-434else:
-435path=[path]
-436
-437# Create each dir in the path
-438fordepthinrange(1,len(path)+1):
-439tmp_path=ntpath.sep.join(path[:depth])
-440try:
-441self.smbClient.createDirectory(
-442shareName=self.smb_share,
-443pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+tmp_path+ntpath.sep)
-444)
-445exceptimpacket.smbconnection.SessionErroraserr:
-446iferr.getErrorCode()==0xc0000035:
-447# STATUS_OBJECT_NAME_COLLISION
-448# Remote directory already created, this is normal
-449# Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19
-450pass
-451else:
-452print("[!] Failed to create directory '%s': %s"%(tmp_path,err))
-453ifself.config.debug:
-454traceback.print_exc()
-455else:
-456pass
-457
-458defpath_exists(self,path=None):
-459"""
-460 Checks if the specified path exists on the SMB share.
-461
-462 This method determines if a given path exists on the SMB share by attempting to list the contents of the path.
-463 If the path listing is successful and returns one or more entries, the path is considered to exist.
+412ifshareandself.smb_shareisnotNone:
+413share_name=self.available_shares.get(self.smb_share.lower(),"")["name"]
+414share_comment=self.available_shares.get(self.smb_share.lower(),"")["comment"]
+415share_type=self.available_shares.get(self.smb_share.lower(),"")["type"]
+416share_type=', '.join([s.replace("STYPE_","")forsinshare_type])
+417share_rawtype=self.available_shares.get(self.smb_share.lower(),"")["rawtype"]
+418ifself.config.no_colors:
+419print("\n[+] Share:")
+420print(" ├─ Name ──────────── : %s"%(share_name))
+421print(" ├─ Description ───── : %s"%(share_comment))
+422print(" ├─ Type ──────────── : %s"%(share_type))
+423print(" └─ Raw type value ── : %s"%(share_rawtype))
+424else:
+425print("\n[+] Share:")
+426print(" ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_name))
+427print(" ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_comment))
+428print(" ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_type))
+429print(" └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m"%(share_rawtype))
+430
+431deflist_contents(self,path=None):
+432"""
+433 Lists the contents of a specified directory on the SMB share.
+434
+435 This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path`
+436 is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with
+437 the long names of the files and directories as keys and their respective SMB entry objects as values.
+438
+439 Args:
+440 shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.
+441 path (str, optional): The directory path to list contents from. Defaults to the current path if None.
+442
+443 Returns:
+444 dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
+445 """
+446
+447ifpathisNoneorlen(path)==0:
+448path=self.smb_cwd
+449path=path.rstrip(ntpath.sep)+ntpath.sep+"*"
+450
+451contents={}
+452entries=self.smbClient.listPath(
+453shareName=self.smb_share,
+454path=path
+455)
+456forentryinentries:
+457contents[entry.get_longname()]=entry
+458
+459returncontents
+460
+461deflist_shares(self):
+462"""
+463 Lists all the shares available on the connected SMB server.464
-465 Args:
-466 path (str, optional): The path to check on the SMB share. Defaults to None.
-467
-468 Returns:
-469 bool: True if the path exists, False otherwise or if an error occurs.
-470 """
-471
-472ifpathisnotNone:
-473path=path.replace('*','')
-474try:
-475contents=self.smbClient.listPath(
-476shareName=self.smb_share,
-477path=ntpath.normpath(self.smb_cwd+ntpath.sep+path+ntpath.sep)
-478)
-479return(len(contents)!=0)
-480exceptExceptionase:
-481returnFalse
-482else:
-483returnFalse
-484
-485defpath_isdir(self,pathFromRoot=None):
-486"""
-487 Checks if the specified path is a directory on the SMB share.
-488
-489 This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the
-490 contents of the path and filtering for entries that match the basename of the path and are marked as directories.
-491
-492 Args:
-493 path (str, optional): The path to check on the SMB share. Defaults to None.
+465 This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary
+466 with key-value pairs where the key is the share name and the value is a dictionary containing details about the share
+467 such as its name, type, raw type, and any comments associated with the share.
+468
+469 Returns:
+470 dict: A dictionary containing information about each share available on the server.
+471 """
+472
+473self.available_shares={}
+474
+475ifself.connected:
+476ifself.smbClientisnotNone:
+477resp=self.smbClient.listShares()
+478
+479forshareinresp:
+480# SHARE_INFO_1 structure (lmshare.h)
+481# https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1
+482sharename=share["shi1_netname"][:-1]
+483sharecomment=share["shi1_remark"][:-1]
+484sharetype=share["shi1_type"]
+485
+486self.available_shares[sharename.lower()]={
+487"name":sharename,
+488"type":STYPE_MASK(sharetype),
+489"rawtype":sharetype,
+490"comment":sharecomment
+491}
+492else:
+493print("[!] Error: SMBSession.smbClient is None.")494
-495 Returns:
-496 bool: True if the path is a directory, False otherwise or if an error occurs.
-497 """
-498
-499ifpathFromRootisnotNone:
-500# Replace slashes if any
-501path=pathFromRoot.replace('/',ntpath.sep)
-502
-503# Strip wildcards to avoid injections
-504path=path.replace('*','')
-505
-506# Normalize path and strip leading backslash
-507path=ntpath.normpath(path+ntpath.sep).lstrip(ntpath.sep)
-508
-509ifpath.strip()in['','.','..']:
-510# By defininition they exist on the filesystem
-511returnTrue
-512else:
-513try:
-514contents=self.smbClient.listPath(
-515shareName=self.smb_share,
-516path=path+'*'
-517)
-518# Filter on directories
-519contents=[
-520cforcincontents
-521ifc.get_longname()==ntpath.basename(path)andc.is_directory()
-522]
-523return(len(contents)!=0)
-524exceptExceptionase:
-525returnFalse
-526else:
-527returnFalse
-528
-529defpath_isfile(self,path=None):
-530"""
-531 Checks if the specified path is a file on the SMB share.
-532
-533 This method determines if a given path corresponds to a file on the SMB share. It does this by listing the
-534 contents of the path and filtering for entries that match the basename of the path and are not marked as directories.
-535
-536 Args:
-537 path (str, optional): The path to check on the SMB share. Defaults to None.
-538
-539 Returns:
-540 bool: True if the path is a file, False otherwise or if an error occurs.
-541 """
-542
-543ifpathisnotNone:
-544path=path.replace('*','')
-545try:
-546contents=self.smbClient.listPath(
-547shareName=self.smb_share,
-548path=ntpath.normpath(self.smb_cwd+ntpath.sep+path+ntpath.sep)
-549)
-550# Filter on files
-551contents=[
-552cforcincontents
-553ifc.get_longname()==ntpath.basename(path)andnotc.is_directory()
-554]
-555return(len(contents)!=0)
-556exceptExceptionase:
-557returnFalse
-558else:
-559returnFalse
-560
-561defping_smb_session(self):
-562"""
-563 Tests the connectivity to the SMB server by sending an echo command.
-564
-565 This method attempts to send an echo command to the SMB server to check if the session is still active.
-566 It updates the `connected` attribute of the class based on the success or failure of the echo command.
-567
-568 Returns:
-569 bool: True if the echo command succeeds (indicating the session is active), False otherwise.
-570 """
+495returnself.available_shares
+496
+497defmkdir(self,path=None):
+498"""
+499 Creates a directory at the specified path on the SMB share.
+500
+501 This method takes a path and attempts to create the directory structure on the SMB share. If the path includes
+502 nested directories, it will create each directory in the sequence. If a directory already exists, it will skip
+503 the creation for that directory without raising an error.
+504
+505 Args:
+506 path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
+507
+508 Note:
+509 The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
+510 """
+511
+512ifpathisnotNone:
+513# Prepare path
+514path=path.replace('/',ntpath.sep)
+515ifntpath.sepinpath:
+516path=path.strip(ntpath.sep).split(ntpath.sep)
+517else:
+518path=[path]
+519
+520# Create each dir in the path
+521fordepthinrange(1,len(path)+1):
+522tmp_path=ntpath.sep.join(path[:depth])
+523try:
+524self.smbClient.createDirectory(
+525shareName=self.smb_share,
+526pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+tmp_path+ntpath.sep)
+527)
+528exceptimpacket.smbconnection.SessionErroraserr:
+529iferr.getErrorCode()==0xc0000035:
+530# STATUS_OBJECT_NAME_COLLISION
+531# Remote directory already created, this is normal
+532# Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19
+533pass
+534else:
+535print("[!] Failed to create directory '%s': %s"%(tmp_path,err))
+536ifself.config.debug:
+537traceback.print_exc()
+538else:
+539pass
+540
+541defpath_exists(self,path=None):
+542"""
+543 Checks if the specified path exists on the SMB share.
+544
+545 This method determines if a given path exists on the SMB share by attempting to list the contents of the path.
+546 If the path listing is successful and returns one or more entries, the path is considered to exist.
+547
+548 Args:
+549 path (str, optional): The path to check on the SMB share. Defaults to None.
+550
+551 Returns:
+552 bool: True if the path exists, False otherwise or if an error occurs.
+553 """
+554
+555ifpathisnotNone:
+556path=path.replace('*','')
+557try:
+558contents=self.smbClient.listPath(
+559shareName=self.smb_share,
+560path=ntpath.normpath(self.smb_cwd+ntpath.sep+path+ntpath.sep)
+561)
+562return(len(contents)!=0)
+563exceptExceptionase:
+564returnFalse
+565else:
+566returnFalse
+567
+568defpath_isdir(self,pathFromRoot=None):
+569"""
+570 Checks if the specified path is a directory on the SMB share.571
-572try:
-573self.smbClient.getSMBServer().echo()
-574self.connected=True
-575exceptExceptionase:
-576self.connected=False
-577returnself.connected
-578
-579defput_file(self,localpath=None):
-580"""
-581 Uploads a single file to the SMB share.
-582
-583 This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.
-584 It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.
-585 General exceptions are caught and logged, with a traceback provided if debugging is enabled.
-586
-587 Args:
-588 localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
-589 """
-590
-591ifos.path.exists(localpath):
-592ifos.path.isfile(localpath):
-593try:
-594localfile=os.path.basename(localpath)
-595f=LocalFileIO(
-596mode="rb",
-597path=localpath,
-598debug=self.config.debug
-599)
-600self.smbClient.putFile(
-601shareName=self.smb_share,
-602pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+localfile+ntpath.sep),
-603callback=f.read
-604)
-605f.close()
-606except(BrokenPipeError,KeyboardInterrupt)aserr:
-607print("[!] Interrupted.")
-608self.close_smb_session()
-609self.init_smb_session()
-610exceptExceptionaserr:
-611print("[!] Failed to upload '%s': %s"%(localfile,err))
-612ifself.config.debug:
-613traceback.print_exc()
-614else:
-615print("[!] The specified localpath is a directory. Use 'put -r <directory>' instead.")
-616else:
-617print("[!] The specified localpath does not exist.")
+572 This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the
+573 contents of the path and filtering for entries that match the basename of the path and are marked as directories.
+574
+575 Args:
+576 path (str, optional): The path to check on the SMB share. Defaults to None.
+577
+578 Returns:
+579 bool: True if the path is a directory, False otherwise or if an error occurs.
+580 """
+581
+582ifpathFromRootisnotNone:
+583# Replace slashes if any
+584path=pathFromRoot.replace('/',ntpath.sep)
+585
+586# Strip wildcards to avoid injections
+587path=path.replace('*','')
+588
+589# Normalize path and strip leading backslash
+590path=ntpath.normpath(path+ntpath.sep).lstrip(ntpath.sep)
+591
+592ifpath.strip()in['','.','..']:
+593# By defininition they exist on the filesystem
+594returnTrue
+595else:
+596try:
+597contents=self.smbClient.listPath(
+598shareName=self.smb_share,
+599path=path+'*'
+600)
+601# Filter on directories
+602contents=[
+603cforcincontents
+604ifc.get_longname()==ntpath.basename(path)andc.is_directory()
+605]
+606return(len(contents)!=0)
+607exceptExceptionase:
+608returnFalse
+609else:
+610returnFalse
+611
+612defpath_isfile(self,path=None):
+613"""
+614 Checks if the specified path is a file on the SMB share.
+615
+616 This method determines if a given path corresponds to a file on the SMB share. It does this by listing the
+617 contents of the path and filtering for entries that match the basename of the path and are not marked as directories.618
-619defput_file_recursively(self,localpath=None):
-620"""
-621 Recursively uploads files from a specified local directory to the SMB share.
-622
-623 This method walks through the given local directory and all its subdirectories, uploading each file to the
-624 corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,
-625 it iterates over all files and directories within the local path, creating necessary directories on the SMB share
-626 and uploading files. If the local path is not a directory, it prints an error message.
-627
-628 Args:
-629 localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
-630 """
-631
-632ifos.path.exists(localpath):
-633ifos.path.isfile(localpath):
-634# Iterate over all files and directories within the local path
-635local_files={}
-636forroot,dirs,filesinos.walk(localpath):
-637iflen(files)!=0:
-638local_files[root]=files
-639
-640# Iterate over the found files
-641forlocal_dir_pathinsorted(local_files.keys()):
-642print("[>] Putting files of '%s'"%local_dir_path)
-643
-644# Create remote directory
-645remote_dir_path=local_dir_path.replace(os.path.sep,ntpath.sep)
-646self.mkdir(
-647path=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep)
-648)
+619 Args:
+620 path (str, optional): The path to check on the SMB share. Defaults to None.
+621
+622 Returns:
+623 bool: True if the path is a file, False otherwise or if an error occurs.
+624 """
+625
+626ifpathisnotNone:
+627path=path.replace('*','')
+628search_dir=ntpath.normpath(self.smb_cwd+ntpath.sep+path)
+629search_dir=ntpath.dirname(search_dir)+ntpath.sep+'*'
+630try:
+631contents=self.smbClient.listPath(
+632shareName=self.smb_share,
+633path=search_dir
+634)
+635# Filter on files
+636contents=[
+637cforcincontents
+638ifc.get_longname()==ntpath.basename(path)andnotc.is_directory()
+639]
+640return(len(contents)!=0)
+641exceptExceptionase:
+642returnFalse
+643else:
+644returnFalse
+645
+646defping_smb_session(self):
+647"""
+648 Tests the connectivity to the SMB server by sending an echo command.649
-650forlocal_file_pathinlocal_files[local_dir_path]:
-651try:
-652f=LocalFileIO(
-653mode="rb",
-654path=local_dir_path+os.path.sep+local_file_path,
-655debug=self.config.debug
-656)
-657self.smbClient.putFile(
-658shareName=self.smb_share,
-659pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep+local_file_path),
-660callback=f.read
-661)
-662f.close()
-663
-664exceptBrokenPipeErroraserr:
-665f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
-666f.close(remove=True)
-667break
-668exceptExceptionaserr:
-669f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
-670f.close(remove=True)
-671else:
-672print("[!] The specified localpath is a file. Use 'put <file>' instead.")
-673else:
-674print("[!] The specified localpath does not exist.")
-675
-676defrmdir(self,path=None):
-677"""
-678 Removes a directory from the SMB share at the specified path.
-679
-680 This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,
-681 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
-682 the stack trace of the exception.
-683
-684 Args:
-685 path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
-686 """
-687try:
-688self.smbClient.deleteDirectory(
-689shareName=self.smb_share,
-690pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
-691)
-692exceptExceptionaserr:
-693print("[!] Failed to remove directory '%s': %s"%(path,err))
-694ifself.config.debug:
-695traceback.print_exc()
-696
-697defrm(self,path=None):
-698"""
-699 Removes a file from the SMB share at the specified path.
-700
-701 This method attempts to delete a file located at the given path on the SMB share. If the operation fails,
-702 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
-703 the stack trace of the exception.
-704
-705 Args:
-706 path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
-707 """
-708try:
-709self.smbClient.deleteFile(
-710shareName=self.smb_share,
-711pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
-712)
-713exceptExceptionaserr:
-714print("[!] Failed to remove file '%s': %s"%(path,err))
-715ifself.config.debug:
-716traceback.print_exc()
-717
-718deftree(self,path=None):
-719"""
-720 Recursively lists the directory structure of the SMB share starting from the specified path.
-721
-722 This function prints a visual representation of the directory tree of the remote SMB share. It uses
-723 recursion to navigate through directories and lists all files and subdirectories in each directory.
-724 The output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
-725
-726 Args:
-727 path (str, optional): The starting path on the SMB share from which to begin listing the tree.
-728 Defaults to the root of the current share.
-729 """
-730
-731defrecurse_action(base_dir="",path=[],prompt=[]):
-732bars=["│ ","├── ","└── "]
+650 This method attempts to send an echo command to the SMB server to check if the session is still active.
+651 It updates the `connected` attribute of the class based on the success or failure of the echo command.
+652
+653 Returns:
+654 bool: True if the echo command succeeds (indicating the session is active), False otherwise.
+655 """
+656
+657try:
+658self.smbClient.getSMBServer().echo()
+659exceptExceptionase:
+660self.connected=False
+661returnself.connected
+662
+663defput_file(self,localpath=None):
+664"""
+665 Uploads a single file to the SMB share.
+666
+667 This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.
+668 It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.
+669 General exceptions are caught and logged, with a traceback provided if debugging is enabled.
+670
+671 Args:
+672 localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
+673 """
+674
+675ifos.path.exists(localpath):
+676ifos.path.isfile(localpath):
+677try:
+678localfile=os.path.basename(localpath)
+679f=LocalFileIO(
+680mode="rb",
+681path=localpath,
+682debug=self.config.debug
+683)
+684self.smbClient.putFile(
+685shareName=self.smb_share,
+686pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+localfile+ntpath.sep),
+687callback=f.read
+688)
+689f.close()
+690except(BrokenPipeError,KeyboardInterrupt)aserr:
+691print("[!] Interrupted.")
+692self.close_smb_session()
+693self.init_smb_session()
+694exceptExceptionaserr:
+695print("[!] Failed to upload '%s': %s"%(localfile,err))
+696ifself.config.debug:
+697traceback.print_exc()
+698else:
+699print("[!] The specified localpath is a directory. Use 'put -r <directory>' instead.")
+700else:
+701print("[!] The specified localpath does not exist.")
+702
+703defput_file_recursively(self,localpath=None):
+704"""
+705 Recursively uploads files from a specified local directory to the SMB share.
+706
+707 This method walks through the given local directory and all its subdirectories, uploading each file to the
+708 corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,
+709 it iterates over all files and directories within the local path, creating necessary directories on the SMB share
+710 and uploading files. If the local path is not a directory, it prints an error message.
+711
+712 Args:
+713 localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
+714 """
+715
+716ifos.path.exists(localpath):
+717ifos.path.isfile(localpath):
+718# Iterate over all files and directories within the local path
+719local_files={}
+720forroot,dirs,filesinos.walk(localpath):
+721iflen(files)!=0:
+722local_files[root]=files
+723
+724# Iterate over the found files
+725forlocal_dir_pathinsorted(local_files.keys()):
+726print("[>] Putting files of '%s'"%local_dir_path)
+727
+728# Create remote directory
+729remote_dir_path=local_dir_path.replace(os.path.sep,ntpath.sep)
+730self.mkdir(
+731path=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep)
+732)733
-734remote_smb_path=ntpath.normpath(base_dir+ntpath.sep+ntpath.sep.join(path))
-735
-736entries=[]
-737try:
-738entries=self.smbClient.listPath(
-739shareName=self.smb_share,
-740path=remote_smb_path+'\\*'
-741)
-742exceptimpacket.smbconnection.SessionErroraserr:
-743code,const,text=err.getErrorCode(),err.getErrorString()[0],err.getErrorString()[1]
-744errmsg="Error 0x%08x (%s): %s"%(code,const,text)
-745ifself.config.no_colors:
-746print("%s%s"%(''.join(prompt+[bars[2]]),errmsg))
-747else:
-748print("%s\x1b[1;91m%s\x1b[0m"%(''.join(prompt+[bars[2]]),errmsg))
-749return
-750
-751entries=[eforeinentriesife.get_longname()notin[".",".."]]
-752entries=sorted(entries,key=lambdax:x.get_longname())
-753
-754#
-755iflen(entries)>1:
-756index=0
-757forentryinentries:
-758index+=1
-759# This is the first entry
-760ifindex==0:
-761ifentry.is_directory():
-762ifself.config.no_colors:
-763print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-764else:
-765print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-766recurse_action(
-767base_dir=base_dir,
-768path=path+[entry.get_longname()],
-769prompt=prompt+["│ "]
-770)
-771else:
-772ifself.config.no_colors:
-773print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-774else:
-775print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-776
-777# This is the last entry
-778elifindex==len(entries):
-779ifentry.is_directory():
-780ifself.config.no_colors:
-781print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-782else:
-783print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-784recurse_action(
-785base_dir=base_dir,
-786path=path+[entry.get_longname()],
-787prompt=prompt+[" "]
-788)
-789else:
-790ifself.config.no_colors:
-791print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-792else:
-793print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-794
-795# These are entries in the middle
-796else:
-797ifentry.is_directory():
-798ifself.config.no_colors:
-799print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-800else:
-801print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-802recurse_action(
-803base_dir=base_dir,
-804path=path+[entry.get_longname()],
-805prompt=prompt+["│ "]
-806)
-807else:
-808ifself.config.no_colors:
-809print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-810else:
-811print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-812
-813#
-814eliflen(entries)==1:
-815entry=entries[0]
-816ifentry.is_directory():
-817ifself.config.no_colors:
-818print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-819else:
-820print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-821recurse_action(
-822base_dir=base_dir,
-823path=path+[entry.get_longname()],
-824prompt=prompt+[" "]
-825)
-826else:
-827ifself.config.no_colors:
-828print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-829else:
-830print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-831
-832# Entrypoint
-833try:
-834ifself.config.no_colors:
-835print("%s\\"%path)
-836else:
-837print("\x1b[1;96m%s\x1b[0m\\"%path)
-838recurse_action(
-839base_dir=self.smb_cwd,
-840path=[path],
-841prompt=[""]
-842)
-843except(BrokenPipeError,KeyboardInterrupt)ase:
-844print("[!] Interrupted.")
-845self.close_smb_session()
-846self.init_smb_session()
-847
-848# Setter / Getter
-849
-850defset_share(self,shareName):
-851"""
-852 Sets the current SMB share to the specified share name.
-853
-854 This method updates the SMB session to use the specified share name. It checks if the share name is valid
-855 and updates the smb_share attribute of the SMBSession instance.
-856
-857 Parameters:
-858 shareName (str): The name of the share to set as the current SMB share.
-859
-860 Raises:
-861 ValueError: If the shareName is None or an empty string.
-862 """
-863
-864ifshareNameisnotNone:
-865self.smb_share=shareName
-866
-867defset_cwd(self,path=None):
-868"""
-869 Sets the current working directory on the SMB share to the specified path.
-870
-871 This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.
-872 If the specified path is not a directory, the cwd remains unchanged.
-873
-874 Parameters:
-875 path (str): The path to set as the current working directory.
-876
-877 Raises:
-878 ValueError: If the specified path is not a directory.
-879 """
-880
-881ifpathisnotNone:
-882# Set path separators to ntpath sep
-883if'/'inpath:
-884path=path.replace('/',ntpath.sep)
-885
-886ifpath.startswith(ntpath.sep):
-887# Absolute path
-888path=path+ntpath.sep
-889else:
-890# Relative path to the CWD
-891iflen(self.smb_cwd)==0:
-892path=path+ntpath.sep
-893else:
-894path=self.smb_cwd+ntpath.sep+path
-895
-896# Path normalization
-897path=ntpath.normpath(path)
-898path=re.sub(r'\\+',r'\\',path)
-899
-900ifpathin["",".",".."]:
-901self.smb_cwd=""
-902else:
-903ifself.path_isdir(pathFromRoot=path.strip(ntpath.sep)):
-904# Path exists on the remote
-905self.smb_cwd=ntpath.normpath(path)
-906else:
-907# Path does not exists or is not a directory on the remote
-908print("[!] Remote directory '%s' does not exist."%path)
+734forlocal_file_pathinlocal_files[local_dir_path]:
+735try:
+736f=LocalFileIO(
+737mode="rb",
+738path=local_dir_path+os.path.sep+local_file_path,
+739debug=self.config.debug
+740)
+741self.smbClient.putFile(
+742shareName=self.smb_share,
+743pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep+local_file_path),
+744callback=f.read
+745)
+746f.close()
+747
+748exceptBrokenPipeErroraserr:
+749f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
+750f.close(remove=True)
+751break
+752exceptExceptionaserr:
+753f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
+754f.close(remove=True)
+755else:
+756print("[!] The specified localpath is a file. Use 'put <file>' instead.")
+757else:
+758print("[!] The specified localpath does not exist.")
+759
+760defrmdir(self,path=None):
+761"""
+762 Removes a directory from the SMB share at the specified path.
+763
+764 This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,
+765 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
+766 the stack trace of the exception.
+767
+768 Args:
+769 path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
+770 """
+771try:
+772self.smbClient.deleteDirectory(
+773shareName=self.smb_share,
+774pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
+775)
+776exceptExceptionaserr:
+777print("[!] Failed to remove directory '%s': %s"%(path,err))
+778ifself.config.debug:
+779traceback.print_exc()
+780
+781defrm(self,path=None):
+782"""
+783 Removes a file from the SMB share at the specified path.
+784
+785 This method attempts to delete a file located at the given path on the SMB share. If the operation fails,
+786 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
+787 the stack trace of the exception.
+788
+789 Args:
+790 path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
+791 """
+792try:
+793self.smbClient.deleteFile(
+794shareName=self.smb_share,
+795pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
+796)
+797exceptExceptionaserr:
+798print("[!] Failed to remove file '%s': %s"%(path,err))
+799ifself.config.debug:
+800traceback.print_exc()
+801
+802deftree(self,path=None):
+803"""
+804 Recursively lists the directory structure of the SMB share starting from the specified path.
+805
+806 This function prints a visual representation of the directory tree of the remote SMB share. It uses
+807 recursion to navigate through directories and lists all files and subdirectories in each directory.
+808 The output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
+809
+810 Args:
+811 path (str, optional): The starting path on the SMB share from which to begin listing the tree.
+812 Defaults to the root of the current share.
+813 """
+814
+815defrecurse_action(base_dir="",path=[],prompt=[]):
+816bars=["│ ","├── ","└── "]
+817
+818remote_smb_path=ntpath.normpath(base_dir+ntpath.sep+ntpath.sep.join(path))
+819
+820entries=[]
+821try:
+822entries=self.smbClient.listPath(
+823shareName=self.smb_share,
+824path=remote_smb_path+'\\*'
+825)
+826exceptimpacket.smbconnection.SessionErroraserr:
+827code,const,text=err.getErrorCode(),err.getErrorString()[0],err.getErrorString()[1]
+828errmsg="Error 0x%08x (%s): %s"%(code,const,text)
+829ifself.config.no_colors:
+830print("%s%s"%(''.join(prompt+[bars[2]]),errmsg))
+831else:
+832print("%s\x1b[1;91m%s\x1b[0m"%(''.join(prompt+[bars[2]]),errmsg))
+833return
+834
+835entries=[eforeinentriesife.get_longname()notin[".",".."]]
+836entries=sorted(entries,key=lambdax:x.get_longname())
+837
+838#
+839iflen(entries)>1:
+840index=0
+841forentryinentries:
+842index+=1
+843# This is the first entry
+844ifindex==0:
+845ifentry.is_directory():
+846ifself.config.no_colors:
+847print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+848else:
+849print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+850recurse_action(
+851base_dir=base_dir,
+852path=path+[entry.get_longname()],
+853prompt=prompt+["│ "]
+854)
+855else:
+856ifself.config.no_colors:
+857print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+858else:
+859print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+860
+861# This is the last entry
+862elifindex==len(entries):
+863ifentry.is_directory():
+864ifself.config.no_colors:
+865print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+866else:
+867print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+868recurse_action(
+869base_dir=base_dir,
+870path=path+[entry.get_longname()],
+871prompt=prompt+[" "]
+872)
+873else:
+874ifself.config.no_colors:
+875print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+876else:
+877print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+878
+879# These are entries in the middle
+880else:
+881ifentry.is_directory():
+882ifself.config.no_colors:
+883print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+884else:
+885print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+886recurse_action(
+887base_dir=base_dir,
+888path=path+[entry.get_longname()],
+889prompt=prompt+["│ "]
+890)
+891else:
+892ifself.config.no_colors:
+893print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+894else:
+895print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+896
+897#
+898eliflen(entries)==1:
+899entry=entries[0]
+900ifentry.is_directory():
+901ifself.config.no_colors:
+902print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+903else:
+904print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+905recurse_action(
+906base_dir=base_dir,
+907path=path+[entry.get_longname()],
+908prompt=prompt+[" "]
+909)
+910else:
+911ifself.config.no_colors:
+912print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+913else:
+914print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+915
+916# Entrypoint
+917try:
+918ifself.config.no_colors:
+919print("%s\\"%path)
+920else:
+921print("\x1b[1;96m%s\x1b[0m\\"%path)
+922recurse_action(
+923base_dir=self.smb_cwd,
+924path=[path],
+925prompt=[""]
+926)
+927except(BrokenPipeError,KeyboardInterrupt)ase:
+928print("[!] Interrupted.")
+929self.close_smb_session()
+930self.init_smb_session()
+931
+932# Setter / Getter
+933
+934defset_share(self,shareName):
+935"""
+936 Sets the current SMB share to the specified share name.
+937
+938 This method updates the SMB session to use the specified share name. It checks if the share name is valid
+939 and updates the smb_share attribute of the SMBSession instance.
+940
+941 Parameters:
+942 shareName (str): The name of the share to set as the current SMB share.
+943
+944 Raises:
+945 ValueError: If the shareName is None or an empty string.
+946 """
+947
+948ifshareNameisnotNone:
+949self.list_shares()
+950ifshareName.lower()inself.available_shares.keys():
+951# Doing this in order to keep the case of the share adevertised by the remote machine
+952self.smb_share=self.available_shares[shareName.lower()]["name"]
+953else:
+954print("[!] Could not set share '%s', it does not exist remotely."%shareName)
+955
+956defset_cwd(self,path=None):
+957"""
+958 Sets the current working directory on the SMB share to the specified path.
+959
+960 This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.
+961 If the specified path is not a directory, the cwd remains unchanged.
+962
+963 Parameters:
+964 path (str): The path to set as the current working directory.
+965
+966 Raises:
+967 ValueError: If the specified path is not a directory.
+968 """
+969
+970ifpathisnotNone:
+971# Set path separators to ntpath sep
+972if'/'inpath:
+973path=path.replace('/',ntpath.sep)
+974
+975ifpath.startswith(ntpath.sep):
+976# Absolute path
+977path=path+ntpath.sep
+978else:
+979# Relative path to the CWD
+980iflen(self.smb_cwd)==0:
+981path=path+ntpath.sep
+982else:
+983path=self.smb_cwd+ntpath.sep+path
+984
+985# Path normalization
+986path=ntpath.normpath(path)
+987path=re.sub(r'\\+',r'\\',path)
+988
+989ifpathin["",".",".."]:
+990self.smb_cwd=""
+991else:
+992ifself.path_isdir(pathFromRoot=path.strip(ntpath.sep)):
+993# Path exists on the remote
+994self.smb_cwd=ntpath.normpath(path)
+995else:
+996# Path does not exists or is not a directory on the remote
+997print("[!] Remote directory '%s' does not exist."%path)
73definit_smb_session(self):
- 74"""
- 75 Initializes and establishes a session with the SMB server.
- 76
- 77 This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.
- 78 It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization.
- 79
- 80 The method will print debug information if the `debug` attribute is set to True. Upon successful connection and authentication, it sets the `connected` attribute to True.
- 81
- 82 Returns:
- 83 bool: True if the connection and authentication are successful, False otherwise.
- 84 """
- 85
- 86ifself.config.debug:
- 87print("[debug] [>] Connecting to remote SMB server '%s' ... "%self.address)
- 88try:
- 89self.smbClient=impacket.smbconnection.SMBConnection(
- 90remoteName=self.address,
- 91remoteHost=self.address,
- 92sess_port=int(445)
- 93)
- 94exceptOSErroraserr:
- 95print("[!] %s"%err)
- 96self.smbClient=None
- 97
- 98self.connected=False
- 99ifself.smbClientisnotNone:
-100ifself.use_kerberos:
-101ifself.config.debug:
-102print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... "%(self.domain,self.username))
-103self.connected=self.smbClient.kerberosLogin(
-104user=self.username,
-105password=self.password,
-106domain=self.domain,
-107lmhash=self.lmhash,
-108nthash=self.nthash,
-109aesKey=self.aesKey,
-110kdcHost=self.kdcHost
-111)
-112
-113else:
-114ifself.config.debug:
-115print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... "%(self.domain,self.username))
-116self.connected=self.smbClient.login(
-117user=self.username,
-118password=self.password,
-119domain=self.domain,
-120lmhash=self.lmhash,
-121nthash=self.nthash
-122)
-123
-124ifself.connected:
-125print("[+] Successfully authenticated to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
-126else:
-127print("[!] Failed to authenticate to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
-128
-129returnself.connected
+
74definit_smb_session(self):
+ 75"""
+ 76 Initializes and establishes a session with the SMB server.
+ 77
+ 78 This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.
+ 79 It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization.
+ 80
+ 81 The method will print debug information if the `debug` attribute is set to True. Upon successful connection and authentication, it sets the `connected` attribute to True.
+ 82
+ 83 Returns:
+ 84 bool: True if the connection and authentication are successful, False otherwise.
+ 85 """
+ 86
+ 87self.connected=False
+ 88
+ 89ifself.config.debug:
+ 90print("[debug] [>] Connecting to remote SMB server '%s' ... "%self.address)
+ 91try:
+ 92self.smbClient=impacket.smbconnection.SMBConnection(
+ 93remoteName=self.address,
+ 94remoteHost=self.address,
+ 95sess_port=int(445)
+ 96)
+ 97exceptOSErroraserr:
+ 98print("[!] %s"%err)
+ 99self.smbClient=None
+100
+101ifself.smbClientisnotNone:
+102ifself.use_kerberos:
+103ifself.config.debug:
+104print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... "%(self.domain,self.username))
+105try:
+106self.connected=self.smbClient.kerberosLogin(
+107user=self.username,
+108password=self.password,
+109domain=self.domain,
+110lmhash=self.lmhash,
+111nthash=self.nthash,
+112aesKey=self.aesKey,
+113kdcHost=self.kdcHost
+114)
+115exceptimpacket.smbconnection.SessionErroraserr:
+116ifself.config.debug:
+117traceback.print_exc()
+118print("[!] Could not login: %s"%err)
+119self.connected=False
+120
+121else:
+122ifself.config.debug:
+123print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... "%(self.domain,self.username))
+124try:
+125self.connected=self.smbClient.login(
+126user=self.username,
+127password=self.password,
+128domain=self.domain,
+129lmhash=self.lmhash,
+130nthash=self.nthash
+131)
+132exceptimpacket.smbconnection.SessionErroraserr:
+133ifself.config.debug:
+134traceback.print_exc()
+135print("[!] Could not login: %s"%err)
+136self.connected=False
+137
+138ifself.connected:
+139print("[+] Successfully authenticated to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
+140else:
+141print("[!] Failed to authenticate to '%s' as '%s\\%s'!"%(self.address,self.domain,self.username))
+142
+143returnself.connected
@@ -2291,26 +2487,28 @@
-
131defclose_smb_session(self):
-132"""
-133 Closes the current SMB session by disconnecting the SMB client.
-134
-135 This method ensures that the SMB client connection is properly closed. It checks if the client is connected
-136 and if so, it closes the connection and resets the connection status.
-137
-138 Raises:
-139 Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
-140 """
-141
-142ifself.smbClientisnotNone:
-143ifself.connected:
-144self.smbClient.close()
-145self.connected=False
-146print("[+] SMB connection closed successfully.")
-147else:
-148print("[!] No active SMB connection to close.")
-149else:
-150raiseException("SMB client is not initialized.")
+
145defclose_smb_session(self):
+146"""
+147 Closes the current SMB session by disconnecting the SMB client.
+148
+149 This method ensures that the SMB client connection is properly closed. It checks if the client is connected
+150 and if so, it closes the connection and resets the connection status.
+151
+152 Raises:
+153 Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
+154 """
+155
+156ifself.smbClientisnotNone:
+157ifself.connected:
+158self.smbClient.close()
+159self.connected=False
+160ifself.config.debug:
+161print("[+] SMB connection closed successfully.")
+162else:
+163ifself.config.debug:
+164print("[!] No active SMB connection to close.")
+165else:
+166raiseException("SMB client is not initialized.")
@@ -2324,6 +2522,105 @@
+
+
+
+
+
+ def
+ read_file(self, path=None):
+
+
+
+
+
+
170defread_file(self,path=None):
+171ifself.path_isfile(path=path):
+172tmp_file_path=self.smb_cwd+ntpath.sep+path
+173matches=self.smbClient.listPath(
+174shareName=self.smb_share,
+175path=tmp_file_path
+176)
+177
+178fh=io.BytesIO()
+179try:
+180# opening the files in streams instead of mounting shares allows
+181# for running the script from unprivileged containers
+182self.smbClient.getFile(self.smb_share,tmp_file_path,fh.write)
+183exceptimpacket.smbconnection.SessionErrorase:
+184returnNone
+185rawdata=fh.getvalue()
+186fh.close()
+187returnrawdata
+188else:
+189print("[!] Remote path '%s' is not a file."%path)
+
154defget_file(self,path=None,keepRemotePath=False):
-155"""
-156 Retrieves a file from the specified path on the SMB share.
-157
-158 This method attempts to retrieve a file from the given path within the currently connected SMB share.
-159 If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local
-160 file object and writing the contents of the remote file to it using the SMB client's getFile method.
-161
-162 Parameters:
-163 path (str): The path of the file to retrieve. If None, uses the current smb_path.
-164
-165 Returns:
-166 None
-167 """
-168
-169tmp_file_path=self.smb_cwd+ntpath.sep+path
-170matches=self.smbClient.listPath(
-171shareName=self.smb_share,
-172path=tmp_file_path
-173)
-174
-175forentryinmatches:
-176ifentry.is_directory():
-177print("[>] Skipping '%s' because it is a directory."%tmp_file_path)
-178else:
-179try:
-180ifntpath.sepinpath:
-181outputfile=ntpath.dirname(path)+ntpath.sep+entry.get_longname()
-182else:
-183outputfile=entry.get_longname()
-184f=LocalFileIO(
-185mode="wb",
-186path=outputfile,
-187expected_size=entry.get_filesize(),
-188debug=self.config.debug,
-189keepRemotePath=keepRemotePath
-190)
-191self.smbClient.getFile(
-192shareName=self.smb_share,
-193pathName=tmp_file_path,
-194callback=f.write
-195)
-196f.close()
-197except(BrokenPipeError,KeyboardInterrupt)ase:
-198f.close()
-199print("\x1b[v\x1b[o\r[!] Interrupted.")
-200self.close_smb_session()
-201self.init_smb_session()
-202
-203returnNone
+
237defget_file(self,path=None,keepRemotePath=False):
+238"""
+239 Retrieves a file from the specified path on the SMB share.
+240
+241 This method attempts to retrieve a file from the given path within the currently connected SMB share.
+242 If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local
+243 file object and writing the contents of the remote file to it using the SMB client's getFile method.
+244
+245 Parameters:
+246 path (str): The path of the file to retrieve. If None, uses the current smb_path.
+247
+248 Returns:
+249 None
+250 """
+251
+252tmp_file_path=self.smb_cwd+ntpath.sep+path
+253matches=self.smbClient.listPath(
+254shareName=self.smb_share,
+255path=tmp_file_path
+256)
+257
+258forentryinmatches:
+259ifentry.is_directory():
+260print("[>] Skipping '%s' because it is a directory."%tmp_file_path)
+261else:
+262try:
+263ifntpath.sepinpath:
+264outputfile=ntpath.dirname(path)+ntpath.sep+entry.get_longname()
+265else:
+266outputfile=entry.get_longname()
+267f=LocalFileIO(
+268mode="wb",
+269path=outputfile,
+270expected_size=entry.get_filesize(),
+271debug=self.config.debug,
+272keepRemotePath=keepRemotePath
+273)
+274self.smbClient.getFile(
+275shareName=self.smb_share,
+276pathName=tmp_file_path,
+277callback=f.write
+278)
+279f.close()
+280except(BrokenPipeError,KeyboardInterrupt)ase:
+281f.close()
+282print("\x1b[v\x1b[o\r[!] Interrupted.")
+283self.close_smb_session()
+284self.init_smb_session()
+285
+286returnNone
@@ -2415,73 +2712,73 @@
-
205defget_file_recursively(self,path=None):
-206"""
-207 Recursively retrieves files from a specified path on the SMB share.
-208
-209 This method navigates through all directories starting from the given path,
-210 and downloads all files found. It handles directories recursively, ensuring
-211 that all nested files are retrieved. The method skips over directory entries
-212 and handles errors gracefully, attempting to continue the operation where possible.
-213
-214 Parameters:
-215 path (str): The initial directory path from which to start the recursive file retrieval.
-216 If None, it starts from the root of the configured SMB share.
-217 """
-218
-219defrecurse_action(base_dir="",path=[]):
-220remote_smb_path=base_dir+ntpath.sep.join(path)
-221entries=self.smbClient.listPath(
-222shareName=self.smb_share,
-223path=remote_smb_path+'\\*'
-224)
-225iflen(entries)!=0:
-226files=[entryforentryinentriesifnotentry.is_directory()]
-227directories=[entryforentryinentriesifentry.is_directory()andentry.get_longname()notin[".",".."]]
-228
-229# Files
-230iflen(files)!=0:
-231print("[>] Retrieving files of '%s'"%remote_smb_path)
-232forentry_fileinfiles:
-233ifnotentry_file.is_directory():
-234f=LocalFileIO(
-235mode="wb",
-236path=remote_smb_path+ntpath.sep+entry_file.get_longname(),
-237expected_size=entry_file.get_filesize(),
-238debug=self.config.debug
-239)
-240try:
-241self.smbClient.getFile(
-242shareName=self.smb_share,
-243pathName=remote_smb_path+ntpath.sep+entry_file.get_longname(),
-244callback=f.write
-245)
-246f.close()
-247exceptBrokenPipeErroraserr:
-248f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
-249f.close(remove=True)
-250break
-251exceptExceptionaserr:
-252f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
-253f.close(remove=True)
-254
-255# Directories
-256forentry_directoryindirectories:
-257ifentry_directory.is_directory():
-258recurse_action(
-259base_dir=self.smb_cwd,
-260path=path+[entry_directory.get_longname()]
-261)
-262# Entrypoint
-263try:
-264recurse_action(
-265base_dir=self.smb_cwd,
-266path=[path]
-267)
-268except(BrokenPipeError,KeyboardInterrupt)ase:
-269print("\x1b[v\x1b[o\r[!] Interrupted.")
-270self.close_smb_session()
-271self.init_smb_session()
+
288defget_file_recursively(self,path=None):
+289"""
+290 Recursively retrieves files from a specified path on the SMB share.
+291
+292 This method navigates through all directories starting from the given path,
+293 and downloads all files found. It handles directories recursively, ensuring
+294 that all nested files are retrieved. The method skips over directory entries
+295 and handles errors gracefully, attempting to continue the operation where possible.
+296
+297 Parameters:
+298 path (str): The initial directory path from which to start the recursive file retrieval.
+299 If None, it starts from the root of the configured SMB share.
+300 """
+301
+302defrecurse_action(base_dir="",path=[]):
+303remote_smb_path=base_dir+ntpath.sep.join(path)
+304entries=self.smbClient.listPath(
+305shareName=self.smb_share,
+306path=remote_smb_path+'\\*'
+307)
+308iflen(entries)!=0:
+309files=[entryforentryinentriesifnotentry.is_directory()]
+310directories=[entryforentryinentriesifentry.is_directory()andentry.get_longname()notin[".",".."]]
+311
+312# Files
+313iflen(files)!=0:
+314print("[>] Retrieving files of '%s'"%remote_smb_path)
+315forentry_fileinfiles:
+316ifnotentry_file.is_directory():
+317f=LocalFileIO(
+318mode="wb",
+319path=remote_smb_path+ntpath.sep+entry_file.get_longname(),
+320expected_size=entry_file.get_filesize(),
+321debug=self.config.debug
+322)
+323try:
+324self.smbClient.getFile(
+325shareName=self.smb_share,
+326pathName=remote_smb_path+ntpath.sep+entry_file.get_longname(),
+327callback=f.write
+328)
+329f.close()
+330exceptBrokenPipeErroraserr:
+331f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
+332f.close(remove=True)
+333break
+334exceptExceptionaserr:
+335f.set_error(message="[bold red]Failed downloading '%s': %s"%(f.path,err))
+336f.close(remove=True)
+337
+338# Directories
+339forentry_directoryindirectories:
+340ifentry_directory.is_directory():
+341recurse_action(
+342base_dir=self.smb_cwd,
+343path=path+[entry_directory.get_longname()]
+344)
+345# Entrypoint
+346try:
+347recurse_action(
+348base_dir=self.smb_cwd,
+349path=[path]
+350)
+351except(BrokenPipeError,KeyboardInterrupt)ase:
+352print("\x1b[v\x1b[o\r[!] Interrupted.")
+353self.close_smb_session()
+354self.init_smb_session()
@@ -2510,80 +2807,80 @@
-
273definfo(self,share=True,server=True):
-274"""
-275 Displays information about the server and optionally the shares.
-276
-277 This method prints detailed information about the server's characteristics such as NetBIOS names, DNS details, OS information, and SMB capabilities. If the `share` parameter is set to True and a share is currently set, it will also attempt to display information about the share.
-278
-279 Parameters:
-280 share (bool): If True, display information about the current share.
-281 server (bool): If True, display information about the server.
-282
-283 Returns:
-284 None
-285 """
-286
-287ifserver:
-288ifself.config.no_colors:
-289print("[+] Server:")
-290print(" ├─NetBIOS:")
-291print(" │ ├─ NetBIOS Hostname ──────── : %s"%(self.smbClient.getServerName()))
-292print(" │ └─ NetBIOS Domain ────────── : %s"%(self.smbClient.getServerDomain()))
-293print(" ├─DNS:")
-294print(" │ ├─ DNS Hostname ──────────── : %s"%(self.smbClient.getServerDNSHostName()))
-295print(" │ └─ DNS Domain ────────────── : %s"%(self.smbClient.getServerDNSDomainName()))
-296print(" ├─OS:")
-297print(" │ ├─ OS Name ───────────────── : %s"%(self.smbClient.getServerOS()))
-298print(" │ └─ OS Version ────────────── : %s.%s.%s"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
-299print(" ├─Server:")
-300print(" │ ├─ Signing Required ──────── : %s"%(self.smbClient.isSigningRequired()))
-301print(" │ ├─ Login Required ────────── : %s"%(self.smbClient.isLoginRequired()))
-302print(" │ ├─ Supports NTLMv2 ───────── : %s"%(self.smbClient.doesSupportNTLMv2()))
-303MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
-304print(" │ ├─ Max size of read chunk ── : %d bytes (%s)"%(MaxReadSize,b_filesize(MaxReadSize)))
-305MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
-306print(" │ └─ Max size of write chunk ─ : %d bytes (%s)"%(MaxWriteSize,b_filesize(MaxWriteSize)))
-307print(" └─")
-308else:
-309print("[+] Server:")
-310print(" ├─NetBIOS:")
-311print(" │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerName()))
-312print(" │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDomain()))
-313print(" ├─DNS:")
-314print(" │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSHostName()))
-315print(" │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSDomainName()))
-316print(" ├─OS:")
-317print(" │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerOS()))
-318print(" │ └─ \x1b[94mOS Version\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s.%s.%s\x1b[0m"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
-319print(" ├─Server:")
-320print(" │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isSigningRequired()))
-321print(" │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isLoginRequired()))
-322print(" │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.doesSupportNTLMv2()))
-323MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
-324print(" │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxReadSize,b_filesize(MaxReadSize)))
-325MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
-326print(" │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxWriteSize,b_filesize(MaxWriteSize)))
-327print(" └─")
-328
-329ifshareandself.smb_shareisnotNone:
-330share_name=self.available_shares.get(self.smb_share.lower(),"")["name"]
-331share_comment=self.available_shares.get(self.smb_share.lower(),"")["comment"]
-332share_type=self.available_shares.get(self.smb_share.lower(),"")["type"]
-333share_type=', '.join([s.replace("STYPE_","")forsinshare_type])
-334share_rawtype=self.available_shares.get(self.smb_share.lower(),"")["rawtype"]
-335ifself.config.no_colors:
-336print("\n[+] Share:")
-337print(" ├─ Name ──────────── : %s"%(share_name))
-338print(" ├─ Description ───── : %s"%(share_comment))
-339print(" ├─ Type ──────────── : %s"%(share_type))
-340print(" └─ Raw type value ── : %s"%(share_rawtype))
-341else:
-342print("\n[+] Share:")
-343print(" ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_name))
-344print(" ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_comment))
-345print(" ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_type))
-346print(" └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m"%(share_rawtype))
+
356definfo(self,share=True,server=True):
+357"""
+358 Displays information about the server and optionally the shares.
+359
+360 This method prints detailed information about the server's characteristics such as NetBIOS names, DNS details, OS information, and SMB capabilities. If the `share` parameter is set to True and a share is currently set, it will also attempt to display information about the share.
+361
+362 Parameters:
+363 share (bool): If True, display information about the current share.
+364 server (bool): If True, display information about the server.
+365
+366 Returns:
+367 None
+368 """
+369
+370ifserver:
+371ifself.config.no_colors:
+372print("[+] Server:")
+373print(" ├─NetBIOS:")
+374print(" │ ├─ NetBIOS Hostname ──────── : %s"%(self.smbClient.getServerName()))
+375print(" │ └─ NetBIOS Domain ────────── : %s"%(self.smbClient.getServerDomain()))
+376print(" ├─DNS:")
+377print(" │ ├─ DNS Hostname ──────────── : %s"%(self.smbClient.getServerDNSHostName()))
+378print(" │ └─ DNS Domain ────────────── : %s"%(self.smbClient.getServerDNSDomainName()))
+379print(" ├─OS:")
+380print(" │ ├─ OS Name ───────────────── : %s"%(self.smbClient.getServerOS()))
+381print(" │ └─ OS Version ────────────── : %s.%s.%s"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
+382print(" ├─Server:")
+383print(" │ ├─ Signing Required ──────── : %s"%(self.smbClient.isSigningRequired()))
+384print(" │ ├─ Login Required ────────── : %s"%(self.smbClient.isLoginRequired()))
+385print(" │ ├─ Supports NTLMv2 ───────── : %s"%(self.smbClient.doesSupportNTLMv2()))
+386MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
+387print(" │ ├─ Max size of read chunk ── : %d bytes (%s)"%(MaxReadSize,b_filesize(MaxReadSize)))
+388MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
+389print(" │ └─ Max size of write chunk ─ : %d bytes (%s)"%(MaxWriteSize,b_filesize(MaxWriteSize)))
+390print(" └─")
+391else:
+392print("[+] Server:")
+393print(" ├─NetBIOS:")
+394print(" │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerName()))
+395print(" │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDomain()))
+396print(" ├─DNS:")
+397print(" │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSHostName()))
+398print(" │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerDNSDomainName()))
+399print(" ├─OS:")
+400print(" │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.getServerOS()))
+401print(" │ └─ \x1b[94mOS Version\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s.%s.%s\x1b[0m"%(self.smbClient.getServerOSMajor(),self.smbClient.getServerOSMinor(),self.smbClient.getServerOSBuild()))
+402print(" ├─Server:")
+403print(" │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isSigningRequired()))
+404print(" │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.isLoginRequired()))
+405print(" │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m"%(self.smbClient.doesSupportNTLMv2()))
+406MaxReadSize=self.smbClient.getIOCapabilities()["MaxReadSize"]
+407print(" │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxReadSize,b_filesize(MaxReadSize)))
+408MaxWriteSize=self.smbClient.getIOCapabilities()["MaxWriteSize"]
+409print(" │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m"%(MaxWriteSize,b_filesize(MaxWriteSize)))
+410print(" └─")
+411
+412ifshareandself.smb_shareisnotNone:
+413share_name=self.available_shares.get(self.smb_share.lower(),"")["name"]
+414share_comment=self.available_shares.get(self.smb_share.lower(),"")["comment"]
+415share_type=self.available_shares.get(self.smb_share.lower(),"")["type"]
+416share_type=', '.join([s.replace("STYPE_","")forsinshare_type])
+417share_rawtype=self.available_shares.get(self.smb_share.lower(),"")["rawtype"]
+418ifself.config.no_colors:
+419print("\n[+] Share:")
+420print(" ├─ Name ──────────── : %s"%(share_name))
+421print(" ├─ Description ───── : %s"%(share_comment))
+422print(" ├─ Type ──────────── : %s"%(share_type))
+423print(" └─ Raw type value ── : %s"%(share_rawtype))
+424else:
+425print("\n[+] Share:")
+426print(" ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_name))
+427print(" ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_comment))
+428print(" ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m"%(share_type))
+429print(" └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m"%(share_rawtype))
@@ -2612,35 +2909,35 @@
-
348deflist_contents(self,path=None):
-349"""
-350 Lists the contents of a specified directory on the SMB share.
-351
-352 This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path`
-353 is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with
-354 the long names of the files and directories as keys and their respective SMB entry objects as values.
-355
-356 Args:
-357 shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.
-358 path (str, optional): The directory path to list contents from. Defaults to the current path if None.
-359
-360 Returns:
-361 dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
-362 """
-363
-364ifpathisNoneorlen(path)==0:
-365path=self.smb_cwd
-366path=path.rstrip(ntpath.sep)+ntpath.sep+"*"
-367
-368contents={}
-369entries=self.smbClient.listPath(
-370shareName=self.smb_share,
-371path=path
-372)
-373forentryinentries:
-374contents[entry.get_longname()]=entry
-375
-376returncontents
+
431deflist_contents(self,path=None):
+432"""
+433 Lists the contents of a specified directory on the SMB share.
+434
+435 This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path`
+436 is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with
+437 the long names of the files and directories as keys and their respective SMB entry objects as values.
+438
+439 Args:
+440 shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.
+441 path (str, optional): The directory path to list contents from. Defaults to the current path if None.
+442
+443 Returns:
+444 dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
+445 """
+446
+447ifpathisNoneorlen(path)==0:
+448path=self.smb_cwd
+449path=path.rstrip(ntpath.sep)+ntpath.sep+"*"
+450
+451contents={}
+452entries=self.smbClient.listPath(
+453shareName=self.smb_share,
+454path=path
+455)
+456forentryinentries:
+457contents[entry.get_longname()]=entry
+458
+459returncontents
@@ -2671,41 +2968,41 @@
-
378deflist_shares(self):
-379"""
-380 Lists all the shares available on the connected SMB server.
-381
-382 This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary
-383 with key-value pairs where the key is the share name and the value is a dictionary containing details about the share
-384 such as its name, type, raw type, and any comments associated with the share.
-385
-386 Returns:
-387 dict: A dictionary containing information about each share available on the server.
-388 """
-389
-390self.available_shares={}
-391
-392ifself.connected:
-393ifself.smbClientisnotNone:
-394resp=self.smbClient.listShares()
-395
-396forshareinresp:
-397# SHARE_INFO_1 structure (lmshare.h)
-398# https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1
-399sharename=share["shi1_netname"][:-1]
-400sharecomment=share["shi1_remark"][:-1]
-401sharetype=share["shi1_type"]
-402
-403self.available_shares[sharename.lower()]={
-404"name":sharename,
-405"type":STYPE_MASK(sharetype),
-406"rawtype":sharetype,
-407"comment":sharecomment
-408}
-409else:
-410print("[!] Error: SMBSession.smbClient is None.")
-411
-412returnself.available_shares
+
461deflist_shares(self):
+462"""
+463 Lists all the shares available on the connected SMB server.
+464
+465 This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary
+466 with key-value pairs where the key is the share name and the value is a dictionary containing details about the share
+467 such as its name, type, raw type, and any comments associated with the share.
+468
+469 Returns:
+470 dict: A dictionary containing information about each share available on the server.
+471 """
+472
+473self.available_shares={}
+474
+475ifself.connected:
+476ifself.smbClientisnotNone:
+477resp=self.smbClient.listShares()
+478
+479forshareinresp:
+480# SHARE_INFO_1 structure (lmshare.h)
+481# https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1
+482sharename=share["shi1_netname"][:-1]
+483sharecomment=share["shi1_remark"][:-1]
+484sharetype=share["shi1_type"]
+485
+486self.available_shares[sharename.lower()]={
+487"name":sharename,
+488"type":STYPE_MASK(sharetype),
+489"rawtype":sharetype,
+490"comment":sharecomment
+491}
+492else:
+493print("[!] Error: SMBSession.smbClient is None.")
+494
+495returnself.available_shares
@@ -2732,49 +3029,49 @@
-
414defmkdir(self,path=None):
-415"""
-416 Creates a directory at the specified path on the SMB share.
-417
-418 This method takes a path and attempts to create the directory structure on the SMB share. If the path includes
-419 nested directories, it will create each directory in the sequence. If a directory already exists, it will skip
-420 the creation for that directory without raising an error.
-421
-422 Args:
-423 path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
-424
-425 Note:
-426 The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
-427 """
-428
-429ifpathisnotNone:
-430# Prepare path
-431path=path.replace('/',ntpath.sep)
-432ifntpath.sepinpath:
-433path=path.strip(ntpath.sep).split(ntpath.sep)
-434else:
-435path=[path]
-436
-437# Create each dir in the path
-438fordepthinrange(1,len(path)+1):
-439tmp_path=ntpath.sep.join(path[:depth])
-440try:
-441self.smbClient.createDirectory(
-442shareName=self.smb_share,
-443pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+tmp_path+ntpath.sep)
-444)
-445exceptimpacket.smbconnection.SessionErroraserr:
-446iferr.getErrorCode()==0xc0000035:
-447# STATUS_OBJECT_NAME_COLLISION
-448# Remote directory already created, this is normal
-449# Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19
-450pass
-451else:
-452print("[!] Failed to create directory '%s': %s"%(tmp_path,err))
-453ifself.config.debug:
-454traceback.print_exc()
-455else:
-456pass
+
497defmkdir(self,path=None):
+498"""
+499 Creates a directory at the specified path on the SMB share.
+500
+501 This method takes a path and attempts to create the directory structure on the SMB share. If the path includes
+502 nested directories, it will create each directory in the sequence. If a directory already exists, it will skip
+503 the creation for that directory without raising an error.
+504
+505 Args:
+506 path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
+507
+508 Note:
+509 The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
+510 """
+511
+512ifpathisnotNone:
+513# Prepare path
+514path=path.replace('/',ntpath.sep)
+515ifntpath.sepinpath:
+516path=path.strip(ntpath.sep).split(ntpath.sep)
+517else:
+518path=[path]
+519
+520# Create each dir in the path
+521fordepthinrange(1,len(path)+1):
+522tmp_path=ntpath.sep.join(path[:depth])
+523try:
+524self.smbClient.createDirectory(
+525shareName=self.smb_share,
+526pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+tmp_path+ntpath.sep)
+527)
+528exceptimpacket.smbconnection.SessionErroraserr:
+529iferr.getErrorCode()==0xc0000035:
+530# STATUS_OBJECT_NAME_COLLISION
+531# Remote directory already created, this is normal
+532# Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19
+533pass
+534else:
+535print("[!] Failed to create directory '%s': %s"%(tmp_path,err))
+536ifself.config.debug:
+537traceback.print_exc()
+538else:
+539pass
@@ -2804,32 +3101,32 @@
-
458defpath_exists(self,path=None):
-459"""
-460 Checks if the specified path exists on the SMB share.
-461
-462 This method determines if a given path exists on the SMB share by attempting to list the contents of the path.
-463 If the path listing is successful and returns one or more entries, the path is considered to exist.
-464
-465 Args:
-466 path (str, optional): The path to check on the SMB share. Defaults to None.
-467
-468 Returns:
-469 bool: True if the path exists, False otherwise or if an error occurs.
-470 """
-471
-472ifpathisnotNone:
-473path=path.replace('*','')
-474try:
-475contents=self.smbClient.listPath(
-476shareName=self.smb_share,
-477path=ntpath.normpath(self.smb_cwd+ntpath.sep+path+ntpath.sep)
-478)
-479return(len(contents)!=0)
-480exceptExceptionase:
-481returnFalse
-482else:
-483returnFalse
+
541defpath_exists(self,path=None):
+542"""
+543 Checks if the specified path exists on the SMB share.
+544
+545 This method determines if a given path exists on the SMB share by attempting to list the contents of the path.
+546 If the path listing is successful and returns one or more entries, the path is considered to exist.
+547
+548 Args:
+549 path (str, optional): The path to check on the SMB share. Defaults to None.
+550
+551 Returns:
+552 bool: True if the path exists, False otherwise or if an error occurs.
+553 """
+554
+555ifpathisnotNone:
+556path=path.replace('*','')
+557try:
+558contents=self.smbClient.listPath(
+559shareName=self.smb_share,
+560path=ntpath.normpath(self.smb_cwd+ntpath.sep+path+ntpath.sep)
+561)
+562return(len(contents)!=0)
+563exceptExceptionase:
+564returnFalse
+565else:
+566returnFalse
@@ -2858,49 +3155,49 @@
-
485defpath_isdir(self,pathFromRoot=None):
-486"""
-487 Checks if the specified path is a directory on the SMB share.
-488
-489 This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the
-490 contents of the path and filtering for entries that match the basename of the path and are marked as directories.
-491
-492 Args:
-493 path (str, optional): The path to check on the SMB share. Defaults to None.
-494
-495 Returns:
-496 bool: True if the path is a directory, False otherwise or if an error occurs.
-497 """
-498
-499ifpathFromRootisnotNone:
-500# Replace slashes if any
-501path=pathFromRoot.replace('/',ntpath.sep)
-502
-503# Strip wildcards to avoid injections
-504path=path.replace('*','')
-505
-506# Normalize path and strip leading backslash
-507path=ntpath.normpath(path+ntpath.sep).lstrip(ntpath.sep)
-508
-509ifpath.strip()in['','.','..']:
-510# By defininition they exist on the filesystem
-511returnTrue
-512else:
-513try:
-514contents=self.smbClient.listPath(
-515shareName=self.smb_share,
-516path=path+'*'
-517)
-518# Filter on directories
-519contents=[
-520cforcincontents
-521ifc.get_longname()==ntpath.basename(path)andc.is_directory()
-522]
-523return(len(contents)!=0)
-524exceptExceptionase:
-525returnFalse
-526else:
-527returnFalse
+
568defpath_isdir(self,pathFromRoot=None):
+569"""
+570 Checks if the specified path is a directory on the SMB share.
+571
+572 This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the
+573 contents of the path and filtering for entries that match the basename of the path and are marked as directories.
+574
+575 Args:
+576 path (str, optional): The path to check on the SMB share. Defaults to None.
+577
+578 Returns:
+579 bool: True if the path is a directory, False otherwise or if an error occurs.
+580 """
+581
+582ifpathFromRootisnotNone:
+583# Replace slashes if any
+584path=pathFromRoot.replace('/',ntpath.sep)
+585
+586# Strip wildcards to avoid injections
+587path=path.replace('*','')
+588
+589# Normalize path and strip leading backslash
+590path=ntpath.normpath(path+ntpath.sep).lstrip(ntpath.sep)
+591
+592ifpath.strip()in['','.','..']:
+593# By defininition they exist on the filesystem
+594returnTrue
+595else:
+596try:
+597contents=self.smbClient.listPath(
+598shareName=self.smb_share,
+599path=path+'*'
+600)
+601# Filter on directories
+602contents=[
+603cforcincontents
+604ifc.get_longname()==ntpath.basename(path)andc.is_directory()
+605]
+606return(len(contents)!=0)
+607exceptExceptionase:
+608returnFalse
+609else:
+610returnFalse
@@ -2929,37 +3226,39 @@
-
529defpath_isfile(self,path=None):
-530"""
-531 Checks if the specified path is a file on the SMB share.
-532
-533 This method determines if a given path corresponds to a file on the SMB share. It does this by listing the
-534 contents of the path and filtering for entries that match the basename of the path and are not marked as directories.
-535
-536 Args:
-537 path (str, optional): The path to check on the SMB share. Defaults to None.
-538
-539 Returns:
-540 bool: True if the path is a file, False otherwise or if an error occurs.
-541 """
-542
-543ifpathisnotNone:
-544path=path.replace('*','')
-545try:
-546contents=self.smbClient.listPath(
-547shareName=self.smb_share,
-548path=ntpath.normpath(self.smb_cwd+ntpath.sep+path+ntpath.sep)
-549)
-550# Filter on files
-551contents=[
-552cforcincontents
-553ifc.get_longname()==ntpath.basename(path)andnotc.is_directory()
-554]
-555return(len(contents)!=0)
-556exceptExceptionase:
-557returnFalse
-558else:
-559returnFalse
+
612defpath_isfile(self,path=None):
+613"""
+614 Checks if the specified path is a file on the SMB share.
+615
+616 This method determines if a given path corresponds to a file on the SMB share. It does this by listing the
+617 contents of the path and filtering for entries that match the basename of the path and are not marked as directories.
+618
+619 Args:
+620 path (str, optional): The path to check on the SMB share. Defaults to None.
+621
+622 Returns:
+623 bool: True if the path is a file, False otherwise or if an error occurs.
+624 """
+625
+626ifpathisnotNone:
+627path=path.replace('*','')
+628search_dir=ntpath.normpath(self.smb_cwd+ntpath.sep+path)
+629search_dir=ntpath.dirname(search_dir)+ntpath.sep+'*'
+630try:
+631contents=self.smbClient.listPath(
+632shareName=self.smb_share,
+633path=search_dir
+634)
+635# Filter on files
+636contents=[
+637cforcincontents
+638ifc.get_longname()==ntpath.basename(path)andnotc.is_directory()
+639]
+640return(len(contents)!=0)
+641exceptExceptionase:
+642returnFalse
+643else:
+644returnFalse
@@ -2988,23 +3287,22 @@
-
561defping_smb_session(self):
-562"""
-563 Tests the connectivity to the SMB server by sending an echo command.
-564
-565 This method attempts to send an echo command to the SMB server to check if the session is still active.
-566 It updates the `connected` attribute of the class based on the success or failure of the echo command.
-567
-568 Returns:
-569 bool: True if the echo command succeeds (indicating the session is active), False otherwise.
-570 """
-571
-572try:
-573self.smbClient.getSMBServer().echo()
-574self.connected=True
-575exceptExceptionase:
-576self.connected=False
-577returnself.connected
+
646defping_smb_session(self):
+647"""
+648 Tests the connectivity to the SMB server by sending an echo command.
+649
+650 This method attempts to send an echo command to the SMB server to check if the session is still active.
+651 It updates the `connected` attribute of the class based on the success or failure of the echo command.
+652
+653 Returns:
+654 bool: True if the echo command succeeds (indicating the session is active), False otherwise.
+655 """
+656
+657try:
+658self.smbClient.getSMBServer().echo()
+659exceptExceptionase:
+660self.connected=False
+661returnself.connected
@@ -3030,45 +3328,45 @@
-
579defput_file(self,localpath=None):
-580"""
-581 Uploads a single file to the SMB share.
-582
-583 This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.
-584 It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.
-585 General exceptions are caught and logged, with a traceback provided if debugging is enabled.
-586
-587 Args:
-588 localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
-589 """
-590
-591ifos.path.exists(localpath):
-592ifos.path.isfile(localpath):
-593try:
-594localfile=os.path.basename(localpath)
-595f=LocalFileIO(
-596mode="rb",
-597path=localpath,
-598debug=self.config.debug
-599)
-600self.smbClient.putFile(
-601shareName=self.smb_share,
-602pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+localfile+ntpath.sep),
-603callback=f.read
-604)
-605f.close()
-606except(BrokenPipeError,KeyboardInterrupt)aserr:
-607print("[!] Interrupted.")
-608self.close_smb_session()
-609self.init_smb_session()
-610exceptExceptionaserr:
-611print("[!] Failed to upload '%s': %s"%(localfile,err))
-612ifself.config.debug:
-613traceback.print_exc()
-614else:
-615print("[!] The specified localpath is a directory. Use 'put -r <directory>' instead.")
-616else:
-617print("[!] The specified localpath does not exist.")
+
663defput_file(self,localpath=None):
+664"""
+665 Uploads a single file to the SMB share.
+666
+667 This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.
+668 It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.
+669 General exceptions are caught and logged, with a traceback provided if debugging is enabled.
+670
+671 Args:
+672 localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
+673 """
+674
+675ifos.path.exists(localpath):
+676ifos.path.isfile(localpath):
+677try:
+678localfile=os.path.basename(localpath)
+679f=LocalFileIO(
+680mode="rb",
+681path=localpath,
+682debug=self.config.debug
+683)
+684self.smbClient.putFile(
+685shareName=self.smb_share,
+686pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+localfile+ntpath.sep),
+687callback=f.read
+688)
+689f.close()
+690except(BrokenPipeError,KeyboardInterrupt)aserr:
+691print("[!] Interrupted.")
+692self.close_smb_session()
+693self.init_smb_session()
+694exceptExceptionaserr:
+695print("[!] Failed to upload '%s': %s"%(localfile,err))
+696ifself.config.debug:
+697traceback.print_exc()
+698else:
+699print("[!] The specified localpath is a directory. Use 'put -r <directory>' instead.")
+700else:
+701print("[!] The specified localpath does not exist.")
@@ -3095,62 +3393,62 @@
-
619defput_file_recursively(self,localpath=None):
-620"""
-621 Recursively uploads files from a specified local directory to the SMB share.
-622
-623 This method walks through the given local directory and all its subdirectories, uploading each file to the
-624 corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,
-625 it iterates over all files and directories within the local path, creating necessary directories on the SMB share
-626 and uploading files. If the local path is not a directory, it prints an error message.
-627
-628 Args:
-629 localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
-630 """
-631
-632ifos.path.exists(localpath):
-633ifos.path.isfile(localpath):
-634# Iterate over all files and directories within the local path
-635local_files={}
-636forroot,dirs,filesinos.walk(localpath):
-637iflen(files)!=0:
-638local_files[root]=files
-639
-640# Iterate over the found files
-641forlocal_dir_pathinsorted(local_files.keys()):
-642print("[>] Putting files of '%s'"%local_dir_path)
-643
-644# Create remote directory
-645remote_dir_path=local_dir_path.replace(os.path.sep,ntpath.sep)
-646self.mkdir(
-647path=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep)
-648)
-649
-650forlocal_file_pathinlocal_files[local_dir_path]:
-651try:
-652f=LocalFileIO(
-653mode="rb",
-654path=local_dir_path+os.path.sep+local_file_path,
-655debug=self.config.debug
-656)
-657self.smbClient.putFile(
-658shareName=self.smb_share,
-659pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep+local_file_path),
-660callback=f.read
-661)
-662f.close()
-663
-664exceptBrokenPipeErroraserr:
-665f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
-666f.close(remove=True)
-667break
-668exceptExceptionaserr:
-669f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
-670f.close(remove=True)
-671else:
-672print("[!] The specified localpath is a file. Use 'put <file>' instead.")
-673else:
-674print("[!] The specified localpath does not exist.")
+
703defput_file_recursively(self,localpath=None):
+704"""
+705 Recursively uploads files from a specified local directory to the SMB share.
+706
+707 This method walks through the given local directory and all its subdirectories, uploading each file to the
+708 corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,
+709 it iterates over all files and directories within the local path, creating necessary directories on the SMB share
+710 and uploading files. If the local path is not a directory, it prints an error message.
+711
+712 Args:
+713 localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
+714 """
+715
+716ifos.path.exists(localpath):
+717ifos.path.isfile(localpath):
+718# Iterate over all files and directories within the local path
+719local_files={}
+720forroot,dirs,filesinos.walk(localpath):
+721iflen(files)!=0:
+722local_files[root]=files
+723
+724# Iterate over the found files
+725forlocal_dir_pathinsorted(local_files.keys()):
+726print("[>] Putting files of '%s'"%local_dir_path)
+727
+728# Create remote directory
+729remote_dir_path=local_dir_path.replace(os.path.sep,ntpath.sep)
+730self.mkdir(
+731path=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep)
+732)
+733
+734forlocal_file_pathinlocal_files[local_dir_path]:
+735try:
+736f=LocalFileIO(
+737mode="rb",
+738path=local_dir_path+os.path.sep+local_file_path,
+739debug=self.config.debug
+740)
+741self.smbClient.putFile(
+742shareName=self.smb_share,
+743pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+remote_dir_path+ntpath.sep+local_file_path),
+744callback=f.read
+745)
+746f.close()
+747
+748exceptBrokenPipeErroraserr:
+749f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
+750f.close(remove=True)
+751break
+752exceptExceptionaserr:
+753f.set_error(message="[bold red]Failed uploading '%s': %s"%(f.path,err))
+754f.close(remove=True)
+755else:
+756print("[!] The specified localpath is a file. Use 'put <file>' instead.")
+757else:
+758print("[!] The specified localpath does not exist.")
@@ -3178,26 +3476,26 @@
-
676defrmdir(self,path=None):
-677"""
-678 Removes a directory from the SMB share at the specified path.
-679
-680 This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,
-681 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
-682 the stack trace of the exception.
-683
-684 Args:
-685 path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
-686 """
-687try:
-688self.smbClient.deleteDirectory(
-689shareName=self.smb_share,
-690pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
-691)
-692exceptExceptionaserr:
-693print("[!] Failed to remove directory '%s': %s"%(path,err))
-694ifself.config.debug:
-695traceback.print_exc()
+
760defrmdir(self,path=None):
+761"""
+762 Removes a directory from the SMB share at the specified path.
+763
+764 This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,
+765 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
+766 the stack trace of the exception.
+767
+768 Args:
+769 path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
+770 """
+771try:
+772self.smbClient.deleteDirectory(
+773shareName=self.smb_share,
+774pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
+775)
+776exceptExceptionaserr:
+777print("[!] Failed to remove directory '%s': %s"%(path,err))
+778ifself.config.debug:
+779traceback.print_exc()
@@ -3224,26 +3522,26 @@
-
697defrm(self,path=None):
-698"""
-699 Removes a file from the SMB share at the specified path.
-700
-701 This method attempts to delete a file located at the given path on the SMB share. If the operation fails,
-702 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
-703 the stack trace of the exception.
-704
-705 Args:
-706 path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
-707 """
-708try:
-709self.smbClient.deleteFile(
-710shareName=self.smb_share,
-711pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
-712)
-713exceptExceptionaserr:
-714print("[!] Failed to remove file '%s': %s"%(path,err))
-715ifself.config.debug:
-716traceback.print_exc()
+
781defrm(self,path=None):
+782"""
+783 Removes a file from the SMB share at the specified path.
+784
+785 This method attempts to delete a file located at the given path on the SMB share. If the operation fails,
+786 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
+787 the stack trace of the exception.
+788
+789 Args:
+790 path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
+791 """
+792try:
+793self.smbClient.deleteFile(
+794shareName=self.smb_share,
+795pathName=ntpath.normpath(self.smb_cwd+ntpath.sep+path),
+796)
+797exceptExceptionaserr:
+798print("[!] Failed to remove file '%s': %s"%(path,err))
+799ifself.config.debug:
+800traceback.print_exc()
@@ -3270,135 +3568,135 @@
-
718deftree(self,path=None):
-719"""
-720 Recursively lists the directory structure of the SMB share starting from the specified path.
-721
-722 This function prints a visual representation of the directory tree of the remote SMB share. It uses
-723 recursion to navigate through directories and lists all files and subdirectories in each directory.
-724 The output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
-725
-726 Args:
-727 path (str, optional): The starting path on the SMB share from which to begin listing the tree.
-728 Defaults to the root of the current share.
-729 """
-730
-731defrecurse_action(base_dir="",path=[],prompt=[]):
-732bars=["│ ","├── ","└── "]
-733
-734remote_smb_path=ntpath.normpath(base_dir+ntpath.sep+ntpath.sep.join(path))
-735
-736entries=[]
-737try:
-738entries=self.smbClient.listPath(
-739shareName=self.smb_share,
-740path=remote_smb_path+'\\*'
-741)
-742exceptimpacket.smbconnection.SessionErroraserr:
-743code,const,text=err.getErrorCode(),err.getErrorString()[0],err.getErrorString()[1]
-744errmsg="Error 0x%08x (%s): %s"%(code,const,text)
-745ifself.config.no_colors:
-746print("%s%s"%(''.join(prompt+[bars[2]]),errmsg))
-747else:
-748print("%s\x1b[1;91m%s\x1b[0m"%(''.join(prompt+[bars[2]]),errmsg))
-749return
-750
-751entries=[eforeinentriesife.get_longname()notin[".",".."]]
-752entries=sorted(entries,key=lambdax:x.get_longname())
-753
-754#
-755iflen(entries)>1:
-756index=0
-757forentryinentries:
-758index+=1
-759# This is the first entry
-760ifindex==0:
-761ifentry.is_directory():
-762ifself.config.no_colors:
-763print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-764else:
-765print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-766recurse_action(
-767base_dir=base_dir,
-768path=path+[entry.get_longname()],
-769prompt=prompt+["│ "]
-770)
-771else:
-772ifself.config.no_colors:
-773print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-774else:
-775print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-776
-777# This is the last entry
-778elifindex==len(entries):
-779ifentry.is_directory():
-780ifself.config.no_colors:
-781print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-782else:
-783print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-784recurse_action(
-785base_dir=base_dir,
-786path=path+[entry.get_longname()],
-787prompt=prompt+[" "]
-788)
-789else:
-790ifself.config.no_colors:
-791print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-792else:
-793print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-794
-795# These are entries in the middle
-796else:
-797ifentry.is_directory():
-798ifself.config.no_colors:
-799print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-800else:
-801print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-802recurse_action(
-803base_dir=base_dir,
-804path=path+[entry.get_longname()],
-805prompt=prompt+["│ "]
-806)
-807else:
-808ifself.config.no_colors:
-809print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-810else:
-811print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
-812
-813#
-814eliflen(entries)==1:
-815entry=entries[0]
-816ifentry.is_directory():
-817ifself.config.no_colors:
-818print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-819else:
-820print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-821recurse_action(
-822base_dir=base_dir,
-823path=path+[entry.get_longname()],
-824prompt=prompt+[" "]
-825)
-826else:
-827ifself.config.no_colors:
-828print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-829else:
-830print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
-831
-832# Entrypoint
-833try:
-834ifself.config.no_colors:
-835print("%s\\"%path)
-836else:
-837print("\x1b[1;96m%s\x1b[0m\\"%path)
-838recurse_action(
-839base_dir=self.smb_cwd,
-840path=[path],
-841prompt=[""]
-842)
-843except(BrokenPipeError,KeyboardInterrupt)ase:
-844print("[!] Interrupted.")
-845self.close_smb_session()
-846self.init_smb_session()
+
802deftree(self,path=None):
+803"""
+804 Recursively lists the directory structure of the SMB share starting from the specified path.
+805
+806 This function prints a visual representation of the directory tree of the remote SMB share. It uses
+807 recursion to navigate through directories and lists all files and subdirectories in each directory.
+808 The output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
+809
+810 Args:
+811 path (str, optional): The starting path on the SMB share from which to begin listing the tree.
+812 Defaults to the root of the current share.
+813 """
+814
+815defrecurse_action(base_dir="",path=[],prompt=[]):
+816bars=["│ ","├── ","└── "]
+817
+818remote_smb_path=ntpath.normpath(base_dir+ntpath.sep+ntpath.sep.join(path))
+819
+820entries=[]
+821try:
+822entries=self.smbClient.listPath(
+823shareName=self.smb_share,
+824path=remote_smb_path+'\\*'
+825)
+826exceptimpacket.smbconnection.SessionErroraserr:
+827code,const,text=err.getErrorCode(),err.getErrorString()[0],err.getErrorString()[1]
+828errmsg="Error 0x%08x (%s): %s"%(code,const,text)
+829ifself.config.no_colors:
+830print("%s%s"%(''.join(prompt+[bars[2]]),errmsg))
+831else:
+832print("%s\x1b[1;91m%s\x1b[0m"%(''.join(prompt+[bars[2]]),errmsg))
+833return
+834
+835entries=[eforeinentriesife.get_longname()notin[".",".."]]
+836entries=sorted(entries,key=lambdax:x.get_longname())
+837
+838#
+839iflen(entries)>1:
+840index=0
+841forentryinentries:
+842index+=1
+843# This is the first entry
+844ifindex==0:
+845ifentry.is_directory():
+846ifself.config.no_colors:
+847print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+848else:
+849print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+850recurse_action(
+851base_dir=base_dir,
+852path=path+[entry.get_longname()],
+853prompt=prompt+["│ "]
+854)
+855else:
+856ifself.config.no_colors:
+857print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+858else:
+859print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+860
+861# This is the last entry
+862elifindex==len(entries):
+863ifentry.is_directory():
+864ifself.config.no_colors:
+865print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+866else:
+867print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+868recurse_action(
+869base_dir=base_dir,
+870path=path+[entry.get_longname()],
+871prompt=prompt+[" "]
+872)
+873else:
+874ifself.config.no_colors:
+875print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+876else:
+877print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+878
+879# These are entries in the middle
+880else:
+881ifentry.is_directory():
+882ifself.config.no_colors:
+883print("%s%s\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+884else:
+885print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+886recurse_action(
+887base_dir=base_dir,
+888path=path+[entry.get_longname()],
+889prompt=prompt+["│ "]
+890)
+891else:
+892ifself.config.no_colors:
+893print("%s%s"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+894else:
+895print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[1]]),entry.get_longname()))
+896
+897#
+898eliflen(entries)==1:
+899entry=entries[0]
+900ifentry.is_directory():
+901ifself.config.no_colors:
+902print("%s%s\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+903else:
+904print("%s\x1b[1;96m%s\x1b[0m\\"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+905recurse_action(
+906base_dir=base_dir,
+907path=path+[entry.get_longname()],
+908prompt=prompt+[" "]
+909)
+910else:
+911ifself.config.no_colors:
+912print("%s%s"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+913else:
+914print("%s\x1b[1m%s\x1b[0m"%(''.join(prompt+[bars[2]]),entry.get_longname()))
+915
+916# Entrypoint
+917try:
+918ifself.config.no_colors:
+919print("%s\\"%path)
+920else:
+921print("\x1b[1;96m%s\x1b[0m\\"%path)
+922recurse_action(
+923base_dir=self.smb_cwd,
+924path=[path],
+925prompt=[""]
+926)
+927except(BrokenPipeError,KeyboardInterrupt)ase:
+928print("[!] Interrupted.")
+929self.close_smb_session()
+930self.init_smb_session()
@@ -3426,22 +3724,27 @@
-
850defset_share(self,shareName):
-851"""
-852 Sets the current SMB share to the specified share name.
-853
-854 This method updates the SMB session to use the specified share name. It checks if the share name is valid
-855 and updates the smb_share attribute of the SMBSession instance.
-856
-857 Parameters:
-858 shareName (str): The name of the share to set as the current SMB share.
-859
-860 Raises:
-861 ValueError: If the shareName is None or an empty string.
-862 """
-863
-864ifshareNameisnotNone:
-865self.smb_share=shareName
+
934defset_share(self,shareName):
+935"""
+936 Sets the current SMB share to the specified share name.
+937
+938 This method updates the SMB session to use the specified share name. It checks if the share name is valid
+939 and updates the smb_share attribute of the SMBSession instance.
+940
+941 Parameters:
+942 shareName (str): The name of the share to set as the current SMB share.
+943
+944 Raises:
+945 ValueError: If the shareName is None or an empty string.
+946 """
+947
+948ifshareNameisnotNone:
+949self.list_shares()
+950ifshareName.lower()inself.available_shares.keys():
+951# Doing this in order to keep the case of the share adevertised by the remote machine
+952self.smb_share=self.available_shares[shareName.lower()]["name"]
+953else:
+954print("[!] Could not set share '%s', it does not exist remotely."%shareName)
@@ -3470,48 +3773,48 @@
-
867defset_cwd(self,path=None):
-868"""
-869 Sets the current working directory on the SMB share to the specified path.
-870
-871 This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.
-872 If the specified path is not a directory, the cwd remains unchanged.
-873
-874 Parameters:
-875 path (str): The path to set as the current working directory.
-876
-877 Raises:
-878 ValueError: If the specified path is not a directory.
-879 """
-880
-881ifpathisnotNone:
-882# Set path separators to ntpath sep
-883if'/'inpath:
-884path=path.replace('/',ntpath.sep)
-885
-886ifpath.startswith(ntpath.sep):
-887# Absolute path
-888path=path+ntpath.sep
-889else:
-890# Relative path to the CWD
-891iflen(self.smb_cwd)==0:
-892path=path+ntpath.sep
-893else:
-894path=self.smb_cwd+ntpath.sep+path
-895
-896# Path normalization
-897path=ntpath.normpath(path)
-898path=re.sub(r'\\+',r'\\',path)
-899
-900ifpathin["",".",".."]:
-901self.smb_cwd=""
-902else:
-903ifself.path_isdir(pathFromRoot=path.strip(ntpath.sep)):
-904# Path exists on the remote
-905self.smb_cwd=ntpath.normpath(path)
-906else:
-907# Path does not exists or is not a directory on the remote
-908print("[!] Remote directory '%s' does not exist."%path)
+
956defset_cwd(self,path=None):
+957"""
+958 Sets the current working directory on the SMB share to the specified path.
+959
+960 This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.
+961 If the specified path is not a directory, the cwd remains unchanged.
+962
+963 Parameters:
+964 path (str): The path to set as the current working directory.
+965
+966 Raises:
+967 ValueError: If the specified path is not a directory.
+968 """
+969
+970ifpathisnotNone:
+971# Set path separators to ntpath sep
+972if'/'inpath:
+973path=path.replace('/',ntpath.sep)
+974
+975ifpath.startswith(ntpath.sep):
+976# Absolute path
+977path=path+ntpath.sep
+978else:
+979# Relative path to the CWD
+980iflen(self.smb_cwd)==0:
+981path=path+ntpath.sep
+982else:
+983path=self.smb_cwd+ntpath.sep+path
+984
+985# Path normalization
+986path=ntpath.normpath(path)
+987path=re.sub(r'\\+',r'\\',path)
+988
+989ifpathin["",".",".."]:
+990self.smb_cwd=""
+991else:
+992ifself.path_isdir(pathFromRoot=path.strip(ntpath.sep)):
+993# Path exists on the remote
+994self.smb_cwd=ntpath.normpath(path)
+995else:
+996# Path does not exists or is not a directory on the remote
+997print("[!] Remote directory '%s' does not exist."%path)
41# Adding positional arguments 42parser.add_argument("paths",metavar="PATH",type=str,nargs="*",default=[],help="The starting point(s) for the search.") 43
- 44# Adding tests, actions, and options for expressions (incomplete for brevity)
+ 44# Adding options for filtering 45parser.add_argument("-name",type=str,help="Base of file name (the path with the leading directories removed).") 46parser.add_argument("-iname",type=str,help="Like -name, but the match is case insensitive.") 47parser.add_argument("-type",type=str,default=None,help="File type (e.g., f for regular file, d for directory).")
@@ -125,7 +125,7 @@
54parser.add_argument("-ls",action="store_true",default=False,help="List current file in ls -dils format on standard output.") 55parser.add_argument("-download",action="store_true",default=False,help="List current file in ls -dils format on standard output.") 56
- 57# Other options (incomplete for brevity)
+ 57# Other options 58parser.add_argument("-maxdepth",type=int,help="Descend at most levels (a non-negative integer) levels of directories below the command line arguments.") 59parser.add_argument("-mindepth",type=int,help="Do not apply any tests or actions at levels less than levels (a non-negative integer).") 60
@@ -142,181 +142,155 @@
71 72returnself.options 73
- 74def__recurse_action(self,paths=[],depth=0):
- 75"""
- 76 Recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
- 77
- 78 Args:
- 79 base_dir (str): The base directory to start the search from.
- 80 paths (list): List of paths to search within the base directory.
- 81 depth (int): The current depth level in the directory hierarchy.
- 82
- 83 Returns:
- 84 None
- 85 """
- 86
- 87next_directories_to_explore=[]
+ 74def__find_callback(self,entry,fullpath,depth):
+ 75# Documentation for __find_callback function
+ 76"""
+ 77 This function serves as a callback for the find operation. It applies filters based on the command line arguments
+ 78 and decides whether to print, download, or list the entry in 'ls -dils' format if it matches the specified filters.
+ 79
+ 80 Args:
+ 81 entry (SMBEntry): The current file or directory entry being processed.
+ 82 fullpath (str): The full path to the entry.
+ 83
+ 84 The function checks against filters such as file name, case sensitivity, file type, and size. If the entry matches
+ 85 the filters, it will perform actions like printing the entry's details, downloading the entry, or listing the entry
+ 86 based on the options provided in the command line arguments.
+ 87 """ 88
- 89forpathinpaths:
- 90remote_smb_path=ntpath.normpath(self.smbSession.smb_cwd+ntpath.sep+path)
- 91
- 92entries=[]
- 93try:
- 94entries=self.smbSession.smbClient.listPath(
- 95shareName=self.smbSession.smb_share,
- 96path=(remote_smb_path+ntpath.sep+'*')
- 97)
- 98exceptimpacket.smbconnection.SessionErroraserr:
- 99continue
-100# Remove dot names
-101entries=[eforeinentriesife.get_longname()notin[".",".."]]
-102# Sort the entries ignoring case
-103entries=sorted(entries,key=lambdax:x.get_longname().lower())
-104
-105# Match and print results
-106do_print_results=True
-107ifself.options.mindepthisnotNone:
-108ifdepth<self.options.mindepth:
-109do_print_results=False
-110ifself.options.maxdepthisnotNone:
-111ifdepth>self.options.maxdepth:
-112do_print_results=False
-113
-114ifdo_print_results:
-115forentryinentries:
-116do_print_entry=False
-117# Print directory
-118ifentry.is_directory():
-119if(self.options.type=='d'orself.options.typeisNone):
-120# No name filtering
-121ifself.options.nameisNoneandself.options.inameisNone:
-122do_print_entry=True
-123
-124# Filtering on names case sensitive
-125elifself.options.nameisnotNone:
-126if'*'inself.options.name:
-127regex=self.options.name
-128regex=regex.replace('.','\\.')
-129regex=regex.replace('*','.*')
-130regex='^'+regex+'$'
-131ifre.match(regex,entry.get_longname()):
-132do_print_entry=True
-133else:
-134do_print_entry=False
-135else:
-136do_print_entry=(entry.get_longname().lower()==self.options.name.lower())
-137
-138# Filtering on names case insensitive
-139elifself.options.inameisnotNone:
-140if'*'inself.options.iname:
-141regex=self.options.iname
-142regex=regex.replace('.','\\.')
-143regex=regex.replace('*','.*')
-144regex='^'+regex+'$'
-145ifre.match(regex,entry.get_longname(),re.IGNORECASE):
-146do_print_entry=True
-147else:
-148do_print_entry=False
-149else:
-150do_print_entry=(entry.get_longname().lower()==self.options.iname.lower())
-151
-152# Print file
-153else:
-154if(self.options.type=='f'orself.options.typeisNone):
-155# No name filtering
-156ifself.options.nameisNoneandself.options.inameisNone:
-157do_print_entry=True
-158
-159# Filtering on names case sensitive
-160elifself.options.nameisnotNone:
-161if'*'inself.options.name:
-162regex=self.options.name
-163regex=regex.replace('.','\\.')
-164regex=regex.replace('*','.*')
-165regex='^'+regex+'$'
-166ifre.match(regex,entry.get_longname()):
-167do_print_entry=True
-168else:
-169do_print_entry=False
-170else:
-171do_print_entry=(entry.get_longname().lower()==self.options.name.lower())
-172
-173# Filtering on names case insensitive
-174elifself.options.inameisnotNone:
-175if'*'inself.options.iname:
-176regex=self.options.iname
-177regex=regex.replace('.','\\.')
-178regex=regex.replace('*','.*')
-179regex='^'+regex+'$'
-180ifre.match(regex,entry.get_longname(),re.IGNORECASE):
-181do_print_entry=True
-182else:
-183do_print_entry=False
-184else:
-185do_print_entry=(entry.get_longname().lower()==self.options.iname.lower())
-186
-187ifdo_print_entry:
-188# Actions on matches
-189ifself.options.download:
-190ifentry.is_directory():
-191self.smbSession.get_file_recursively(path=(path+entry.get_longname()+ntpath.sep))
-192else:
-193self.smbSession.get_file(path=(path+entry.get_longname()+ntpath.sep),keepRemotePath=True)
-194# Output formats
-195ifself.options.ls:
-196ifentry.is_directory():
-197windows_ls_entry(entry,(path+entry.get_longname()+ntpath.sep))
-198else:
-199windows_ls_entry(entry,(path+entry.get_longname()))
-200else:
-201ifentry.is_directory():
-202print("%s"%(path+entry.get_longname()+ntpath.sep))
-203else:
-204print("%s"%(path+entry.get_longname()))
+ 89# Match and print results
+ 90do_print_results=True
+ 91ifself.options.mindepthisnotNone:
+ 92ifdepth<self.options.mindepth:
+ 93do_print_results=False
+ 94ifself.options.maxdepthisnotNone:
+ 95ifdepth>self.options.maxdepth:
+ 96do_print_results=False
+ 97
+ 98ifdo_print_results:
+ 99do_print_entry=False
+100# Print directory
+101ifentry.is_directory():
+102if(self.options.type=='d'orself.options.typeisNone):
+103# No name filtering
+104ifself.options.nameisNoneandself.options.inameisNone:
+105do_print_entry=True
+106
+107# Filtering on names case sensitive
+108elifself.options.nameisnotNone:
+109if'*'inself.options.name:
+110regex=self.options.name
+111regex=regex.replace('.','\\.')
+112regex=regex.replace('*','.*')
+113regex='^'+regex+'$'
+114ifre.match(regex,entry.get_longname()):
+115do_print_entry=True
+116else:
+117do_print_entry=False
+118else:
+119do_print_entry=(entry.get_longname().lower()==self.options.name.lower())
+120
+121# Filtering on names case insensitive
+122elifself.options.inameisnotNone:
+123if'*'inself.options.iname:
+124regex=self.options.iname
+125regex=regex.replace('.','\\.')
+126regex=regex.replace('*','.*')
+127regex='^'+regex+'$'
+128ifre.match(regex,entry.get_longname(),re.IGNORECASE):
+129do_print_entry=True
+130else:
+131do_print_entry=False
+132else:
+133do_print_entry=(entry.get_longname().lower()==self.options.iname.lower())
+134
+135# Print file
+136else:
+137if(self.options.type=='f'orself.options.typeisNone):
+138# No name filtering
+139ifself.options.nameisNoneandself.options.inameisNone:
+140do_print_entry=True
+141
+142# Filtering on names case sensitive
+143elifself.options.nameisnotNone:
+144if'*'inself.options.name:
+145regex=self.options.name
+146regex=regex.replace('.','\\.')
+147regex=regex.replace('*','.*')
+148regex='^'+regex+'$'
+149ifre.match(regex,entry.get_longname()):
+150do_print_entry=True
+151else:
+152do_print_entry=False
+153else:
+154do_print_entry=(entry.get_longname().lower()==self.options.name.lower())
+155
+156# Filtering on names case insensitive
+157elifself.options.inameisnotNone:
+158if'*'inself.options.iname:
+159regex=self.options.iname
+160regex=regex.replace('.','\\.')
+161regex=regex.replace('*','.*')
+162regex='^'+regex+'$'
+163ifre.match(regex,entry.get_longname(),re.IGNORECASE):
+164do_print_entry=True
+165else:
+166do_print_entry=False
+167else:
+168do_print_entry=(entry.get_longname().lower()==self.options.iname.lower())
+169
+170ifdo_print_entry:
+171# Actions on matches
+172ifself.options.download:
+173ifentry.is_directory():
+174self.smbSession.get_file_recursively(path=fullpath)
+175else:
+176self.smbSession.get_file(path=fullpath,keepRemotePath=True)
+177# Output formats
+178ifself.options.ls:
+179ifentry.is_directory():
+180windows_ls_entry(entry,fullpath)
+181else:
+182windows_ls_entry(entry,fullpath)
+183else:
+184ifentry.is_directory():
+185print("%s"%fullpath)
+186else:
+187print("%s"%fullpath)
+188
+189returnNone
+190
+191defrun(self,arguments):
+192"""
+193 This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
+194
+195 Args:
+196 base_dir (str): The base directory to start the search from.
+197 paths (list): List of paths to search within the base directory.
+198 depth (int): The current depth level in the directory hierarchy.
+199
+200 Returns:
+201 None
+202 """
+203
+204self.options=self.parseArgs(arguments=arguments)205
-206# Next directories to explore
-207forentryinentries:
-208ifentry.is_directory():
-209next_directories_to_explore.append(path+entry.get_longname()+ntpath.sep)
-210
-211returnnext_directories_to_explore
-212
-213defrun(self,arguments):
-214"""
-215 This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
-216
-217 Args:
-218 base_dir (str): The base directory to start the search from.
-219 paths (list): List of paths to search within the base directory.
-220 depth (int): The current depth level in the directory hierarchy.
-221
-222 Returns:
-223 None
-224 """
-225
-226self.options=self.parseArgs(arguments=arguments)
-227
-228ifself.optionsisnotNone:
-229# Entrypoint
-230try:
-231next_directories_to_explore=[]
-232forpathinlist(set(self.options.paths)):
-233next_directories_to_explore.append(ntpath.normpath(path)+ntpath.sep)
-234next_directories_to_explore=sorted(list(set(next_directories_to_explore)))
-235
-236depth=0
-237
-238whilelen(next_directories_to_explore)!=0:
-239next_directories_to_explore=self.__recurse_action(
-240paths=next_directories_to_explore,
-241depth=depth
-242)
-243depth=depth+1
-244
-245except(BrokenPipeError,KeyboardInterrupt)ase:
-246print("[!] Interrupted.")
-247self.smbSession.close_smb_session()
-248self.smbSession.init_smb_session()
+206ifself.optionsisnotNone:
+207# Entrypoint
+208try:
+209next_directories_to_explore=[]
+210forpathinlist(set(self.options.paths)):
+211next_directories_to_explore.append(ntpath.normpath(path)+ntpath.sep)
+212next_directories_to_explore=sorted(list(set(next_directories_to_explore)))
+213
+214self.smbSession.find(
+215paths=next_directories_to_explore,
+216callback=self.__find_callback
+217)
+218
+219except(BrokenPipeError,KeyboardInterrupt)ase:
+220print("[!] Interrupted.")
+221self.smbSession.close_smb_session()
+222self.smbSession.init_smb_session()
@@ -360,7 +334,7 @@
42# Adding positional arguments 43parser.add_argument("paths",metavar="PATH",type=str,nargs="*",default=[],help="The starting point(s) for the search.") 44
- 45# Adding tests, actions, and options for expressions (incomplete for brevity)
+ 45# Adding options for filtering 46parser.add_argument("-name",type=str,help="Base of file name (the path with the leading directories removed).") 47parser.add_argument("-iname",type=str,help="Like -name, but the match is case insensitive.") 48parser.add_argument("-type",type=str,default=None,help="File type (e.g., f for regular file, d for directory).")
@@ -373,7 +347,7 @@
55parser.add_argument("-ls",action="store_true",default=False,help="List current file in ls -dils format on standard output.") 56parser.add_argument("-download",action="store_true",default=False,help="List current file in ls -dils format on standard output.") 57
- 58# Other options (incomplete for brevity)
+ 58# Other options 59parser.add_argument("-maxdepth",type=int,help="Descend at most levels (a non-negative integer) levels of directories below the command line arguments.") 60parser.add_argument("-mindepth",type=int,help="Do not apply any tests or actions at levels less than levels (a non-negative integer).") 61
@@ -390,181 +364,155 @@
72 73returnself.options 74
- 75def__recurse_action(self,paths=[],depth=0):
- 76"""
- 77 Recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
- 78
- 79 Args:
- 80 base_dir (str): The base directory to start the search from.
- 81 paths (list): List of paths to search within the base directory.
- 82 depth (int): The current depth level in the directory hierarchy.
- 83
- 84 Returns:
- 85 None
- 86 """
- 87
- 88next_directories_to_explore=[]
+ 75def__find_callback(self,entry,fullpath,depth):
+ 76# Documentation for __find_callback function
+ 77"""
+ 78 This function serves as a callback for the find operation. It applies filters based on the command line arguments
+ 79 and decides whether to print, download, or list the entry in 'ls -dils' format if it matches the specified filters.
+ 80
+ 81 Args:
+ 82 entry (SMBEntry): The current file or directory entry being processed.
+ 83 fullpath (str): The full path to the entry.
+ 84
+ 85 The function checks against filters such as file name, case sensitivity, file type, and size. If the entry matches
+ 86 the filters, it will perform actions like printing the entry's details, downloading the entry, or listing the entry
+ 87 based on the options provided in the command line arguments.
+ 88 """ 89
- 90forpathinpaths:
- 91remote_smb_path=ntpath.normpath(self.smbSession.smb_cwd+ntpath.sep+path)
- 92
- 93entries=[]
- 94try:
- 95entries=self.smbSession.smbClient.listPath(
- 96shareName=self.smbSession.smb_share,
- 97path=(remote_smb_path+ntpath.sep+'*')
- 98)
- 99exceptimpacket.smbconnection.SessionErroraserr:
-100continue
-101# Remove dot names
-102entries=[eforeinentriesife.get_longname()notin[".",".."]]
-103# Sort the entries ignoring case
-104entries=sorted(entries,key=lambdax:x.get_longname().lower())
-105
-106# Match and print results
-107do_print_results=True
-108ifself.options.mindepthisnotNone:
-109ifdepth<self.options.mindepth:
-110do_print_results=False
-111ifself.options.maxdepthisnotNone:
-112ifdepth>self.options.maxdepth:
-113do_print_results=False
-114
-115ifdo_print_results:
-116forentryinentries:
-117do_print_entry=False
-118# Print directory
-119ifentry.is_directory():
-120if(self.options.type=='d'orself.options.typeisNone):
-121# No name filtering
-122ifself.options.nameisNoneandself.options.inameisNone:
-123do_print_entry=True
-124
-125# Filtering on names case sensitive
-126elifself.options.nameisnotNone:
-127if'*'inself.options.name:
-128regex=self.options.name
-129regex=regex.replace('.','\\.')
-130regex=regex.replace('*','.*')
-131regex='^'+regex+'$'
-132ifre.match(regex,entry.get_longname()):
-133do_print_entry=True
-134else:
-135do_print_entry=False
-136else:
-137do_print_entry=(entry.get_longname().lower()==self.options.name.lower())
-138
-139# Filtering on names case insensitive
-140elifself.options.inameisnotNone:
-141if'*'inself.options.iname:
-142regex=self.options.iname
-143regex=regex.replace('.','\\.')
-144regex=regex.replace('*','.*')
-145regex='^'+regex+'$'
-146ifre.match(regex,entry.get_longname(),re.IGNORECASE):
-147do_print_entry=True
-148else:
-149do_print_entry=False
-150else:
-151do_print_entry=(entry.get_longname().lower()==self.options.iname.lower())
-152
-153# Print file
-154else:
-155if(self.options.type=='f'orself.options.typeisNone):
-156# No name filtering
-157ifself.options.nameisNoneandself.options.inameisNone:
-158do_print_entry=True
-159
-160# Filtering on names case sensitive
-161elifself.options.nameisnotNone:
-162if'*'inself.options.name:
-163regex=self.options.name
-164regex=regex.replace('.','\\.')
-165regex=regex.replace('*','.*')
-166regex='^'+regex+'$'
-167ifre.match(regex,entry.get_longname()):
-168do_print_entry=True
-169else:
-170do_print_entry=False
-171else:
-172do_print_entry=(entry.get_longname().lower()==self.options.name.lower())
-173
-174# Filtering on names case insensitive
-175elifself.options.inameisnotNone:
-176if'*'inself.options.iname:
-177regex=self.options.iname
-178regex=regex.replace('.','\\.')
-179regex=regex.replace('*','.*')
-180regex='^'+regex+'$'
-181ifre.match(regex,entry.get_longname(),re.IGNORECASE):
-182do_print_entry=True
-183else:
-184do_print_entry=False
-185else:
-186do_print_entry=(entry.get_longname().lower()==self.options.iname.lower())
-187
-188ifdo_print_entry:
-189# Actions on matches
-190ifself.options.download:
-191ifentry.is_directory():
-192self.smbSession.get_file_recursively(path=(path+entry.get_longname()+ntpath.sep))
-193else:
-194self.smbSession.get_file(path=(path+entry.get_longname()+ntpath.sep),keepRemotePath=True)
-195# Output formats
-196ifself.options.ls:
-197ifentry.is_directory():
-198windows_ls_entry(entry,(path+entry.get_longname()+ntpath.sep))
-199else:
-200windows_ls_entry(entry,(path+entry.get_longname()))
-201else:
-202ifentry.is_directory():
-203print("%s"%(path+entry.get_longname()+ntpath.sep))
-204else:
-205print("%s"%(path+entry.get_longname()))
+ 90# Match and print results
+ 91do_print_results=True
+ 92ifself.options.mindepthisnotNone:
+ 93ifdepth<self.options.mindepth:
+ 94do_print_results=False
+ 95ifself.options.maxdepthisnotNone:
+ 96ifdepth>self.options.maxdepth:
+ 97do_print_results=False
+ 98
+ 99ifdo_print_results:
+100do_print_entry=False
+101# Print directory
+102ifentry.is_directory():
+103if(self.options.type=='d'orself.options.typeisNone):
+104# No name filtering
+105ifself.options.nameisNoneandself.options.inameisNone:
+106do_print_entry=True
+107
+108# Filtering on names case sensitive
+109elifself.options.nameisnotNone:
+110if'*'inself.options.name:
+111regex=self.options.name
+112regex=regex.replace('.','\\.')
+113regex=regex.replace('*','.*')
+114regex='^'+regex+'$'
+115ifre.match(regex,entry.get_longname()):
+116do_print_entry=True
+117else:
+118do_print_entry=False
+119else:
+120do_print_entry=(entry.get_longname().lower()==self.options.name.lower())
+121
+122# Filtering on names case insensitive
+123elifself.options.inameisnotNone:
+124if'*'inself.options.iname:
+125regex=self.options.iname
+126regex=regex.replace('.','\\.')
+127regex=regex.replace('*','.*')
+128regex='^'+regex+'$'
+129ifre.match(regex,entry.get_longname(),re.IGNORECASE):
+130do_print_entry=True
+131else:
+132do_print_entry=False
+133else:
+134do_print_entry=(entry.get_longname().lower()==self.options.iname.lower())
+135
+136# Print file
+137else:
+138if(self.options.type=='f'orself.options.typeisNone):
+139# No name filtering
+140ifself.options.nameisNoneandself.options.inameisNone:
+141do_print_entry=True
+142
+143# Filtering on names case sensitive
+144elifself.options.nameisnotNone:
+145if'*'inself.options.name:
+146regex=self.options.name
+147regex=regex.replace('.','\\.')
+148regex=regex.replace('*','.*')
+149regex='^'+regex+'$'
+150ifre.match(regex,entry.get_longname()):
+151do_print_entry=True
+152else:
+153do_print_entry=False
+154else:
+155do_print_entry=(entry.get_longname().lower()==self.options.name.lower())
+156
+157# Filtering on names case insensitive
+158elifself.options.inameisnotNone:
+159if'*'inself.options.iname:
+160regex=self.options.iname
+161regex=regex.replace('.','\\.')
+162regex=regex.replace('*','.*')
+163regex='^'+regex+'$'
+164ifre.match(regex,entry.get_longname(),re.IGNORECASE):
+165do_print_entry=True
+166else:
+167do_print_entry=False
+168else:
+169do_print_entry=(entry.get_longname().lower()==self.options.iname.lower())
+170
+171ifdo_print_entry:
+172# Actions on matches
+173ifself.options.download:
+174ifentry.is_directory():
+175self.smbSession.get_file_recursively(path=fullpath)
+176else:
+177self.smbSession.get_file(path=fullpath,keepRemotePath=True)
+178# Output formats
+179ifself.options.ls:
+180ifentry.is_directory():
+181windows_ls_entry(entry,fullpath)
+182else:
+183windows_ls_entry(entry,fullpath)
+184else:
+185ifentry.is_directory():
+186print("%s"%fullpath)
+187else:
+188print("%s"%fullpath)
+189
+190returnNone
+191
+192defrun(self,arguments):
+193"""
+194 This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
+195
+196 Args:
+197 base_dir (str): The base directory to start the search from.
+198 paths (list): List of paths to search within the base directory.
+199 depth (int): The current depth level in the directory hierarchy.
+200
+201 Returns:
+202 None
+203 """
+204
+205self.options=self.parseArgs(arguments=arguments)206
-207# Next directories to explore
-208forentryinentries:
-209ifentry.is_directory():
-210next_directories_to_explore.append(path+entry.get_longname()+ntpath.sep)
-211
-212returnnext_directories_to_explore
-213
-214defrun(self,arguments):
-215"""
-216 This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
-217
-218 Args:
-219 base_dir (str): The base directory to start the search from.
-220 paths (list): List of paths to search within the base directory.
-221 depth (int): The current depth level in the directory hierarchy.
-222
-223 Returns:
-224 None
-225 """
-226
-227self.options=self.parseArgs(arguments=arguments)
-228
-229ifself.optionsisnotNone:
-230# Entrypoint
-231try:
-232next_directories_to_explore=[]
-233forpathinlist(set(self.options.paths)):
-234next_directories_to_explore.append(ntpath.normpath(path)+ntpath.sep)
-235next_directories_to_explore=sorted(list(set(next_directories_to_explore)))
-236
-237depth=0
-238
-239whilelen(next_directories_to_explore)!=0:
-240next_directories_to_explore=self.__recurse_action(
-241paths=next_directories_to_explore,
-242depth=depth
-243)
-244depth=depth+1
-245
-246except(BrokenPipeError,KeyboardInterrupt)ase:
-247print("[!] Interrupted.")
-248self.smbSession.close_smb_session()
-249self.smbSession.init_smb_session()
+207ifself.optionsisnotNone:
+208# Entrypoint
+209try:
+210next_directories_to_explore=[]
+211forpathinlist(set(self.options.paths)):
+212next_directories_to_explore.append(ntpath.normpath(path)+ntpath.sep)
+213next_directories_to_explore=sorted(list(set(next_directories_to_explore)))
+214
+215self.smbSession.find(
+216paths=next_directories_to_explore,
+217callback=self.__find_callback
+218)
+219
+220except(BrokenPipeError,KeyboardInterrupt)ase:
+221print("[!] Interrupted.")
+222self.smbSession.close_smb_session()
+223self.smbSession.init_smb_session()
@@ -627,7 +575,7 @@
42# Adding positional arguments43parser.add_argument("paths",metavar="PATH",type=str,nargs="*",default=[],help="The starting point(s) for the search.")44
-45# Adding tests, actions, and options for expressions (incomplete for brevity)
+45# Adding options for filtering46parser.add_argument("-name",type=str,help="Base of file name (the path with the leading directories removed).")47parser.add_argument("-iname",type=str,help="Like -name, but the match is case insensitive.")48parser.add_argument("-type",type=str,default=None,help="File type (e.g., f for regular file, d for directory).")
@@ -640,7 +588,7 @@
55parser.add_argument("-ls",action="store_true",default=False,help="List current file in ls -dils format on standard output.")56parser.add_argument("-download",action="store_true",default=False,help="List current file in ls -dils format on standard output.")57
-58# Other options (incomplete for brevity)
+58# Other options59parser.add_argument("-maxdepth",type=int,help="Descend at most levels (a non-negative integer) levels of directories below the command line arguments.")60parser.add_argument("-mindepth",type=int,help="Do not apply any tests or actions at levels less than levels (a non-negative integer).")61
@@ -683,42 +631,38 @@
-
214defrun(self,arguments):
-215"""
-216 This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
-217
-218 Args:
-219 base_dir (str): The base directory to start the search from.
-220 paths (list): List of paths to search within the base directory.
-221 depth (int): The current depth level in the directory hierarchy.
-222
-223 Returns:
-224 None
-225 """
-226
-227self.options=self.parseArgs(arguments=arguments)
-228
-229ifself.optionsisnotNone:
-230# Entrypoint
-231try:
-232next_directories_to_explore=[]
-233forpathinlist(set(self.options.paths)):
-234next_directories_to_explore.append(ntpath.normpath(path)+ntpath.sep)
-235next_directories_to_explore=sorted(list(set(next_directories_to_explore)))
-236
-237depth=0
-238
-239whilelen(next_directories_to_explore)!=0:
-240next_directories_to_explore=self.__recurse_action(
-241paths=next_directories_to_explore,
-242depth=depth
-243)
-244depth=depth+1
-245
-246except(BrokenPipeError,KeyboardInterrupt)ase:
-247print("[!] Interrupted.")
-248self.smbSession.close_smb_session()
-249self.smbSession.init_smb_session()
+
192defrun(self,arguments):
+193"""
+194 This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
+195
+196 Args:
+197 base_dir (str): The base directory to start the search from.
+198 paths (list): List of paths to search within the base directory.
+199 depth (int): The current depth level in the directory hierarchy.
+200
+201 Returns:
+202 None
+203 """
+204
+205self.options=self.parseArgs(arguments=arguments)
+206
+207ifself.optionsisnotNone:
+208# Entrypoint
+209try:
+210next_directories_to_explore=[]
+211forpathinlist(set(self.options.paths)):
+212next_directories_to_explore.append(ntpath.normpath(path)+ntpath.sep)
+213next_directories_to_explore=sorted(list(set(next_directories_to_explore)))
+214
+215self.smbSession.find(
+216paths=next_directories_to_explore,
+217callback=self.__find_callback
+218)
+219
+220except(BrokenPipeError,KeyboardInterrupt)ase:
+221print("[!] Interrupted.")
+222self.smbSession.close_smb_session()
+223self.smbSession.init_smb_session()
1#!/usr/bin/env python3
+ 2# -*- coding: utf-8 -*-
+ 3# File name : GPPPasswords.py
+ 4# Author : Podalirius (@podalirius_)
+ 5# Date created : 02 june 2024
+ 6
+ 7
+ 8importbase64
+ 9importcharset_normalizer
+ 10fromCryptodome.CipherimportAES
+ 11fromCryptodome.Util.Paddingimportunpad
+ 12importimpacket
+ 13importio
+ 14importntpath
+ 15importre
+ 16fromsmbclientng.core.ModuleimportModule
+ 17fromsmbclientng.core.ModuleArgumentParserimportModuleArgumentParser
+ 18fromsmbclientng.core.utilsimportwindows_ls_entry
+ 19importxml
+ 20fromxml.domimportminidom
+ 21
+ 22
+ 23classGPPPasswords(Module):
+ 24"""
+ 25 GPPPasswords is a module designed to search and retrieve stored Group Policy Preferences (GPP) passwords from specified network shares.
+ 26 It leverages the SMB protocol to access files across the network, parse them, and extract credentials that are often stored within Group Policy Preferences files.
+ 27
+ 28 This module is particularly useful in penetration testing scenarios where discovering stored credentials can lead to further system access or reveal poor security practices.
+ 29
+ 30 Attributes:
+ 31 name (str): The name of the module, used in command line invocation.
+ 32 description (str): A brief description of what the module does.
+ 33
+ 34 Methods:
+ 35 parseArgs(arguments): Parses and handles command line arguments for the module.
+ 36 parse_xmlfile_content(pathtofile): Parses the content of an XML file to extract credentials.
+ 37 """
+ 38
+ 39name="gpppasswords"
+ 40description="Searches for Group Policy Preferences Passwords in a share."
+ 41
+ 42defparseArgs(self,arguments):
+ 43"""
+ 44 Parses the command line arguments provided to the module.
+ 45
+ 46 This method initializes the argument parser with the module's name and description, and defines all the necessary arguments that the module accepts. It then parses the provided command line arguments based on these definitions.
+ 47
+ 48 Args:
+ 49 arguments (str): A string of command line arguments.
+ 50
+ 51 Returns:
+ 52 ModuleArgumentParser.Namespace | None: The parsed arguments as a Namespace object if successful, None if there are no arguments or help is requested.
+ 53 """
+ 54
+ 55parser=ModuleArgumentParser(prog=self.name,description=self.description)
+ 56
+ 57# Adding positional arguments
+ 58parser.add_argument("paths",metavar="PATH",type=str,nargs="*",default=[],help="The starting point(s) for the search.")
+ 59
+ 60# Adding actions
+ 61parser.add_argument("-ls",action="store_true",default=False,help="List current file in ls -dils format on standard output.")
+ 62parser.add_argument("-download",action="store_true",default=False,help="List current file in ls -dils format on standard output.")
+ 63
+ 64# Other options
+ 65parser.add_argument("-maxdepth",type=int,help="Descend at most levels (a non-negative integer) levels of directories below the command line arguments.")
+ 66parser.add_argument("-mindepth",type=int,help="Do not apply any tests or actions at levels less than levels (a non-negative integer).")
+ 67
+ 68iflen(arguments.strip())==0:
+ 69parser.print_help()
+ 70returnNone
+ 71else:
+ 72self.options=self.processArguments(parser,arguments)
+ 73
+ 74returnself.options
+ 75
+ 76defparse_xmlfile_content(self,pathtofile):
+ 77"""
+ 78 Parses the content of an XML file to extract credentials related to Group Policy Preferences.
+ 79
+ 80 This method attempts to retrieve and parse the content of the specified XML file from the SMB share. It looks for credentials stored within the XML structure, specifically targeting the 'cpassword' attribute which is commonly used for storing encrypted passwords in Group Policy Preferences files.
+ 81
+ 82 Args:
+ 83 pathtofile (str): The path to the XML file on the SMB share.
+ 84
+ 85 Returns:
+ 86 list: A list of dictionaries, each containing details about found credentials such as username, encrypted and decrypted passwords, and other relevant attributes.
+ 87 """
+ 88
+ 89results=[]
+ 90fh=io.BytesIO()
+ 91try:
+ 92# opening the files in streams instead of mounting shares allows for running the script from
+ 93# unprivileged containers
+ 94self.smbSession.smbClient.getFile(self.smbSession.smb_share,pathtofile,fh.write)
+ 95exceptimpacket.smbconnection.SessionErrorase:
+ 96returnresults
+ 97exceptExceptionase:
+ 98raise
+ 99rawdata=fh.getvalue()
+100fh.close()
+101gppp_found=False
+102encoding=charset_normalizer.detect(rawdata)["encoding"]
+103ifencodingisnotNone:
+104filecontent=rawdata.decode(encoding).rstrip()
+105if"cpassword"infilecontent:
+106gppp_found=True
+107else:
+108ifself.config.debug:
+109print("[debug] No cpassword was found in %s"%pathtofile)
+110
+111ifgppp_found:
+112try:
+113root=minidom.parseString(filecontent)
+114xmltype=root.childNodes[0].tagName
+115# function to get attribute if it exists, returns "" if empty
+116read_or_empty=lambdaelement,attribute:(element.getAttribute(attribute)ifelement.getAttribute(attribute)isnotNoneelse"")
+117
+118# ScheduledTasks
+119ifxmltype=="ScheduledTasks":
+120fortopnodeinroot.childNodes:
+121task_nodes=[cforcintopnode.childNodesifisinstance(c,xml.dom.minidom.Element)]
+122fortaskintask_nodes:
+123forpropertyintask.getElementsByTagName("Properties"):
+124results.append({
+125"tagName":xmltype,
+126"attributes":{
+127"username":read_or_empty(task,"name"),
+128"runAs":read_or_empty(property,"runAs"),
+129"cpassword":read_or_empty(property,"cpassword"),
+130"password":self.decrypt_password(read_or_empty(property,"cpassword")),
+131"changed":read_or_empty(property.parentNode,"changed"),
+132},
+133"file":pathtofile
+134})
+135elifxmltype=="Groups":
+136fortopnodeinroot.childNodes:
+137task_nodes=[cforcintopnode.childNodesifisinstance(c,xml.dom.minidom.Element)]
+138fortaskintask_nodes:
+139forpropertyintask.getElementsByTagName("Properties"):
+140results.append({
+141"tagName":xmltype,
+142"attributes":{
+143"username":read_or_empty(property,"newName"),
+144# "userName": read_or_empty(property, "userName"),
+145"cpassword":read_or_empty(property,"cpassword"),
+146"password":self.decrypt_password(read_or_empty(property,"cpassword")),
+147"changed":read_or_empty(property.parentNode,"changed"),
+148},
+149"file":pathtofile
+150})
+151else:
+152fortopnodeinroot.childNodes:
+153task_nodes=[cforcintopnode.childNodesifisinstance(c,xml.dom.minidom.Element)]
+154fortaskintask_nodes:
+155forpropertyintask.getElementsByTagName("Properties"):
+156results.append({
+157"tagName":xmltype,
+158"attributes":{
+159"username":read_or_empty(property,"newName"),
+160# "userName": read_or_empty(property, "userName"),
+161"cpassword":read_or_empty(property,"cpassword"),
+162"password":self.decrypt_password(read_or_empty(property,"cpassword")),
+163"changed":read_or_empty(property.parentNode,"changed"),
+164},
+165"file":pathtofile
+166})
+167
+168exceptExceptionase:
+169raise
+170
+171returnresults
+172
+173defdecrypt_password(self,pw_enc_b64):
+174"""
+175 Decrypts a password from its Base64 encoded form using a known AES key and IV.
+176
+177 This method takes a Base64 encoded string which is encrypted using AES-CBC with a fixed key and IV as per Microsoft's published details. It decodes the Base64 string, decrypts it using the AES key and IV, and returns the plaintext password.
+178
+179 Args:
+180 pw_enc_b64 (str): The Base64 encoded string of the encrypted password.
+181
+182 Returns:
+183 str: The decrypted password in plaintext, or an empty string if input is empty or decryption fails.
+184 """
+185
+186iflen(pw_enc_b64)!=0:
+187# Thank you Microsoft for publishing the key :)
+188# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gppref/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be
+189key=b"\x4e\x99\x06\xe8\xfc\xb6\x6c\xc9\xfa\xf4\x93\x10\x62\x0f\xfe\xe8\xf4\x96\xe8\x06\xcc\x05\x79\x90\x20\x9b\x09\xa4\x33\xb6\x6c\x1b"
+190# Thank you Microsoft for using a fixed IV :)
+191iv=b"\x00"*16
+192pad=len(pw_enc_b64)%4
+193ifpad==1:
+194pw_enc_b64=pw_enc_b64[:-1]
+195elifpad==2orpad==3:
+196pw_enc_b64+="="*(4-pad)
+197pw_enc=base64.b64decode(pw_enc_b64)
+198ctx=AES.new(key,AES.MODE_CBC,iv)
+199pw_dec=unpad(ctx.decrypt(pw_enc),ctx.block_size)
+200returnpw_dec.decode("utf-16-le")
+201else:
+202# cpassword is empty, cannot decrypt anything.
+203return""
+204
+205def__find_callback(self,entry,fullpath,depth):
+206"""
+207 Callback function for SMB session find method. This function is called for each entry found in the search.
+208
+209 This function checks if the entry is a file with an '.xml' extension. If it is, it parses the XML content to extract relevant data such as usernames and passwords. It then prints the file path and the extracted data if the current depth is within the specified minimum and maximum depth range.
+210
+211 Args:
+212 entry (SMBEntry): The current file or directory entry being processed.
+213 fullpath (str): The full path to the current entry.
+214 depth (int): Depth of the path.
+215
+216 Returns:
+217 None: This function does not return any value.
+218 """
+219
+220# Match and print results
+221do_print_results=True
+222ifself.options.mindepthisnotNone:
+223ifdepth<self.options.mindepth:
+224do_print_results=False
+225ifself.options.maxdepthisnotNone:
+226ifdepth>self.options.maxdepth:
+227do_print_results=False
+228
+229ifdo_print_results:
+230if(notentry.is_directory())and(entry.get_longname().lower().endswith('.xml')):
+231data=self.parse_xmlfile_content(fullpath)
+232ifdataisnotNone:
+233iflen(data)!=0:
+234print("[+] %s"%fullpath)
+235forentryindata:
+236ifself.config.no_colors:
+237print(" | username: '%s'"%entry["attributes"]["username"])
+238print(" | password: '%s'"%entry["attributes"]["password"])
+239else:
+240print(" | \x1b[94musername\x1b[0m: '\x1b[93m%s\x1b[0m'"%entry["attributes"]["username"])
+241print(" | \x1b[94mpassword\x1b[0m: '\x1b[93m%s\x1b[0m'"%entry["attributes"]["password"])
+242iflen(data)>1:
+243print("|")
+244returnNone
+245
+246defrun(self,arguments):
+247"""
+248 This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
+249
+250 Args:
+251 base_dir (str): The base directory to start the search from.
+252 paths (list): List of paths to search within the base directory.
+253 depth (int): The current depth level in the directory hierarchy.
+254
+255 Returns:
+256 None
+257 """
+258
+259self.options=self.parseArgs(arguments=arguments)
+260
+261ifself.optionsisnotNone:
+262# Entrypoint
+263try:
+264next_directories_to_explore=[]
+265forpathinlist(set(self.options.paths)):
+266next_directories_to_explore.append(ntpath.normpath(path)+ntpath.sep)
+267next_directories_to_explore=sorted(list(set(next_directories_to_explore)))
+268
+269self.smbSession.find(
+270paths=next_directories_to_explore,
+271callback=self.__find_callback
+272)
+273
+274except(BrokenPipeError,KeyboardInterrupt)ase:
+275print("[!] Interrupted.")
+276self.smbSession.close_smb_session()
+277self.smbSession.init_smb_session()
+
24classGPPPasswords(Module):
+ 25"""
+ 26 GPPPasswords is a module designed to search and retrieve stored Group Policy Preferences (GPP) passwords from specified network shares.
+ 27 It leverages the SMB protocol to access files across the network, parse them, and extract credentials that are often stored within Group Policy Preferences files.
+ 28
+ 29 This module is particularly useful in penetration testing scenarios where discovering stored credentials can lead to further system access or reveal poor security practices.
+ 30
+ 31 Attributes:
+ 32 name (str): The name of the module, used in command line invocation.
+ 33 description (str): A brief description of what the module does.
+ 34
+ 35 Methods:
+ 36 parseArgs(arguments): Parses and handles command line arguments for the module.
+ 37 parse_xmlfile_content(pathtofile): Parses the content of an XML file to extract credentials.
+ 38 """
+ 39
+ 40name="gpppasswords"
+ 41description="Searches for Group Policy Preferences Passwords in a share."
+ 42
+ 43defparseArgs(self,arguments):
+ 44"""
+ 45 Parses the command line arguments provided to the module.
+ 46
+ 47 This method initializes the argument parser with the module's name and description, and defines all the necessary arguments that the module accepts. It then parses the provided command line arguments based on these definitions.
+ 48
+ 49 Args:
+ 50 arguments (str): A string of command line arguments.
+ 51
+ 52 Returns:
+ 53 ModuleArgumentParser.Namespace | None: The parsed arguments as a Namespace object if successful, None if there are no arguments or help is requested.
+ 54 """
+ 55
+ 56parser=ModuleArgumentParser(prog=self.name,description=self.description)
+ 57
+ 58# Adding positional arguments
+ 59parser.add_argument("paths",metavar="PATH",type=str,nargs="*",default=[],help="The starting point(s) for the search.")
+ 60
+ 61# Adding actions
+ 62parser.add_argument("-ls",action="store_true",default=False,help="List current file in ls -dils format on standard output.")
+ 63parser.add_argument("-download",action="store_true",default=False,help="List current file in ls -dils format on standard output.")
+ 64
+ 65# Other options
+ 66parser.add_argument("-maxdepth",type=int,help="Descend at most levels (a non-negative integer) levels of directories below the command line arguments.")
+ 67parser.add_argument("-mindepth",type=int,help="Do not apply any tests or actions at levels less than levels (a non-negative integer).")
+ 68
+ 69iflen(arguments.strip())==0:
+ 70parser.print_help()
+ 71returnNone
+ 72else:
+ 73self.options=self.processArguments(parser,arguments)
+ 74
+ 75returnself.options
+ 76
+ 77defparse_xmlfile_content(self,pathtofile):
+ 78"""
+ 79 Parses the content of an XML file to extract credentials related to Group Policy Preferences.
+ 80
+ 81 This method attempts to retrieve and parse the content of the specified XML file from the SMB share. It looks for credentials stored within the XML structure, specifically targeting the 'cpassword' attribute which is commonly used for storing encrypted passwords in Group Policy Preferences files.
+ 82
+ 83 Args:
+ 84 pathtofile (str): The path to the XML file on the SMB share.
+ 85
+ 86 Returns:
+ 87 list: A list of dictionaries, each containing details about found credentials such as username, encrypted and decrypted passwords, and other relevant attributes.
+ 88 """
+ 89
+ 90results=[]
+ 91fh=io.BytesIO()
+ 92try:
+ 93# opening the files in streams instead of mounting shares allows for running the script from
+ 94# unprivileged containers
+ 95self.smbSession.smbClient.getFile(self.smbSession.smb_share,pathtofile,fh.write)
+ 96exceptimpacket.smbconnection.SessionErrorase:
+ 97returnresults
+ 98exceptExceptionase:
+ 99raise
+100rawdata=fh.getvalue()
+101fh.close()
+102gppp_found=False
+103encoding=charset_normalizer.detect(rawdata)["encoding"]
+104ifencodingisnotNone:
+105filecontent=rawdata.decode(encoding).rstrip()
+106if"cpassword"infilecontent:
+107gppp_found=True
+108else:
+109ifself.config.debug:
+110print("[debug] No cpassword was found in %s"%pathtofile)
+111
+112ifgppp_found:
+113try:
+114root=minidom.parseString(filecontent)
+115xmltype=root.childNodes[0].tagName
+116# function to get attribute if it exists, returns "" if empty
+117read_or_empty=lambdaelement,attribute:(element.getAttribute(attribute)ifelement.getAttribute(attribute)isnotNoneelse"")
+118
+119# ScheduledTasks
+120ifxmltype=="ScheduledTasks":
+121fortopnodeinroot.childNodes:
+122task_nodes=[cforcintopnode.childNodesifisinstance(c,xml.dom.minidom.Element)]
+123fortaskintask_nodes:
+124forpropertyintask.getElementsByTagName("Properties"):
+125results.append({
+126"tagName":xmltype,
+127"attributes":{
+128"username":read_or_empty(task,"name"),
+129"runAs":read_or_empty(property,"runAs"),
+130"cpassword":read_or_empty(property,"cpassword"),
+131"password":self.decrypt_password(read_or_empty(property,"cpassword")),
+132"changed":read_or_empty(property.parentNode,"changed"),
+133},
+134"file":pathtofile
+135})
+136elifxmltype=="Groups":
+137fortopnodeinroot.childNodes:
+138task_nodes=[cforcintopnode.childNodesifisinstance(c,xml.dom.minidom.Element)]
+139fortaskintask_nodes:
+140forpropertyintask.getElementsByTagName("Properties"):
+141results.append({
+142"tagName":xmltype,
+143"attributes":{
+144"username":read_or_empty(property,"newName"),
+145# "userName": read_or_empty(property, "userName"),
+146"cpassword":read_or_empty(property,"cpassword"),
+147"password":self.decrypt_password(read_or_empty(property,"cpassword")),
+148"changed":read_or_empty(property.parentNode,"changed"),
+149},
+150"file":pathtofile
+151})
+152else:
+153fortopnodeinroot.childNodes:
+154task_nodes=[cforcintopnode.childNodesifisinstance(c,xml.dom.minidom.Element)]
+155fortaskintask_nodes:
+156forpropertyintask.getElementsByTagName("Properties"):
+157results.append({
+158"tagName":xmltype,
+159"attributes":{
+160"username":read_or_empty(property,"newName"),
+161# "userName": read_or_empty(property, "userName"),
+162"cpassword":read_or_empty(property,"cpassword"),
+163"password":self.decrypt_password(read_or_empty(property,"cpassword")),
+164"changed":read_or_empty(property.parentNode,"changed"),
+165},
+166"file":pathtofile
+167})
+168
+169exceptExceptionase:
+170raise
+171
+172returnresults
+173
+174defdecrypt_password(self,pw_enc_b64):
+175"""
+176 Decrypts a password from its Base64 encoded form using a known AES key and IV.
+177
+178 This method takes a Base64 encoded string which is encrypted using AES-CBC with a fixed key and IV as per Microsoft's published details. It decodes the Base64 string, decrypts it using the AES key and IV, and returns the plaintext password.
+179
+180 Args:
+181 pw_enc_b64 (str): The Base64 encoded string of the encrypted password.
+182
+183 Returns:
+184 str: The decrypted password in plaintext, or an empty string if input is empty or decryption fails.
+185 """
+186
+187iflen(pw_enc_b64)!=0:
+188# Thank you Microsoft for publishing the key :)
+189# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gppref/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be
+190key=b"\x4e\x99\x06\xe8\xfc\xb6\x6c\xc9\xfa\xf4\x93\x10\x62\x0f\xfe\xe8\xf4\x96\xe8\x06\xcc\x05\x79\x90\x20\x9b\x09\xa4\x33\xb6\x6c\x1b"
+191# Thank you Microsoft for using a fixed IV :)
+192iv=b"\x00"*16
+193pad=len(pw_enc_b64)%4
+194ifpad==1:
+195pw_enc_b64=pw_enc_b64[:-1]
+196elifpad==2orpad==3:
+197pw_enc_b64+="="*(4-pad)
+198pw_enc=base64.b64decode(pw_enc_b64)
+199ctx=AES.new(key,AES.MODE_CBC,iv)
+200pw_dec=unpad(ctx.decrypt(pw_enc),ctx.block_size)
+201returnpw_dec.decode("utf-16-le")
+202else:
+203# cpassword is empty, cannot decrypt anything.
+204return""
+205
+206def__find_callback(self,entry,fullpath,depth):
+207"""
+208 Callback function for SMB session find method. This function is called for each entry found in the search.
+209
+210 This function checks if the entry is a file with an '.xml' extension. If it is, it parses the XML content to extract relevant data such as usernames and passwords. It then prints the file path and the extracted data if the current depth is within the specified minimum and maximum depth range.
+211
+212 Args:
+213 entry (SMBEntry): The current file or directory entry being processed.
+214 fullpath (str): The full path to the current entry.
+215 depth (int): Depth of the path.
+216
+217 Returns:
+218 None: This function does not return any value.
+219 """
+220
+221# Match and print results
+222do_print_results=True
+223ifself.options.mindepthisnotNone:
+224ifdepth<self.options.mindepth:
+225do_print_results=False
+226ifself.options.maxdepthisnotNone:
+227ifdepth>self.options.maxdepth:
+228do_print_results=False
+229
+230ifdo_print_results:
+231if(notentry.is_directory())and(entry.get_longname().lower().endswith('.xml')):
+232data=self.parse_xmlfile_content(fullpath)
+233ifdataisnotNone:
+234iflen(data)!=0:
+235print("[+] %s"%fullpath)
+236forentryindata:
+237ifself.config.no_colors:
+238print(" | username: '%s'"%entry["attributes"]["username"])
+239print(" | password: '%s'"%entry["attributes"]["password"])
+240else:
+241print(" | \x1b[94musername\x1b[0m: '\x1b[93m%s\x1b[0m'"%entry["attributes"]["username"])
+242print(" | \x1b[94mpassword\x1b[0m: '\x1b[93m%s\x1b[0m'"%entry["attributes"]["password"])
+243iflen(data)>1:
+244print("|")
+245returnNone
+246
+247defrun(self,arguments):
+248"""
+249 This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
+250
+251 Args:
+252 base_dir (str): The base directory to start the search from.
+253 paths (list): List of paths to search within the base directory.
+254 depth (int): The current depth level in the directory hierarchy.
+255
+256 Returns:
+257 None
+258 """
+259
+260self.options=self.parseArgs(arguments=arguments)
+261
+262ifself.optionsisnotNone:
+263# Entrypoint
+264try:
+265next_directories_to_explore=[]
+266forpathinlist(set(self.options.paths)):
+267next_directories_to_explore.append(ntpath.normpath(path)+ntpath.sep)
+268next_directories_to_explore=sorted(list(set(next_directories_to_explore)))
+269
+270self.smbSession.find(
+271paths=next_directories_to_explore,
+272callback=self.__find_callback
+273)
+274
+275except(BrokenPipeError,KeyboardInterrupt)ase:
+276print("[!] Interrupted.")
+277self.smbSession.close_smb_session()
+278self.smbSession.init_smb_session()
+
+
+
+
GPPPasswords is a module designed to search and retrieve stored Group Policy Preferences (GPP) passwords from specified network shares.
+It leverages the SMB protocol to access files across the network, parse them, and extract credentials that are often stored within Group Policy Preferences files.
+
+
This module is particularly useful in penetration testing scenarios where discovering stored credentials can lead to further system access or reveal poor security practices.
+
+
Attributes:
+ name (str): The name of the module, used in command line invocation.
+ description (str): A brief description of what the module does.
+
+
Methods:
+ parseArgs(arguments): Parses and handles command line arguments for the module.
+ parse_xmlfile_content(pathtofile): Parses the content of an XML file to extract credentials.
+
+
+
+
+
+ name =
+'gpppasswords'
+
+
+
+
+
+
+
+
+
+
+ description =
+'Searches for Group Policy Preferences Passwords in a share.'
+
+
+
+
+
+
+
+
+
+
+
+
+ def
+ parseArgs(self, arguments):
+
+
+
+
+
+
43defparseArgs(self,arguments):
+44"""
+45 Parses the command line arguments provided to the module.
+46
+47 This method initializes the argument parser with the module's name and description, and defines all the necessary arguments that the module accepts. It then parses the provided command line arguments based on these definitions.
+48
+49 Args:
+50 arguments (str): A string of command line arguments.
+51
+52 Returns:
+53 ModuleArgumentParser.Namespace | None: The parsed arguments as a Namespace object if successful, None if there are no arguments or help is requested.
+54 """
+55
+56parser=ModuleArgumentParser(prog=self.name,description=self.description)
+57
+58# Adding positional arguments
+59parser.add_argument("paths",metavar="PATH",type=str,nargs="*",default=[],help="The starting point(s) for the search.")
+60
+61# Adding actions
+62parser.add_argument("-ls",action="store_true",default=False,help="List current file in ls -dils format on standard output.")
+63parser.add_argument("-download",action="store_true",default=False,help="List current file in ls -dils format on standard output.")
+64
+65# Other options
+66parser.add_argument("-maxdepth",type=int,help="Descend at most levels (a non-negative integer) levels of directories below the command line arguments.")
+67parser.add_argument("-mindepth",type=int,help="Do not apply any tests or actions at levels less than levels (a non-negative integer).")
+68
+69iflen(arguments.strip())==0:
+70parser.print_help()
+71returnNone
+72else:
+73self.options=self.processArguments(parser,arguments)
+74
+75returnself.options
+
+
+
+
Parses the command line arguments provided to the module.
+
+
This method initializes the argument parser with the module's name and description, and defines all the necessary arguments that the module accepts. It then parses the provided command line arguments based on these definitions.
+
+
Args:
+ arguments (str): A string of command line arguments.
+
+
Returns:
+ ModuleArgumentParser.Namespace | None: The parsed arguments as a Namespace object if successful, None if there are no arguments or help is requested.
77defparse_xmlfile_content(self,pathtofile):
+ 78"""
+ 79 Parses the content of an XML file to extract credentials related to Group Policy Preferences.
+ 80
+ 81 This method attempts to retrieve and parse the content of the specified XML file from the SMB share. It looks for credentials stored within the XML structure, specifically targeting the 'cpassword' attribute which is commonly used for storing encrypted passwords in Group Policy Preferences files.
+ 82
+ 83 Args:
+ 84 pathtofile (str): The path to the XML file on the SMB share.
+ 85
+ 86 Returns:
+ 87 list: A list of dictionaries, each containing details about found credentials such as username, encrypted and decrypted passwords, and other relevant attributes.
+ 88 """
+ 89
+ 90results=[]
+ 91fh=io.BytesIO()
+ 92try:
+ 93# opening the files in streams instead of mounting shares allows for running the script from
+ 94# unprivileged containers
+ 95self.smbSession.smbClient.getFile(self.smbSession.smb_share,pathtofile,fh.write)
+ 96exceptimpacket.smbconnection.SessionErrorase:
+ 97returnresults
+ 98exceptExceptionase:
+ 99raise
+100rawdata=fh.getvalue()
+101fh.close()
+102gppp_found=False
+103encoding=charset_normalizer.detect(rawdata)["encoding"]
+104ifencodingisnotNone:
+105filecontent=rawdata.decode(encoding).rstrip()
+106if"cpassword"infilecontent:
+107gppp_found=True
+108else:
+109ifself.config.debug:
+110print("[debug] No cpassword was found in %s"%pathtofile)
+111
+112ifgppp_found:
+113try:
+114root=minidom.parseString(filecontent)
+115xmltype=root.childNodes[0].tagName
+116# function to get attribute if it exists, returns "" if empty
+117read_or_empty=lambdaelement,attribute:(element.getAttribute(attribute)ifelement.getAttribute(attribute)isnotNoneelse"")
+118
+119# ScheduledTasks
+120ifxmltype=="ScheduledTasks":
+121fortopnodeinroot.childNodes:
+122task_nodes=[cforcintopnode.childNodesifisinstance(c,xml.dom.minidom.Element)]
+123fortaskintask_nodes:
+124forpropertyintask.getElementsByTagName("Properties"):
+125results.append({
+126"tagName":xmltype,
+127"attributes":{
+128"username":read_or_empty(task,"name"),
+129"runAs":read_or_empty(property,"runAs"),
+130"cpassword":read_or_empty(property,"cpassword"),
+131"password":self.decrypt_password(read_or_empty(property,"cpassword")),
+132"changed":read_or_empty(property.parentNode,"changed"),
+133},
+134"file":pathtofile
+135})
+136elifxmltype=="Groups":
+137fortopnodeinroot.childNodes:
+138task_nodes=[cforcintopnode.childNodesifisinstance(c,xml.dom.minidom.Element)]
+139fortaskintask_nodes:
+140forpropertyintask.getElementsByTagName("Properties"):
+141results.append({
+142"tagName":xmltype,
+143"attributes":{
+144"username":read_or_empty(property,"newName"),
+145# "userName": read_or_empty(property, "userName"),
+146"cpassword":read_or_empty(property,"cpassword"),
+147"password":self.decrypt_password(read_or_empty(property,"cpassword")),
+148"changed":read_or_empty(property.parentNode,"changed"),
+149},
+150"file":pathtofile
+151})
+152else:
+153fortopnodeinroot.childNodes:
+154task_nodes=[cforcintopnode.childNodesifisinstance(c,xml.dom.minidom.Element)]
+155fortaskintask_nodes:
+156forpropertyintask.getElementsByTagName("Properties"):
+157results.append({
+158"tagName":xmltype,
+159"attributes":{
+160"username":read_or_empty(property,"newName"),
+161# "userName": read_or_empty(property, "userName"),
+162"cpassword":read_or_empty(property,"cpassword"),
+163"password":self.decrypt_password(read_or_empty(property,"cpassword")),
+164"changed":read_or_empty(property.parentNode,"changed"),
+165},
+166"file":pathtofile
+167})
+168
+169exceptExceptionase:
+170raise
+171
+172returnresults
+
+
+
+
Parses the content of an XML file to extract credentials related to Group Policy Preferences.
+
+
This method attempts to retrieve and parse the content of the specified XML file from the SMB share. It looks for credentials stored within the XML structure, specifically targeting the 'cpassword' attribute which is commonly used for storing encrypted passwords in Group Policy Preferences files.
+
+
Args:
+ pathtofile (str): The path to the XML file on the SMB share.
+
+
Returns:
+ list: A list of dictionaries, each containing details about found credentials such as username, encrypted and decrypted passwords, and other relevant attributes.
174defdecrypt_password(self,pw_enc_b64):
+175"""
+176 Decrypts a password from its Base64 encoded form using a known AES key and IV.
+177
+178 This method takes a Base64 encoded string which is encrypted using AES-CBC with a fixed key and IV as per Microsoft's published details. It decodes the Base64 string, decrypts it using the AES key and IV, and returns the plaintext password.
+179
+180 Args:
+181 pw_enc_b64 (str): The Base64 encoded string of the encrypted password.
+182
+183 Returns:
+184 str: The decrypted password in plaintext, or an empty string if input is empty or decryption fails.
+185 """
+186
+187iflen(pw_enc_b64)!=0:
+188# Thank you Microsoft for publishing the key :)
+189# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gppref/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be
+190key=b"\x4e\x99\x06\xe8\xfc\xb6\x6c\xc9\xfa\xf4\x93\x10\x62\x0f\xfe\xe8\xf4\x96\xe8\x06\xcc\x05\x79\x90\x20\x9b\x09\xa4\x33\xb6\x6c\x1b"
+191# Thank you Microsoft for using a fixed IV :)
+192iv=b"\x00"*16
+193pad=len(pw_enc_b64)%4
+194ifpad==1:
+195pw_enc_b64=pw_enc_b64[:-1]
+196elifpad==2orpad==3:
+197pw_enc_b64+="="*(4-pad)
+198pw_enc=base64.b64decode(pw_enc_b64)
+199ctx=AES.new(key,AES.MODE_CBC,iv)
+200pw_dec=unpad(ctx.decrypt(pw_enc),ctx.block_size)
+201returnpw_dec.decode("utf-16-le")
+202else:
+203# cpassword is empty, cannot decrypt anything.
+204return""
+
+
+
+
Decrypts a password from its Base64 encoded form using a known AES key and IV.
+
+
This method takes a Base64 encoded string which is encrypted using AES-CBC with a fixed key and IV as per Microsoft's published details. It decodes the Base64 string, decrypts it using the AES key and IV, and returns the plaintext password.
+
+
Args:
+ pw_enc_b64 (str): The Base64 encoded string of the encrypted password.
+
+
Returns:
+ str: The decrypted password in plaintext, or an empty string if input is empty or decryption fails.
+
+
+
+
+
+
+
+
+ def
+ run(self, arguments):
+
+
+
+
+
+
247defrun(self,arguments):
+248"""
+249 This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
+250
+251 Args:
+252 base_dir (str): The base directory to start the search from.
+253 paths (list): List of paths to search within the base directory.
+254 depth (int): The current depth level in the directory hierarchy.
+255
+256 Returns:
+257 None
+258 """
+259
+260self.options=self.parseArgs(arguments=arguments)
+261
+262ifself.optionsisnotNone:
+263# Entrypoint
+264try:
+265next_directories_to_explore=[]
+266forpathinlist(set(self.options.paths)):
+267next_directories_to_explore.append(ntpath.normpath(path)+ntpath.sep)
+268next_directories_to_explore=sorted(list(set(next_directories_to_explore)))
+269
+270self.smbSession.find(
+271paths=next_directories_to_explore,
+272callback=self.__find_callback
+273)
+274
+275except(BrokenPipeError,KeyboardInterrupt)ase:
+276print("[!] Interrupted.")
+277self.smbSession.close_smb_session()
+278self.smbSession.init_smb_session()
+
+
+
+
This function recursively searches for files in a directory hierarchy and prints the results based on specified criteria.
+
+
Args:
+ base_dir (str): The base directory to start the search from.
+ paths (list): List of paths to search within the base directory.
+ depth (int): The current depth level in the directory hierarchy.