diff --git a/documentation/search.js b/documentation/search.js index 0037d97..8c80f7e 100644 --- a/documentation/search.js +++ b/documentation/search.js @@ -1,6 +1,6 @@ window.pdocSearch = (function(){ /** elasticlunr - http://weixsong.github.io * Copyright (C) 2017 Oliver Nightingale * Copyright (C) 2017 Wei Song * MIT Licensed */!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o

\n"}, {"fullname": "smbclientng.core", "modulename": "smbclientng.core", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.CommandCompleter", "modulename": "smbclientng.core.CommandCompleter", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter", "kind": "class", "doc": "

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 remote file.', "Syntax: 'bat <file>'"], 'subcommands': []}, 'cat': {'description': ['Get the contents of a remote 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': []}, 'debug': {'description': ['Command for dev debugging.', "Syntax: 'debug'"], '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']}, 'lbat': {'description': ['Pretty prints the contents of a local file.', "Syntax: 'lbat <file>'"], 'subcommands': []}, 'lcat': {'description': ['Print the contents of a local file.', "Syntax: 'lcat <file>'"], 'subcommands': []}, 'lcd': {'description': ['Changes the current local directory.', "Syntax: 'lcd <directory>'"], 'subcommands': []}, 'lcp': {'description': ['Create a copy of a local file.', "Syntax: 'lcp <srcfile> <dstfile>'"], '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': []}, 'lrename': {'description': ['Renames a local file.', "Syntax: 'lrename <oldfilename> <newfilename>'"], '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': []}, 'mount': {'description': ['Creates a mount point of the remote share on the local machine.', "Syntax: 'mount <remote_path> <local_mountpoint>'"], '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': []}, 'sizeof': {'description': ['Recursively compute the size of a folder.', "Syntax: 'sizeof [directory|file]'"], 'subcommands': []}, 'shares': {'description': ['Lists the SMB shares served by the remote machine.', "Syntax: 'shares'"], 'subcommands': []}, 'tree': {'description': ['Displays a tree view of the remote directories.', "Syntax: 'tree [directory]'"], 'subcommands': []}, 'umount': {'description': ['Removes a mount point of the remote share on the local machine.', "Syntax: 'umount <local_mount_point>'"], 'subcommands': []}, 'use': {'description': ['Use a SMB share.', "Syntax: 'use <sharename>'"], '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.

\n", "signature": "(self, text, state):", "funcdef": "def"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.print_help", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.print_help", "kind": "function", "doc": "

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.

\n\n

Returns:\n None

\n", "signature": "(self, command=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.print_help_format", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.print_help_format", "kind": "function", "doc": "

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.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.Config", "modulename": "smbclientng.core.Config", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.Config.Config", "modulename": "smbclientng.core.Config", "qualname": "Config", "kind": "class", "doc": "

Configuration handler for smbclientng.

\n\n

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.

\n"}, {"fullname": "smbclientng.core.Config.Config.__init__", "modulename": "smbclientng.core.Config", "qualname": "Config.__init__", "kind": "function", "doc": "

\n", "signature": "(debug=False, no_colors=None)"}, {"fullname": "smbclientng.core.Config.Config.debug", "modulename": "smbclientng.core.Config", "qualname": "Config.debug", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.Config.Config.no_colors", "modulename": "smbclientng.core.Config", "qualname": "Config.no_colors", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell", "modulename": "smbclientng.core.InteractiveShell", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell.command_arguments_required", "modulename": "smbclientng.core.InteractiveShell", "qualname": "command_arguments_required", "kind": "function", "doc": "

\n", "signature": "(func):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.active_smb_connection_needed", "modulename": "smbclientng.core.InteractiveShell", "qualname": "active_smb_connection_needed", "kind": "function", "doc": "

\n", "signature": "(func):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.smb_share_is_set", "modulename": "smbclientng.core.InteractiveShell", "qualname": "smb_share_is_set", "kind": "function", "doc": "

\n", "signature": "(func):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell", "kind": "class", "doc": "

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.

\n"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.__init__", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.__init__", "kind": "function", "doc": "

\n", "signature": "(smbSession, config)"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.smbSession", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.smbSession", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.config", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.config", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.commandCompleterObject", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.commandCompleterObject", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.modules", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.modules", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.run", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.run", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.process_command", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.process_command", "kind": "function", "doc": "

\n", "signature": "(self, command, arguments=[]):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_debug", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_debug", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_bat", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_bat", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_cd", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_cd", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_cat", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_cat", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_close", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_close", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_get", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_get", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_help", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_help", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_info", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_info", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lcat", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lcat", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lcd", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lcd", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lcp", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lcp", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lbat", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lbat", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lls", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lls", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lmkdir", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lmkdir", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lpwd", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lpwd", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lrename", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lrename", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lrm", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lrm", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lrmdir", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lrmdir", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_ltree", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_ltree", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_ls", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_ls", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_mkdir", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_mkdir", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_module", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_module", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_mount", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_mount", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_put", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_put", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_reconnect", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_reconnect", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_reset", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_reset", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_rm", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_rm", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_rmdir", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_rmdir", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_sizeof", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_sizeof", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_shares", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_shares", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_tree", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_tree", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_umount", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_umount", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_use", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_use", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.LocalFileIO", "modulename": "smbclientng.core.LocalFileIO", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO", "kind": "class", "doc": "

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.

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.__init__", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.__init__", "kind": "function", "doc": "

\n", "signature": "(\tmode,\tpath=None,\texpected_size=None,\tkeepRemotePath=False,\tdebug=False)"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.mode", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.mode", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.path", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.path", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.dir", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.dir", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.debug", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.debug", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.expected_size", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.expected_size", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.keepRemotePath", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.keepRemotePath", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.write", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.write", "kind": "function", "doc": "

Writes data to the file.

\n\n

This method writes the specified data to the file and updates the progress bar with the amount of data written if the expected size is set.

\n\n

Args:\n data (bytes): The data to be written to the file.

\n\n

Returns:\n int: The number of bytes written.

\n", "signature": "(self, data):", "funcdef": "def"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.read", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.read", "kind": "function", "doc": "

Reads a specified amount of data from the file.

\n\n

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.

\n\n

Returns:\n bytes: The data read from the file.

\n", "signature": "(self, size):", "funcdef": "def"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.close", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.close", "kind": "function", "doc": "

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.

\n", "signature": "(self, remove=False):", "funcdef": "def"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.set_error", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.set_error", "kind": "function", "doc": "

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.

\n", "signature": "(self, message):", "funcdef": "def"}, {"fullname": "smbclientng.core.Module", "modulename": "smbclientng.core.Module", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.Module.Module", "modulename": "smbclientng.core.Module", "qualname": "Module", "kind": "class", "doc": "

A parent class for all modules in the smbclient-ng tool.

\n\n

This class provides common attributes and methods that are shared among different modules.

\n"}, {"fullname": "smbclientng.core.Module.Module.__init__", "modulename": "smbclientng.core.Module", "qualname": "Module.__init__", "kind": "function", "doc": "

\n", "signature": "(smbSession, config)"}, {"fullname": "smbclientng.core.Module.Module.name", "modulename": "smbclientng.core.Module", "qualname": "Module.name", "kind": "variable", "doc": "

\n", "default_value": "''"}, {"fullname": "smbclientng.core.Module.Module.description", "modulename": "smbclientng.core.Module", "qualname": "Module.description", "kind": "variable", "doc": "

\n", "default_value": "''"}, {"fullname": "smbclientng.core.Module.Module.smbSession", "modulename": "smbclientng.core.Module", "qualname": "Module.smbSession", "kind": "variable", "doc": "

\n", "default_value": "None"}, {"fullname": "smbclientng.core.Module.Module.options", "modulename": "smbclientng.core.Module", "qualname": "Module.options", "kind": "variable", "doc": "

\n", "default_value": "None"}, {"fullname": "smbclientng.core.Module.Module.config", "modulename": "smbclientng.core.Module", "qualname": "Module.config", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.Module.Module.parseArgs", "modulename": "smbclientng.core.Module", "qualname": "Module.parseArgs", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.Module.Module.run", "modulename": "smbclientng.core.Module", "qualname": "Module.run", "kind": "function", "doc": "

Placeholder method for running the module.

\n\n

This method should be implemented by subclasses to define the specific behavior of the module.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.Module.Module.processArguments", "modulename": "smbclientng.core.Module", "qualname": "Module.processArguments", "kind": "function", "doc": "

\n", "signature": "(self, parser, arguments):", "funcdef": "def"}, {"fullname": "smbclientng.core.ModuleArgumentParser", "modulename": "smbclientng.core.ModuleArgumentParser", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.ModuleArgumentParser.ModuleArgumentParser", "modulename": "smbclientng.core.ModuleArgumentParser", "qualname": "ModuleArgumentParser", "kind": "class", "doc": "

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.

\n", "bases": "argparse.ArgumentParser"}, {"fullname": "smbclientng.core.ModuleArgumentParser.ModuleArgumentParser.error", "modulename": "smbclientng.core.ModuleArgumentParser", "qualname": "ModuleArgumentParser.error", "kind": "function", "doc": "

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.

\n", "signature": "(self, message):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession", "modulename": "smbclientng.core.SMBSession", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession", "kind": "class", "doc": "

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.

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.__init__", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.__init__", "kind": "function", "doc": "

\n", "signature": "(\taddress,\tdomain,\tusername,\tpassword,\tlmhash,\tnthash,\tuse_kerberos=False,\tkdcHost=None,\tconfig=None)"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.config", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.config", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.address", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.address", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.domain", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.domain", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.username", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.username", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.password", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.password", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.lmhash", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.lmhash", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.nthash", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.nthash", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.use_kerberos", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.use_kerberos", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.kdcHost", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.kdcHost", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.smbClient", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.smbClient", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.connected", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.connected", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.available_shares", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.available_shares", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.smb_share", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.smb_share", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.smb_cwd", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.smb_cwd", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.smb_tree_id", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.smb_tree_id", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.init_smb_session", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.init_smb_session", "kind": "function", "doc": "

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.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.close_smb_session", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.close_smb_session", "kind": "function", "doc": "

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.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.read_file", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.read_file", "kind": "function", "doc": "

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.find", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.find", "kind": "function", "doc": "

\n", "signature": "(self, paths=[], callback=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.get_file", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.get_file", "kind": "function", "doc": "

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.

\n\n

Returns:\n None

\n", "signature": "(self, path=None, keepRemotePath=False):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.get_file_recursively", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.get_file_recursively", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.get_entry", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.get_entry", "kind": "function", "doc": "

Retrieves information about a specific entry located at the provided path on the SMB share.

\n\n

This method checks if the specified path exists on the SMB share. If the path exists, it retrieves the details of the entry at that path, including the directory name and file name. If the entry is found, it returns the entry object; otherwise, it returns None.

\n\n

Args:\n path (str): The path of the entry to retrieve information about.

\n\n

Returns:\n Entry: An object representing the entry at the specified path, or None if the entry is not found.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.info", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.info", "kind": "function", "doc": "

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.

\n\n

Returns:\n None

\n", "signature": "(self, share=True, server=True):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.list_contents", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.list_contents", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.list_shares", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.list_shares", "kind": "function", "doc": "

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.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.mkdir", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.mkdir", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.mount", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.mount", "kind": "function", "doc": "

\n", "signature": "(self, local_mount_point, remote_path):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.path_exists", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.path_exists", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.path_isdir", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.path_isdir", "kind": "function", "doc": "

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.

\n", "signature": "(self, pathFromRoot=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.path_isfile", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.path_isfile", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.ping_smb_session", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.ping_smb_session", "kind": "function", "doc": "

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.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.put_file", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.put_file", "kind": "function", "doc": "

Uploads a single file to the SMB share.

\n\n

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.

\n", "signature": "(self, localpath=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.put_file_recursively", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.put_file_recursively", "kind": "function", "doc": "

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.

\n", "signature": "(self, localpath=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.rmdir", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.rmdir", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.rm", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.rm", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.tree", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.tree", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.umount", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.umount", "kind": "function", "doc": "

\n", "signature": "(self, local_mount_point):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.set_share", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.set_share", "kind": "function", "doc": "

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.

\n", "signature": "(self, shareName):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.set_cwd", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.set_cwd", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils", "modulename": "smbclientng.core.utils", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.utils.parse_lm_nt_hashes", "modulename": "smbclientng.core.utils", "qualname": "parse_lm_nt_hashes", "kind": "function", "doc": "

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.

\n\n

Extracted from p0dalirius/sectools library\nSrc: https://github.com/p0dalirius/sectools/blob/7bb3f5cb7815ad4d4845713c8739e2e2b0ea4e75/sectools/windows/crypto.py#L11-L24

\n", "signature": "(lm_nt_hashes_string):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils.b_filesize", "modulename": "smbclientng.core.utils", "qualname": "b_filesize", "kind": "function", "doc": "

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.

\n", "signature": "(l):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils.unix_permissions", "modulename": "smbclientng.core.utils", "qualname": "unix_permissions", "kind": "function", "doc": "

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.

\n", "signature": "(entryname):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils.STYPE_MASK", "modulename": "smbclientng.core.utils", "qualname": "STYPE_MASK", "kind": "function", "doc": "

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.

\n", "signature": "(stype_value):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils.windows_ls_entry", "modulename": "smbclientng.core.utils", "qualname": "windows_ls_entry", "kind": "function", "doc": "

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.

\n", "signature": "(entry, config, pathToPrint=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils.local_tree", "modulename": "smbclientng.core.utils", "qualname": "local_tree", "kind": "function", "doc": "

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.

\n", "signature": "(path, config):", "funcdef": "def"}, {"fullname": "smbclientng.modules", "modulename": "smbclientng.modules", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.modules.Find", "modulename": "smbclientng.modules.Find", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.modules.Find.Find", "modulename": "smbclientng.modules.Find", "qualname": "Find", "kind": "class", "doc": "

A class to search for files in a directory hierarchy.

\n\n

This class provides functionality to search for files based on various criteria in a directory hierarchy.

\n", "bases": "smbclientng.core.Module.Module"}, {"fullname": "smbclientng.modules.Find.Find.name", "modulename": "smbclientng.modules.Find", "qualname": "Find.name", "kind": "variable", "doc": "

\n", "default_value": "'find'"}, {"fullname": "smbclientng.modules.Find.Find.description", "modulename": "smbclientng.modules.Find", "qualname": "Find.description", "kind": "variable", "doc": "

\n", "default_value": "'Search for files in a directory hierarchy'"}, {"fullname": "smbclientng.modules.Find.Find.parseArgs", "modulename": "smbclientng.modules.Find", "qualname": "Find.parseArgs", "kind": "function", "doc": "

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.

\n", "signature": "(self, arguments):", "funcdef": "def"}, {"fullname": "smbclientng.modules.Find.Find.run", "modulename": "smbclientng.modules.Find", "qualname": "Find.run", "kind": "function", "doc": "

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"}, {"fullname": "smbclientng.modules.GPPPasswords", "modulename": "smbclientng.modules.GPPPasswords", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords", "kind": "class", "doc": "

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.

\n", "bases": "smbclientng.core.Module.Module"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.name", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.name", "kind": "variable", "doc": "

\n", "default_value": "'gpppasswords'"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.description", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.description", "kind": "variable", "doc": "

\n", "default_value": "'Searches for Group Policy Preferences Passwords in a share.'"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.parseArgs", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.parseArgs", "kind": "function", "doc": "

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.

\n", "signature": "(self, arguments):", "funcdef": "def"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.parse_xmlfile_content", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.parse_xmlfile_content", "kind": "function", "doc": "

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.

\n", "signature": "(self, pathtofile):", "funcdef": "def"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.decrypt_password", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.decrypt_password", "kind": "function", "doc": "

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.

\n", "signature": "(self, pw_enc_b64):", "funcdef": "def"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.run", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.run", "kind": "function", "doc": "

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"}]; + /** pdoc search index */const docs = [{"fullname": "smbclientng", "modulename": "smbclientng", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core", "modulename": "smbclientng.core", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.CommandCompleter", "modulename": "smbclientng.core.CommandCompleter", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter", "kind": "class", "doc": "

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 remote file.', "Syntax: 'bat <file>'"], 'subcommands': []}, 'cat': {'description': ['Get the contents of a remote 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': []}, 'debug': {'description': ['Command for dev debugging.', "Syntax: 'debug'"], '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']}, 'lbat': {'description': ['Pretty prints the contents of a local file.', "Syntax: 'lbat <file>'"], 'subcommands': []}, 'lcat': {'description': ['Print the contents of a local file.', "Syntax: 'lcat <file>'"], 'subcommands': []}, 'lcd': {'description': ['Changes the current local directory.', "Syntax: 'lcd <directory>'"], 'subcommands': []}, 'lcp': {'description': ['Create a copy of a local file.', "Syntax: 'lcp <srcfile> <dstfile>'"], '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': []}, 'lrename': {'description': ['Renames a local file.', "Syntax: 'lrename <oldfilename> <newfilename>'"], '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': []}, 'mount': {'description': ['Creates a mount point of the remote share on the local machine.', "Syntax: 'mount <remote_path> <local_mountpoint>'"], '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': []}, 'sizeof': {'description': ['Recursively compute the size of a folder.', "Syntax: 'sizeof [directory|file]'"], 'subcommands': []}, 'shares': {'description': ['Lists the SMB shares served by the remote machine.', "Syntax: 'shares'"], 'subcommands': ['rights']}, 'tree': {'description': ['Displays a tree view of the remote directories.', "Syntax: 'tree [directory]'"], 'subcommands': []}, 'umount': {'description': ['Removes a mount point of the remote share on the local machine.', "Syntax: 'umount <local_mount_point>'"], 'subcommands': []}, 'use': {'description': ['Use a SMB share.', "Syntax: 'use <sharename>'"], '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.

\n", "signature": "(self, text, state):", "funcdef": "def"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.print_help", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.print_help", "kind": "function", "doc": "

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.

\n\n

Returns:\n None

\n", "signature": "(self, command=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.CommandCompleter.CommandCompleter.print_help_format", "modulename": "smbclientng.core.CommandCompleter", "qualname": "CommandCompleter.print_help_format", "kind": "function", "doc": "

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.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.Config", "modulename": "smbclientng.core.Config", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.Config.Config", "modulename": "smbclientng.core.Config", "qualname": "Config", "kind": "class", "doc": "

Configuration handler for smbclientng.

\n\n

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.

\n"}, {"fullname": "smbclientng.core.Config.Config.__init__", "modulename": "smbclientng.core.Config", "qualname": "Config.__init__", "kind": "function", "doc": "

\n", "signature": "(debug=False, no_colors=None)"}, {"fullname": "smbclientng.core.Config.Config.debug", "modulename": "smbclientng.core.Config", "qualname": "Config.debug", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.Config.Config.no_colors", "modulename": "smbclientng.core.Config", "qualname": "Config.no_colors", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell", "modulename": "smbclientng.core.InteractiveShell", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell.command_arguments_required", "modulename": "smbclientng.core.InteractiveShell", "qualname": "command_arguments_required", "kind": "function", "doc": "

\n", "signature": "(func):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.active_smb_connection_needed", "modulename": "smbclientng.core.InteractiveShell", "qualname": "active_smb_connection_needed", "kind": "function", "doc": "

\n", "signature": "(func):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.smb_share_is_set", "modulename": "smbclientng.core.InteractiveShell", "qualname": "smb_share_is_set", "kind": "function", "doc": "

\n", "signature": "(func):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell", "kind": "class", "doc": "

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.

\n"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.__init__", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.__init__", "kind": "function", "doc": "

\n", "signature": "(smbSession, config)"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.smbSession", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.smbSession", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.config", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.config", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.commandCompleterObject", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.commandCompleterObject", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.modules", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.modules", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.run", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.run", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.process_command", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.process_command", "kind": "function", "doc": "

\n", "signature": "(self, command, arguments=[]):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_debug", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_debug", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_bat", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_bat", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_cd", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_cd", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_cat", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_cat", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_close", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_close", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_get", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_get", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_help", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_help", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_info", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_info", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lcat", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lcat", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lcd", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lcd", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lcp", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lcp", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lbat", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lbat", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lls", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lls", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lmkdir", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lmkdir", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lpwd", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lpwd", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lrename", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lrename", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lrm", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lrm", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_lrmdir", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_lrmdir", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_ltree", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_ltree", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_ls", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_ls", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_mkdir", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_mkdir", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_module", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_module", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_mount", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_mount", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_put", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_put", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_reconnect", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_reconnect", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_reset", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_reset", "kind": "function", "doc": "

\n", "signature": "(self, arguments, command):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_rm", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_rm", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_rmdir", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_rmdir", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_sizeof", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_sizeof", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_shares", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_shares", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_tree", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_tree", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_umount", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_umount", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.InteractiveShell.InteractiveShell.command_use", "modulename": "smbclientng.core.InteractiveShell", "qualname": "InteractiveShell.command_use", "kind": "function", "doc": "

\n", "signature": "(*args, **kwargs):", "funcdef": "def"}, {"fullname": "smbclientng.core.LocalFileIO", "modulename": "smbclientng.core.LocalFileIO", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO", "kind": "class", "doc": "

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.

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.__init__", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.__init__", "kind": "function", "doc": "

\n", "signature": "(\tmode,\tpath=None,\texpected_size=None,\tkeepRemotePath=False,\tdebug=False)"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.mode", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.mode", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.path", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.path", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.dir", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.dir", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.debug", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.debug", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.expected_size", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.expected_size", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.keepRemotePath", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.keepRemotePath", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.write", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.write", "kind": "function", "doc": "

Writes data to the file.

\n\n

This method writes the specified data to the file and updates the progress bar with the amount of data written if the expected size is set.

\n\n

Args:\n data (bytes): The data to be written to the file.

\n\n

Returns:\n int: The number of bytes written.

\n", "signature": "(self, data):", "funcdef": "def"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.read", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.read", "kind": "function", "doc": "

Reads a specified amount of data from the file.

\n\n

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.

\n\n

Returns:\n bytes: The data read from the file.

\n", "signature": "(self, size):", "funcdef": "def"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.close", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.close", "kind": "function", "doc": "

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.

\n", "signature": "(self, remove=False):", "funcdef": "def"}, {"fullname": "smbclientng.core.LocalFileIO.LocalFileIO.set_error", "modulename": "smbclientng.core.LocalFileIO", "qualname": "LocalFileIO.set_error", "kind": "function", "doc": "

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.

\n", "signature": "(self, message):", "funcdef": "def"}, {"fullname": "smbclientng.core.Module", "modulename": "smbclientng.core.Module", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.Module.Module", "modulename": "smbclientng.core.Module", "qualname": "Module", "kind": "class", "doc": "

A parent class for all modules in the smbclient-ng tool.

\n\n

This class provides common attributes and methods that are shared among different modules.

\n"}, {"fullname": "smbclientng.core.Module.Module.__init__", "modulename": "smbclientng.core.Module", "qualname": "Module.__init__", "kind": "function", "doc": "

\n", "signature": "(smbSession, config)"}, {"fullname": "smbclientng.core.Module.Module.name", "modulename": "smbclientng.core.Module", "qualname": "Module.name", "kind": "variable", "doc": "

\n", "default_value": "''"}, {"fullname": "smbclientng.core.Module.Module.description", "modulename": "smbclientng.core.Module", "qualname": "Module.description", "kind": "variable", "doc": "

\n", "default_value": "''"}, {"fullname": "smbclientng.core.Module.Module.smbSession", "modulename": "smbclientng.core.Module", "qualname": "Module.smbSession", "kind": "variable", "doc": "

\n", "default_value": "None"}, {"fullname": "smbclientng.core.Module.Module.options", "modulename": "smbclientng.core.Module", "qualname": "Module.options", "kind": "variable", "doc": "

\n", "default_value": "None"}, {"fullname": "smbclientng.core.Module.Module.config", "modulename": "smbclientng.core.Module", "qualname": "Module.config", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.Module.Module.parseArgs", "modulename": "smbclientng.core.Module", "qualname": "Module.parseArgs", "kind": "function", "doc": "

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.Module.Module.run", "modulename": "smbclientng.core.Module", "qualname": "Module.run", "kind": "function", "doc": "

Placeholder method for running the module.

\n\n

This method should be implemented by subclasses to define the specific behavior of the module.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.Module.Module.processArguments", "modulename": "smbclientng.core.Module", "qualname": "Module.processArguments", "kind": "function", "doc": "

\n", "signature": "(self, parser, arguments):", "funcdef": "def"}, {"fullname": "smbclientng.core.ModuleArgumentParser", "modulename": "smbclientng.core.ModuleArgumentParser", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.ModuleArgumentParser.ModuleArgumentParser", "modulename": "smbclientng.core.ModuleArgumentParser", "qualname": "ModuleArgumentParser", "kind": "class", "doc": "

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.

\n", "bases": "argparse.ArgumentParser"}, {"fullname": "smbclientng.core.ModuleArgumentParser.ModuleArgumentParser.error", "modulename": "smbclientng.core.ModuleArgumentParser", "qualname": "ModuleArgumentParser.error", "kind": "function", "doc": "

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.

\n", "signature": "(self, message):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession", "modulename": "smbclientng.core.SMBSession", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession", "kind": "class", "doc": "

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.

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.__init__", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.__init__", "kind": "function", "doc": "

\n", "signature": "(\taddress,\tdomain,\tusername,\tpassword,\tlmhash,\tnthash,\tuse_kerberos=False,\tkdcHost=None,\tconfig=None)"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.config", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.config", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.address", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.address", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.domain", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.domain", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.username", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.username", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.password", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.password", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.lmhash", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.lmhash", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.nthash", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.nthash", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.use_kerberos", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.use_kerberos", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.kdcHost", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.kdcHost", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.smbClient", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.smbClient", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.connected", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.connected", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.available_shares", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.available_shares", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.smb_share", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.smb_share", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.smb_cwd", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.smb_cwd", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.smb_tree_id", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.smb_tree_id", "kind": "variable", "doc": "

\n"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.init_smb_session", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.init_smb_session", "kind": "function", "doc": "

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.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.close_smb_session", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.close_smb_session", "kind": "function", "doc": "

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.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.read_file", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.read_file", "kind": "function", "doc": "

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.find", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.find", "kind": "function", "doc": "

\n", "signature": "(self, paths=[], callback=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.get_file", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.get_file", "kind": "function", "doc": "

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.

\n\n

Returns:\n None

\n", "signature": "(self, path=None, keepRemotePath=False):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.get_file_recursively", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.get_file_recursively", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.get_entry", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.get_entry", "kind": "function", "doc": "

Retrieves information about a specific entry located at the provided path on the SMB share.

\n\n

This method checks if the specified path exists on the SMB share. If the path exists, it retrieves the details of the entry at that path, including the directory name and file name. If the entry is found, it returns the entry object; otherwise, it returns None.

\n\n

Args:\n path (str): The path of the entry to retrieve information about.

\n\n

Returns:\n Entry: An object representing the entry at the specified path, or None if the entry is not found.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.info", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.info", "kind": "function", "doc": "

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.

\n\n

Returns:\n None

\n", "signature": "(self, share=True, server=True):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.list_contents", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.list_contents", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.list_shares", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.list_shares", "kind": "function", "doc": "

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.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.mkdir", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.mkdir", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.mount", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.mount", "kind": "function", "doc": "

Generates the command to mount an SMB share on different platforms.

\n\n

This method takes the local mount point and the remote path of the SMB share and generates the appropriate mount command based on the platform.\nIt constructs the mount command using the provided parameters and executes it using the os.system() function.

\n\n

Args:\n local_mount_point (str): The local directory where the SMB share will be mounted.\n remote_path (str): The remote path on the SMB share to be mounted.

\n\n

Note:\n - For Windows platform, the command uses 'net use' to mount the share.\n - For Linux platform, the command uses 'mount' to mount the share.\n - For macOS platform, the command uses 'mount_smbfs' to mount the share.\n - If the platform is not supported, an error message is displayed.

\n\n

Returns:\n None

\n", "signature": "(self, local_mount_point, remote_path):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.path_exists", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.path_exists", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.path_isdir", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.path_isdir", "kind": "function", "doc": "

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.

\n", "signature": "(self, pathFromRoot=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.path_isfile", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.path_isfile", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.ping_smb_session", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.ping_smb_session", "kind": "function", "doc": "

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.

\n", "signature": "(self):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.put_file", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.put_file", "kind": "function", "doc": "

Uploads a single file to the SMB share.

\n\n

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.

\n", "signature": "(self, localpath=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.put_file_recursively", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.put_file_recursively", "kind": "function", "doc": "

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.

\n", "signature": "(self, localpath=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.rmdir", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.rmdir", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.rm", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.rm", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.tree", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.tree", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.umount", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.umount", "kind": "function", "doc": "

Unmounts the specified local mount point of the remote share.

\n\n

This method unmounts the specified local mount point of the remote share based on the platform.\nIt supports Windows, Linux, and macOS platforms for unmounting.

\n\n

Parameters:\n local_mount_point (str): The local mount point to unmount.

\n\n

Raises:\n None

\n", "signature": "(self, local_mount_point):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.test_rights", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.test_rights", "kind": "function", "doc": "

Tests the read and write access rights of the current SMB session.

\n\n

This method checks the read and write access rights of the current SMB session by attempting to list paths and create/delete temporary directories.

\n\n

Returns:\n dict: A dictionary containing the read and write access rights status.\n - \"readable\" (bool): Indicates if the session has read access rights.\n - \"writable\" (bool): Indicates if the session has write access rights.

\n", "signature": "(self, sharename):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.set_share", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.set_share", "kind": "function", "doc": "

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.

\n", "signature": "(self, shareName):", "funcdef": "def"}, {"fullname": "smbclientng.core.SMBSession.SMBSession.set_cwd", "modulename": "smbclientng.core.SMBSession", "qualname": "SMBSession.set_cwd", "kind": "function", "doc": "

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.

\n", "signature": "(self, path=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils", "modulename": "smbclientng.core.utils", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.core.utils.parse_lm_nt_hashes", "modulename": "smbclientng.core.utils", "qualname": "parse_lm_nt_hashes", "kind": "function", "doc": "

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.

\n\n

Extracted from p0dalirius/sectools library\nSrc: https://github.com/p0dalirius/sectools/blob/7bb3f5cb7815ad4d4845713c8739e2e2b0ea4e75/sectools/windows/crypto.py#L11-L24

\n", "signature": "(lm_nt_hashes_string):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils.b_filesize", "modulename": "smbclientng.core.utils", "qualname": "b_filesize", "kind": "function", "doc": "

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.

\n", "signature": "(l):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils.unix_permissions", "modulename": "smbclientng.core.utils", "qualname": "unix_permissions", "kind": "function", "doc": "

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.

\n", "signature": "(entryname):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils.STYPE_MASK", "modulename": "smbclientng.core.utils", "qualname": "STYPE_MASK", "kind": "function", "doc": "

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.

\n", "signature": "(stype_value):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils.windows_ls_entry", "modulename": "smbclientng.core.utils", "qualname": "windows_ls_entry", "kind": "function", "doc": "

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.

\n", "signature": "(entry, config, pathToPrint=None):", "funcdef": "def"}, {"fullname": "smbclientng.core.utils.local_tree", "modulename": "smbclientng.core.utils", "qualname": "local_tree", "kind": "function", "doc": "

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.

\n", "signature": "(path, config):", "funcdef": "def"}, {"fullname": "smbclientng.modules", "modulename": "smbclientng.modules", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.modules.Find", "modulename": "smbclientng.modules.Find", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.modules.Find.Find", "modulename": "smbclientng.modules.Find", "qualname": "Find", "kind": "class", "doc": "

A class to search for files in a directory hierarchy.

\n\n

This class provides functionality to search for files based on various criteria in a directory hierarchy.

\n", "bases": "smbclientng.core.Module.Module"}, {"fullname": "smbclientng.modules.Find.Find.name", "modulename": "smbclientng.modules.Find", "qualname": "Find.name", "kind": "variable", "doc": "

\n", "default_value": "'find'"}, {"fullname": "smbclientng.modules.Find.Find.description", "modulename": "smbclientng.modules.Find", "qualname": "Find.description", "kind": "variable", "doc": "

\n", "default_value": "'Search for files in a directory hierarchy'"}, {"fullname": "smbclientng.modules.Find.Find.parseArgs", "modulename": "smbclientng.modules.Find", "qualname": "Find.parseArgs", "kind": "function", "doc": "

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.

\n", "signature": "(self, arguments):", "funcdef": "def"}, {"fullname": "smbclientng.modules.Find.Find.run", "modulename": "smbclientng.modules.Find", "qualname": "Find.run", "kind": "function", "doc": "

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"}, {"fullname": "smbclientng.modules.GPPPasswords", "modulename": "smbclientng.modules.GPPPasswords", "kind": "module", "doc": "

\n"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords", "kind": "class", "doc": "

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.

\n", "bases": "smbclientng.core.Module.Module"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.name", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.name", "kind": "variable", "doc": "

\n", "default_value": "'gpppasswords'"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.description", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.description", "kind": "variable", "doc": "

\n", "default_value": "'Searches for Group Policy Preferences Passwords in a share.'"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.parseArgs", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.parseArgs", "kind": "function", "doc": "

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.

\n", "signature": "(self, arguments):", "funcdef": "def"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.parse_xmlfile_content", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.parse_xmlfile_content", "kind": "function", "doc": "

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.

\n", "signature": "(self, pathtofile):", "funcdef": "def"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.decrypt_password", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.decrypt_password", "kind": "function", "doc": "

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.

\n", "signature": "(self, pw_enc_b64):", "funcdef": "def"}, {"fullname": "smbclientng.modules.GPPPasswords.GPPPasswords.run", "modulename": "smbclientng.modules.GPPPasswords", "qualname": "GPPPasswords.run", "kind": "function", "doc": "

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 da8c6f7..9a8ffe3 100644 --- a/documentation/smbclientng/core/CommandCompleter.html +++ b/documentation/smbclientng/core/CommandCompleter.html @@ -335,7 +335,7 @@

255 "Lists the SMB shares served by the remote machine.", 256 "Syntax: 'shares'" 257 ], -258 "subcommands": [] +258 "subcommands": ["rights"] 259 }, 260 "tree": { 261 "description": [ @@ -585,17 +585,28 @@

505 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning 506 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory. 507 """ -508 -509 print("File attributes format:\n") -510 print("\x1b[1mdachnrst\x1b[0m") -511 print("\x1b[90m│││││││└──>\x1b[0m Temporary") -512 print("\x1b[90m││││││└───>\x1b[0m System") -513 print("\x1b[90m│││││└────>\x1b[0m Read-Only") -514 print("\x1b[90m││││└─────>\x1b[0m Normal") -515 print("\x1b[90m│││└──────>\x1b[0m Hidden") -516 print("\x1b[90m││└───────>\x1b[0m Compressed") -517 print("\x1b[90m│└────────>\x1b[0m Archived") -518 print("\x1b[90m└─────────>\x1b[0m Directory") +508 if self.config.no_colors: +509 print("File attributes format:\n") +510 print("dachnrst") +511 print("│││││││└──> Temporary") +512 print("││││││└───> System") +513 print("│││││└────> Read-Only") +514 print("││││└─────> Normal") +515 print("│││└──────> Hidden") +516 print("││└───────> Compressed") +517 print("│└────────> Archived") +518 print("└─────────> Directory") +519 else: +520 print("File attributes format:\n") +521 print("dachnrst") +522 print("\x1b[90m│││││││└──>\x1b[0m Temporary") +523 print("\x1b[90m││││││└───>\x1b[0m System") +524 print("\x1b[90m│││││└────>\x1b[0m Read-Only") +525 print("\x1b[90m││││└─────>\x1b[0m Normal") +526 print("\x1b[90m│││└──────>\x1b[0m Hidden") +527 print("\x1b[90m││└───────>\x1b[0m Compressed") +528 print("\x1b[90m│└────────>\x1b[0m Archived") +529 print("\x1b[90m└─────────>\x1b[0m Directory") @@ -857,7 +868,7 @@

256 "Lists the SMB shares served by the remote machine.", 257 "Syntax: 'shares'" 258 ], -259 "subcommands": [] +259 "subcommands": ["rights"] 260 }, 261 "tree": { 262 "description": [ @@ -1107,17 +1118,28 @@

506 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning 507 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory. 508 """ -509 -510 print("File attributes format:\n") -511 print("\x1b[1mdachnrst\x1b[0m") -512 print("\x1b[90m│││││││└──>\x1b[0m Temporary") -513 print("\x1b[90m││││││└───>\x1b[0m System") -514 print("\x1b[90m│││││└────>\x1b[0m Read-Only") -515 print("\x1b[90m││││└─────>\x1b[0m Normal") -516 print("\x1b[90m│││└──────>\x1b[0m Hidden") -517 print("\x1b[90m││└───────>\x1b[0m Compressed") -518 print("\x1b[90m│└────────>\x1b[0m Archived") -519 print("\x1b[90m└─────────>\x1b[0m Directory") +509 if self.config.no_colors: +510 print("File attributes format:\n") +511 print("dachnrst") +512 print("│││││││└──> Temporary") +513 print("││││││└───> System") +514 print("│││││└────> Read-Only") +515 print("││││└─────> Normal") +516 print("│││└──────> Hidden") +517 print("││└───────> Compressed") +518 print("│└────────> Archived") +519 print("└─────────> Directory") +520 else: +521 print("File attributes format:\n") +522 print("dachnrst") +523 print("\x1b[90m│││││││└──>\x1b[0m Temporary") +524 print("\x1b[90m││││││└───>\x1b[0m System") +525 print("\x1b[90m│││││└────>\x1b[0m Read-Only") +526 print("\x1b[90m││││└─────>\x1b[0m Normal") +527 print("\x1b[90m│││└──────>\x1b[0m Hidden") +528 print("\x1b[90m││└───────>\x1b[0m Compressed") +529 print("\x1b[90m│└────────>\x1b[0m Archived") +530 print("\x1b[90m└─────────>\x1b[0m Directory") @@ -1163,7 +1185,7 @@

commands = - {'bat': {'description': ['Pretty prints the contents of a remote file.', "Syntax: 'bat <file>'"], 'subcommands': []}, 'cat': {'description': ['Get the contents of a remote 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': []}, 'debug': {'description': ['Command for dev debugging.', "Syntax: 'debug'"], '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']}, 'lbat': {'description': ['Pretty prints the contents of a local file.', "Syntax: 'lbat <file>'"], 'subcommands': []}, 'lcat': {'description': ['Print the contents of a local file.', "Syntax: 'lcat <file>'"], 'subcommands': []}, 'lcd': {'description': ['Changes the current local directory.', "Syntax: 'lcd <directory>'"], 'subcommands': []}, 'lcp': {'description': ['Create a copy of a local file.', "Syntax: 'lcp <srcfile> <dstfile>'"], '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': []}, 'lrename': {'description': ['Renames a local file.', "Syntax: 'lrename <oldfilename> <newfilename>'"], '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': []}, 'mount': {'description': ['Creates a mount point of the remote share on the local machine.', "Syntax: 'mount <remote_path> <local_mountpoint>'"], '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': []}, 'sizeof': {'description': ['Recursively compute the size of a folder.', "Syntax: 'sizeof [directory|file]'"], 'subcommands': []}, 'shares': {'description': ['Lists the SMB shares served by the remote machine.', "Syntax: 'shares'"], 'subcommands': []}, 'tree': {'description': ['Displays a tree view of the remote directories.', "Syntax: 'tree [directory]'"], 'subcommands': []}, 'umount': {'description': ['Removes a mount point of the remote share on the local machine.', "Syntax: 'umount <local_mount_point>'"], 'subcommands': []}, 'use': {'description': ['Use a SMB share.', "Syntax: 'use <sharename>'"], 'subcommands': []}} + {'bat': {'description': ['Pretty prints the contents of a remote file.', "Syntax: 'bat <file>'"], 'subcommands': []}, 'cat': {'description': ['Get the contents of a remote 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': []}, 'debug': {'description': ['Command for dev debugging.', "Syntax: 'debug'"], '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']}, 'lbat': {'description': ['Pretty prints the contents of a local file.', "Syntax: 'lbat <file>'"], 'subcommands': []}, 'lcat': {'description': ['Print the contents of a local file.', "Syntax: 'lcat <file>'"], 'subcommands': []}, 'lcd': {'description': ['Changes the current local directory.', "Syntax: 'lcd <directory>'"], 'subcommands': []}, 'lcp': {'description': ['Create a copy of a local file.', "Syntax: 'lcp <srcfile> <dstfile>'"], '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': []}, 'lrename': {'description': ['Renames a local file.', "Syntax: 'lrename <oldfilename> <newfilename>'"], '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': []}, 'mount': {'description': ['Creates a mount point of the remote share on the local machine.', "Syntax: 'mount <remote_path> <local_mountpoint>'"], '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': []}, 'sizeof': {'description': ['Recursively compute the size of a folder.', "Syntax: 'sizeof [directory|file]'"], 'subcommands': []}, 'shares': {'description': ['Lists the SMB shares served by the remote machine.', "Syntax: 'shares'"], 'subcommands': ['rights']}, 'tree': {'description': ['Displays a tree view of the remote directories.', "Syntax: 'tree [directory]'"], 'subcommands': []}, 'umount': {'description': ['Removes a mount point of the remote share on the local machine.', "Syntax: 'umount <local_mount_point>'"], 'subcommands': []}, 'use': {'description': ['Use a SMB share.', "Syntax: 'use <sharename>'"], 'subcommands': []}}
@@ -1478,17 +1500,28 @@

506 This function displays the format of file attributes used in the smbclient-ng shell. It explains the meaning 507 of each character in the file attribute string, such as whether a file is read-only, hidden, or a directory. 508 """ -509 -510 print("File attributes format:\n") -511 print("\x1b[1mdachnrst\x1b[0m") -512 print("\x1b[90m│││││││└──>\x1b[0m Temporary") -513 print("\x1b[90m││││││└───>\x1b[0m System") -514 print("\x1b[90m│││││└────>\x1b[0m Read-Only") -515 print("\x1b[90m││││└─────>\x1b[0m Normal") -516 print("\x1b[90m│││└──────>\x1b[0m Hidden") -517 print("\x1b[90m││└───────>\x1b[0m Compressed") -518 print("\x1b[90m│└────────>\x1b[0m Archived") -519 print("\x1b[90m└─────────>\x1b[0m Directory") +509 if self.config.no_colors: +510 print("File attributes format:\n") +511 print("dachnrst") +512 print("│││││││└──> Temporary") +513 print("││││││└───> System") +514 print("│││││└────> Read-Only") +515 print("││││└─────> Normal") +516 print("│││└──────> Hidden") +517 print("││└───────> Compressed") +518 print("│└────────> Archived") +519 print("└─────────> Directory") +520 else: +521 print("File attributes format:\n") +522 print("dachnrst") +523 print("\x1b[90m│││││││└──>\x1b[0m Temporary") +524 print("\x1b[90m││││││└───>\x1b[0m System") +525 print("\x1b[90m│││││└────>\x1b[0m Read-Only") +526 print("\x1b[90m││││└─────>\x1b[0m Normal") +527 print("\x1b[90m│││└──────>\x1b[0m Hidden") +528 print("\x1b[90m││└───────>\x1b[0m Compressed") +529 print("\x1b[90m│└────────>\x1b[0m Archived") +530 print("\x1b[90m└─────────>\x1b[0m Directory") diff --git a/documentation/smbclientng/core/InteractiveShell.html b/documentation/smbclientng/core/InteractiveShell.html index 5763b2e..62b6897 100644 --- a/documentation/smbclientng/core/InteractiveShell.html +++ b/documentation/smbclientng/core/InteractiveShell.html @@ -911,243 +911,277 @@

723 # SMB share needed : Yes 724 725 path = ' '.join(arguments) -726 if self.smbSession.path_exists(path): -727 if self.smbSession.path_isfile(path): -728 try: -729 self.smbSession.rm(path=path) -730 except Exception as e: -731 print("[!] Error removing file '%s' : %s" % path) -732 else: -733 print("[!] Cannot delete '%s': This is a directory, use 'rmdir <directory>' instead." % path) -734 else: -735 print("[!] Remote file '%s' does not exist." % path) -736 -737 @command_arguments_required -738 @active_smb_connection_needed -739 @smb_share_is_set -740 def command_rmdir(self, arguments, command): -741 # Command arguments required : Yes -742 # Active SMB connection needed : Yes -743 # SMB share needed : Yes -744 -745 path = ' '.join(arguments) -746 if self.smbSession.path_exists(path): -747 if self.smbSession.path_isdir(path): -748 try: -749 self.smbSession.rmdir(path=path) -750 except Exception as e: -751 print("[!] Error removing directory '%s' : %s" % path) -752 else: -753 print("[!] Cannot delete '%s': This is a file, use 'rm <file>' instead." % path) -754 else: -755 print("[!] Remote directory '%s' does not exist." % path) -756 -757 @active_smb_connection_needed -758 @smb_share_is_set -759 def command_sizeof(self, arguments, command): -760 # Command arguments required : Yes -761 # Active SMB connection needed : Yes -762 # SMB share needed : Yes -763 -764 class RecursiveSizeOfPrint(object): -765 def __init__(self, entry, smbSession, config): -766 self.entry = entry -767 self.config = config -768 self.smbSession = smbSession -769 self.size = 0 -770 -771 def update(self, entry, fullpath, depth): -772 self.size += entry.get_filesize() -773 self.print(end='\r') -774 -775 def print(self, end='\n'): -776 # -777 if self.entry.is_directory(): -778 if self.config.no_colors: -779 path = "%s\\" % self.entry.get_longname() -780 else: -781 path = "\x1b[1;96m%s\x1b[0m\\" % self.entry.get_longname() -782 # -783 else: -784 if self.config.no_colors: -785 path = "%s" % self.entry.get_longname() -786 else: -787 path = "\x1b[1m%s\x1b[0m" % self.entry.get_longname() -788 print("%10s %s" % (b_filesize(self.size), path), end=end) -789 -790 entries = [] -791 if len(arguments) == 0: -792 entries = self.smbSession.list_contents() -793 entries = [entry for name, entry in entries.items() if name not in ['.', '..']] -794 else: -795 entry = self.smbSession.get_entry(path=' '.join(arguments)) -796 entries = [] -797 if entry is not None: -798 entries = [entry] -799 else: -800 print("[!] Path '%s' does not exist." % ' '.join(arguments)) -801 -802 total = 0 -803 for entry in entries: -804 rsop = RecursiveSizeOfPrint(entry=entry, smbSession=self.smbSession, config=self.config) -805 # Directory -806 if entry.is_directory(): -807 self.smbSession.find( -808 paths=[entry.get_longname()], -809 callback=rsop.update -810 ) -811 # File -812 else: -813 rsop.update(entry=entry, fullpath=entry.get_longname(), depth=0) -814 # Close the print -815 rsop.print() -816 total += rsop.size -817 -818 if len(entries) > 1: -819 print("──────────────────────") -820 print(" total %s" % b_filesize(total)) -821 -822 @active_smb_connection_needed -823 def command_shares(self, arguments, command): -824 # Command arguments required : No -825 # Active SMB connection needed : Yes -826 # SMB share needed : No -827 -828 shares = self.smbSession.list_shares() -829 if len(shares.keys()) != 0: -830 table = Table(title=None) -831 table.add_column("Share") -832 table.add_column("Hidden") -833 table.add_column("Type") -834 table.add_column("Description", justify="left") -835 -836 for sharename in sorted(shares.keys()): -837 is_hidden = bool(sharename.endswith('$')) -838 types = ', '.join([s.replace("STYPE_","") for s in shares[sharename]["type"]]) -839 if is_hidden: -840 table.add_row(shares[sharename]["name"], str(is_hidden), types, shares[sharename]["comment"]) -841 else: -842 table.add_row(shares[sharename]["name"], str(is_hidden), types, shares[sharename]["comment"]) -843 -844 Console().print(table) -845 else: -846 print("[!] No share served on '%s'" % self.smbSession.address) +726 if '*' in path: +727 self.smbSession.rm(path=path) +728 elif self.smbSession.path_exists(path): +729 if self.smbSession.path_isfile(path): +730 try: +731 self.smbSession.rm(path=path) +732 except Exception as e: +733 print("[!] Error removing file '%s' : %s" % path) +734 else: +735 print("[!] Cannot delete '%s': This is a directory, use 'rmdir <directory>' instead." % path) +736 else: +737 print("[!] Remote file '%s' does not exist." % path) +738 +739 @command_arguments_required +740 @active_smb_connection_needed +741 @smb_share_is_set +742 def command_rmdir(self, arguments, command): +743 # Command arguments required : Yes +744 # Active SMB connection needed : Yes +745 # SMB share needed : Yes +746 +747 path = ' '.join(arguments) +748 if self.smbSession.path_exists(path): +749 if self.smbSession.path_isdir(path): +750 try: +751 self.smbSession.rmdir(path=path) +752 except Exception as e: +753 print("[!] Error removing directory '%s' : %s" % path) +754 else: +755 print("[!] Cannot delete '%s': This is a file, use 'rm <file>' instead." % path) +756 else: +757 print("[!] Remote directory '%s' does not exist." % path) +758 +759 @active_smb_connection_needed +760 @smb_share_is_set +761 def command_sizeof(self, arguments, command): +762 # Command arguments required : Yes +763 # Active SMB connection needed : Yes +764 # SMB share needed : Yes +765 +766 class RecursiveSizeOfPrint(object): +767 def __init__(self, entry, smbSession, config): +768 self.entry = entry +769 self.config = config +770 self.smbSession = smbSession +771 self.size = 0 +772 +773 def update(self, entry, fullpath, depth): +774 self.size += entry.get_filesize() +775 self.print(end='\r') +776 +777 def print(self, end='\n'): +778 # +779 if self.entry.is_directory(): +780 if self.config.no_colors: +781 path = "%s\\" % self.entry.get_longname() +782 else: +783 path = "\x1b[1;96m%s\x1b[0m\\" % self.entry.get_longname() +784 # +785 else: +786 if self.config.no_colors: +787 path = "%s" % self.entry.get_longname() +788 else: +789 path = "\x1b[1m%s\x1b[0m" % self.entry.get_longname() +790 print("%10s %s" % (b_filesize(self.size), path), end=end) +791 +792 entries = [] +793 if len(arguments) == 0: +794 entries = self.smbSession.list_contents() +795 entries = [entry for name, entry in entries.items() if name not in ['.', '..']] +796 else: +797 entry = self.smbSession.get_entry(path=' '.join(arguments)) +798 entries = [] +799 if entry is not None: +800 entries = [entry] +801 else: +802 print("[!] Path '%s' does not exist." % ' '.join(arguments)) +803 +804 total = 0 +805 for entry in entries: +806 rsop = RecursiveSizeOfPrint(entry=entry, smbSession=self.smbSession, config=self.config) +807 # Directory +808 if entry.is_directory(): +809 self.smbSession.find( +810 paths=[entry.get_longname()], +811 callback=rsop.update +812 ) +813 # File +814 else: +815 rsop.update(entry=entry, fullpath=entry.get_longname(), depth=0) +816 # Close the print +817 rsop.print() +818 total += rsop.size +819 +820 if len(entries) > 1: +821 print("──────────────────────") +822 print(" total %s" % b_filesize(total)) +823 +824 @active_smb_connection_needed +825 def command_shares(self, arguments, command): +826 # Command arguments required : No +827 # Active SMB connection needed : Yes +828 # SMB share needed : No +829 +830 do_check_rights = False +831 if len(arguments) != 0: +832 if arguments[0] == "rights": +833 do_check_rights = True +834 +835 shares = self.smbSession.list_shares() +836 if len(shares.keys()) != 0: +837 table = Table(title=None) +838 table.add_column("Share") +839 table.add_column("Visibility") +840 table.add_column("Type") +841 table.add_column("Description", justify="left") +842 if do_check_rights: +843 table.add_column("Rights") +844 +845 for sharename in sorted(shares.keys()): +846 types = ', '.join([s.replace("STYPE_","") for s in shares[sharename]["type"]]) 847 -848 @active_smb_connection_needed -849 @smb_share_is_set -850 def command_tree(self, arguments, command): -851 # Command arguments required : No -852 # Active SMB connection needed : Yes -853 # SMB share needed : Yes -854 -855 if len(arguments) == 0: -856 self.smbSession.tree(path='.') -857 else: -858 self.smbSession.tree(path=' '.join(arguments)) +848 is_hidden = bool(sharename.endswith('$')) +849 if is_hidden: +850 str_hidden = "[bold bright_blue]Hidden[/bold bright_blue]" +851 str_sharename = "[bold bright_blue]" + shares[sharename]["name"] + "[/bold bright_blue]" +852 str_types = "[bold bright_blue]" + types + "[/bold bright_blue]" +853 str_comment = "[bold bright_blue]" + shares[sharename]["comment"] + "[/bold bright_blue]" +854 else: +855 str_hidden = "[bold bright_yellow]Visible[/bold bright_yellow]" +856 str_sharename = "[bold bright_yellow]" + shares[sharename]["name"] + "[/bold bright_yellow]" +857 str_types = "[bold bright_yellow]" + types + "[/bold bright_yellow]" +858 str_comment = "[bold bright_yellow]" + shares[sharename]["comment"] + "[/bold bright_yellow]" 859 -860 @command_arguments_required -861 @active_smb_connection_needed -862 @smb_share_is_set -863 def command_umount(self, arguments, command): -864 # Command arguments required : Yes -865 # Active SMB connection needed : Yes -866 # SMB share needed : Yes -867 -868 local_mount_point = arguments[0] -869 -870 if self.config.debug: -871 print("[debug] Trying to unmount local mount point '%s'" % (local_mount_point)) -872 -873 self.smbSession.umount(local_mount_point) -874 -875 @command_arguments_required -876 @active_smb_connection_needed -877 def command_use(self, arguments, command): -878 # Command arguments required : Yes -879 # Active SMB connection needed : Yes -880 # SMB share needed : No +860 if do_check_rights: +861 access_rights = self.smbSession.test_rights(sharename=shares[sharename]["name"]) +862 str_access_rights = "[bold yellow]NO ACCESS[/bold yellow]" +863 if access_rights["readable"] and access_rights["writable"]: +864 str_access_rights = "[bold green]READ[/bold green], [bold red]WRITE[/bold red]" +865 elif access_rights["readable"]: +866 str_access_rights = "[bold green]READ[/bold green]" +867 elif access_rights["writable"]: +868 # Without READ?? This should not happen IMHO +869 str_access_rights = "[bold red]WRITE[/bold red]" +870 else: +871 str_access_rights = "[bold yellow]NO ACCESS[/bold yellow]" +872 +873 if do_check_rights: +874 table.add_row(str_sharename, str_hidden, str_types, str_comment, str_access_rights) +875 else: +876 table.add_row(str_sharename, str_hidden, str_types, str_comment) +877 +878 Console().print(table) +879 else: +880 print("[!] No share served on '%s'" % self.smbSession.address) 881 -882 sharename = ' '.join(arguments) -883 # Reload the list of shares -884 shares = self.smbSession.list_shares() -885 shares = [s.lower() for s in shares.keys()] -886 if sharename.lower() in shares: -887 self.smbSession.set_share(sharename) -888 else: -889 print("[!] No share named '%s' on '%s'" % (sharename, self.smbSession.address)) -890 -891 # Private functions ======================================================= -892 -893 def __load_modules(self): -894 -895 self.modules.clear() -896 -897 modules_dir = os.path.normpath(os.path.dirname(__file__) + os.path.sep + ".." + os.path.sep + "modules") -898 if self.config.debug: -899 print("[debug] Loading modules from %s ..." % modules_dir) -900 sys.path.extend([modules_dir]) +882 @active_smb_connection_needed +883 @smb_share_is_set +884 def command_tree(self, arguments, command): +885 # Command arguments required : No +886 # Active SMB connection needed : Yes +887 # SMB share needed : Yes +888 +889 if len(arguments) == 0: +890 self.smbSession.tree(path='.') +891 else: +892 self.smbSession.tree(path=' '.join(arguments)) +893 +894 @command_arguments_required +895 @active_smb_connection_needed +896 @smb_share_is_set +897 def command_umount(self, arguments, command): +898 # Command arguments required : Yes +899 # Active SMB connection needed : Yes +900 # SMB share needed : Yes 901 -902 for file in os.listdir(modules_dir): -903 filepath = os.path.normpath(modules_dir + os.path.sep + file) -904 if file.endswith('.py'): -905 if os.path.isfile(filepath) and file not in ["__init__.py"]: -906 try: -907 module_file = import_module('smbclientng.modules.%s' % (file[:-3])) -908 module = module_file.__getattribute__(file[:-3]) -909 self.modules[module.name.lower()] = module -910 except AttributeError as e: -911 pass -912 -913 if self.config.debug: -914 if len(self.modules.keys()) == 0: -915 print("[debug] Loaded 0 modules.") -916 elif len(self.modules.keys()) == 1: -917 print("[debug] Loaded 1 module:") -918 else: -919 print("[debug] Loaded %d modules:" % len(self.modules.keys())) -920 for modulename in sorted(self.modules.keys()): -921 print("[debug] %s : \"%s\" (%s)" % (self.modules[modulename].name, self.modules[modulename].description, self.modules[modulename])) -922 -923 if self.commandCompleterObject is not None: -924 self.commandCompleterObject.commands["module"]["subcommands"] = list(self.modules.keys()) -925 -926 def __prompt(self): -927 """ -928 Prints the command prompt for the interactive shell. -929 -930 This method constructs and returns the command prompt string based on the current state of the SMB session. -931 The prompt indicates the connection status with a visual symbol and displays the current working directory -932 or the SMB share path. The prompt appearance changes based on whether colors are enabled in the configuration. -933 -934 Returns: -935 str: The formatted command prompt string. -936 """ -937 -938 self.smbSession.ping_smb_session() -939 if self.smbSession.connected: -940 if self.config.no_colors: -941 connected_dot = "[v]" -942 else: -943 connected_dot = "\x1b[1;92m⏺\x1b[0m" -944 else: -945 if self.config.no_colors: -946 connected_dot = "[x]" -947 else: -948 connected_dot = "\x1b[1;91m⏺\x1b[0m" -949 -950 if self.smbSession.smb_share is None: -951 if self.config.no_colors: -952 str_prompt = "%s[\\\\%s\\]> " % (connected_dot, self.smbSession.address) -953 else: -954 str_prompt = "%s[\x1b[1;94m\\\\%s\\\x1b[0m]> " % (connected_dot, self.smbSession.address) -955 else: -956 str_path = "\\\\%s\\%s\\%s" % (self.smbSession.address, self.smbSession.smb_share, self.smbSession.smb_cwd.lstrip(ntpath.sep)) -957 if self.config.no_colors: -958 str_prompt = "%s[%s]> " % (connected_dot, str_path) -959 else: -960 str_prompt = "%s[\x1b[1;94m%s\x1b[0m]> " % (connected_dot, str_path) -961 -962 return str_prompt +902 local_mount_point = arguments[0] +903 +904 if self.config.debug: +905 print("[debug] Trying to unmount local mount point '%s'" % (local_mount_point)) +906 +907 self.smbSession.umount(local_mount_point) +908 +909 @command_arguments_required +910 @active_smb_connection_needed +911 def command_use(self, arguments, command): +912 # Command arguments required : Yes +913 # Active SMB connection needed : Yes +914 # SMB share needed : No +915 +916 sharename = ' '.join(arguments) +917 # Reload the list of shares +918 shares = self.smbSession.list_shares() +919 shares = [s.lower() for s in shares.keys()] +920 if sharename.lower() in shares: +921 self.smbSession.set_share(sharename) +922 else: +923 print("[!] No share named '%s' on '%s'" % (sharename, self.smbSession.address)) +924 +925 # Private functions ======================================================= +926 +927 def __load_modules(self): +928 +929 self.modules.clear() +930 +931 modules_dir = os.path.normpath(os.path.dirname(__file__) + os.path.sep + ".." + os.path.sep + "modules") +932 if self.config.debug: +933 print("[debug] Loading modules from %s ..." % modules_dir) +934 sys.path.extend([modules_dir]) +935 +936 for file in os.listdir(modules_dir): +937 filepath = os.path.normpath(modules_dir + os.path.sep + file) +938 if file.endswith('.py'): +939 if os.path.isfile(filepath) and file not in ["__init__.py"]: +940 try: +941 module_file = import_module('smbclientng.modules.%s' % (file[:-3])) +942 module = module_file.__getattribute__(file[:-3]) +943 self.modules[module.name.lower()] = module +944 except AttributeError as e: +945 pass +946 +947 if self.config.debug: +948 if len(self.modules.keys()) == 0: +949 print("[debug] Loaded 0 modules.") +950 elif len(self.modules.keys()) == 1: +951 print("[debug] Loaded 1 module:") +952 else: +953 print("[debug] Loaded %d modules:" % len(self.modules.keys())) +954 for modulename in sorted(self.modules.keys()): +955 print("[debug] %s : \"%s\" (%s)" % (self.modules[modulename].name, self.modules[modulename].description, self.modules[modulename])) +956 +957 if self.commandCompleterObject is not None: +958 self.commandCompleterObject.commands["module"]["subcommands"] = list(self.modules.keys()) +959 +960 def __prompt(self): +961 """ +962 Prints the command prompt for the interactive shell. +963 +964 This method constructs and returns the command prompt string based on the current state of the SMB session. +965 The prompt indicates the connection status with a visual symbol and displays the current working directory +966 or the SMB share path. The prompt appearance changes based on whether colors are enabled in the configuration. +967 +968 Returns: +969 str: The formatted command prompt string. +970 """ +971 +972 self.smbSession.ping_smb_session() +973 if self.smbSession.connected: +974 if self.config.no_colors: +975 connected_dot = "[v]" +976 else: +977 connected_dot = "\x1b[1;92m⏺\x1b[0m" +978 else: +979 if self.config.no_colors: +980 connected_dot = "[x]" +981 else: +982 connected_dot = "\x1b[1;91m⏺\x1b[0m" +983 +984 if self.smbSession.smb_share is None: +985 if self.config.no_colors: +986 str_prompt = "%s[\\\\%s\\]> " % (connected_dot, self.smbSession.address) +987 else: +988 str_prompt = "%s[\x1b[1;94m\\\\%s\\\x1b[0m]> " % (connected_dot, self.smbSession.address) +989 else: +990 str_path = "\\\\%s\\%s\\%s" % (self.smbSession.address, self.smbSession.smb_share, self.smbSession.smb_cwd.lstrip(ntpath.sep)) +991 if self.config.no_colors: +992 str_prompt = "%s[%s]> " % (connected_dot, str_path) +993 else: +994 str_prompt = "%s[\x1b[1;94m%s\x1b[0m]> " % (connected_dot, str_path) +995 +996 return str_prompt @@ -1909,243 +1943,277 @@

724 # SMB share needed : Yes 725 726 path = ' '.join(arguments) -727 if self.smbSession.path_exists(path): -728 if self.smbSession.path_isfile(path): -729 try: -730 self.smbSession.rm(path=path) -731 except Exception as e: -732 print("[!] Error removing file '%s' : %s" % path) -733 else: -734 print("[!] Cannot delete '%s': This is a directory, use 'rmdir <directory>' instead." % path) -735 else: -736 print("[!] Remote file '%s' does not exist." % path) -737 -738 @command_arguments_required -739 @active_smb_connection_needed -740 @smb_share_is_set -741 def command_rmdir(self, arguments, command): -742 # Command arguments required : Yes -743 # Active SMB connection needed : Yes -744 # SMB share needed : Yes -745 -746 path = ' '.join(arguments) -747 if self.smbSession.path_exists(path): -748 if self.smbSession.path_isdir(path): -749 try: -750 self.smbSession.rmdir(path=path) -751 except Exception as e: -752 print("[!] Error removing directory '%s' : %s" % path) -753 else: -754 print("[!] Cannot delete '%s': This is a file, use 'rm <file>' instead." % path) -755 else: -756 print("[!] Remote directory '%s' does not exist." % path) -757 -758 @active_smb_connection_needed -759 @smb_share_is_set -760 def command_sizeof(self, arguments, command): -761 # Command arguments required : Yes -762 # Active SMB connection needed : Yes -763 # SMB share needed : Yes -764 -765 class RecursiveSizeOfPrint(object): -766 def __init__(self, entry, smbSession, config): -767 self.entry = entry -768 self.config = config -769 self.smbSession = smbSession -770 self.size = 0 -771 -772 def update(self, entry, fullpath, depth): -773 self.size += entry.get_filesize() -774 self.print(end='\r') -775 -776 def print(self, end='\n'): -777 # -778 if self.entry.is_directory(): -779 if self.config.no_colors: -780 path = "%s\\" % self.entry.get_longname() -781 else: -782 path = "\x1b[1;96m%s\x1b[0m\\" % self.entry.get_longname() -783 # -784 else: -785 if self.config.no_colors: -786 path = "%s" % self.entry.get_longname() -787 else: -788 path = "\x1b[1m%s\x1b[0m" % self.entry.get_longname() -789 print("%10s %s" % (b_filesize(self.size), path), end=end) -790 -791 entries = [] -792 if len(arguments) == 0: -793 entries = self.smbSession.list_contents() -794 entries = [entry for name, entry in entries.items() if name not in ['.', '..']] -795 else: -796 entry = self.smbSession.get_entry(path=' '.join(arguments)) -797 entries = [] -798 if entry is not None: -799 entries = [entry] -800 else: -801 print("[!] Path '%s' does not exist." % ' '.join(arguments)) -802 -803 total = 0 -804 for entry in entries: -805 rsop = RecursiveSizeOfPrint(entry=entry, smbSession=self.smbSession, config=self.config) -806 # Directory -807 if entry.is_directory(): -808 self.smbSession.find( -809 paths=[entry.get_longname()], -810 callback=rsop.update -811 ) -812 # File -813 else: -814 rsop.update(entry=entry, fullpath=entry.get_longname(), depth=0) -815 # Close the print -816 rsop.print() -817 total += rsop.size -818 -819 if len(entries) > 1: -820 print("──────────────────────") -821 print(" total %s" % b_filesize(total)) -822 -823 @active_smb_connection_needed -824 def command_shares(self, arguments, command): -825 # Command arguments required : No -826 # Active SMB connection needed : Yes -827 # SMB share needed : No -828 -829 shares = self.smbSession.list_shares() -830 if len(shares.keys()) != 0: -831 table = Table(title=None) -832 table.add_column("Share") -833 table.add_column("Hidden") -834 table.add_column("Type") -835 table.add_column("Description", justify="left") -836 -837 for sharename in sorted(shares.keys()): -838 is_hidden = bool(sharename.endswith('$')) -839 types = ', '.join([s.replace("STYPE_","") for s in shares[sharename]["type"]]) -840 if is_hidden: -841 table.add_row(shares[sharename]["name"], str(is_hidden), types, shares[sharename]["comment"]) -842 else: -843 table.add_row(shares[sharename]["name"], str(is_hidden), types, shares[sharename]["comment"]) -844 -845 Console().print(table) -846 else: -847 print("[!] No share served on '%s'" % self.smbSession.address) +727 if '*' in path: +728 self.smbSession.rm(path=path) +729 elif self.smbSession.path_exists(path): +730 if self.smbSession.path_isfile(path): +731 try: +732 self.smbSession.rm(path=path) +733 except Exception as e: +734 print("[!] Error removing file '%s' : %s" % path) +735 else: +736 print("[!] Cannot delete '%s': This is a directory, use 'rmdir <directory>' instead." % path) +737 else: +738 print("[!] Remote file '%s' does not exist." % path) +739 +740 @command_arguments_required +741 @active_smb_connection_needed +742 @smb_share_is_set +743 def command_rmdir(self, arguments, command): +744 # Command arguments required : Yes +745 # Active SMB connection needed : Yes +746 # SMB share needed : Yes +747 +748 path = ' '.join(arguments) +749 if self.smbSession.path_exists(path): +750 if self.smbSession.path_isdir(path): +751 try: +752 self.smbSession.rmdir(path=path) +753 except Exception as e: +754 print("[!] Error removing directory '%s' : %s" % path) +755 else: +756 print("[!] Cannot delete '%s': This is a file, use 'rm <file>' instead." % path) +757 else: +758 print("[!] Remote directory '%s' does not exist." % path) +759 +760 @active_smb_connection_needed +761 @smb_share_is_set +762 def command_sizeof(self, arguments, command): +763 # Command arguments required : Yes +764 # Active SMB connection needed : Yes +765 # SMB share needed : Yes +766 +767 class RecursiveSizeOfPrint(object): +768 def __init__(self, entry, smbSession, config): +769 self.entry = entry +770 self.config = config +771 self.smbSession = smbSession +772 self.size = 0 +773 +774 def update(self, entry, fullpath, depth): +775 self.size += entry.get_filesize() +776 self.print(end='\r') +777 +778 def print(self, end='\n'): +779 # +780 if self.entry.is_directory(): +781 if self.config.no_colors: +782 path = "%s\\" % self.entry.get_longname() +783 else: +784 path = "\x1b[1;96m%s\x1b[0m\\" % self.entry.get_longname() +785 # +786 else: +787 if self.config.no_colors: +788 path = "%s" % self.entry.get_longname() +789 else: +790 path = "\x1b[1m%s\x1b[0m" % self.entry.get_longname() +791 print("%10s %s" % (b_filesize(self.size), path), end=end) +792 +793 entries = [] +794 if len(arguments) == 0: +795 entries = self.smbSession.list_contents() +796 entries = [entry for name, entry in entries.items() if name not in ['.', '..']] +797 else: +798 entry = self.smbSession.get_entry(path=' '.join(arguments)) +799 entries = [] +800 if entry is not None: +801 entries = [entry] +802 else: +803 print("[!] Path '%s' does not exist." % ' '.join(arguments)) +804 +805 total = 0 +806 for entry in entries: +807 rsop = RecursiveSizeOfPrint(entry=entry, smbSession=self.smbSession, config=self.config) +808 # Directory +809 if entry.is_directory(): +810 self.smbSession.find( +811 paths=[entry.get_longname()], +812 callback=rsop.update +813 ) +814 # File +815 else: +816 rsop.update(entry=entry, fullpath=entry.get_longname(), depth=0) +817 # Close the print +818 rsop.print() +819 total += rsop.size +820 +821 if len(entries) > 1: +822 print("──────────────────────") +823 print(" total %s" % b_filesize(total)) +824 +825 @active_smb_connection_needed +826 def command_shares(self, arguments, command): +827 # Command arguments required : No +828 # Active SMB connection needed : Yes +829 # SMB share needed : No +830 +831 do_check_rights = False +832 if len(arguments) != 0: +833 if arguments[0] == "rights": +834 do_check_rights = True +835 +836 shares = self.smbSession.list_shares() +837 if len(shares.keys()) != 0: +838 table = Table(title=None) +839 table.add_column("Share") +840 table.add_column("Visibility") +841 table.add_column("Type") +842 table.add_column("Description", justify="left") +843 if do_check_rights: +844 table.add_column("Rights") +845 +846 for sharename in sorted(shares.keys()): +847 types = ', '.join([s.replace("STYPE_","") for s in shares[sharename]["type"]]) 848 -849 @active_smb_connection_needed -850 @smb_share_is_set -851 def command_tree(self, arguments, command): -852 # Command arguments required : No -853 # Active SMB connection needed : Yes -854 # SMB share needed : Yes -855 -856 if len(arguments) == 0: -857 self.smbSession.tree(path='.') -858 else: -859 self.smbSession.tree(path=' '.join(arguments)) +849 is_hidden = bool(sharename.endswith('$')) +850 if is_hidden: +851 str_hidden = "[bold bright_blue]Hidden[/bold bright_blue]" +852 str_sharename = "[bold bright_blue]" + shares[sharename]["name"] + "[/bold bright_blue]" +853 str_types = "[bold bright_blue]" + types + "[/bold bright_blue]" +854 str_comment = "[bold bright_blue]" + shares[sharename]["comment"] + "[/bold bright_blue]" +855 else: +856 str_hidden = "[bold bright_yellow]Visible[/bold bright_yellow]" +857 str_sharename = "[bold bright_yellow]" + shares[sharename]["name"] + "[/bold bright_yellow]" +858 str_types = "[bold bright_yellow]" + types + "[/bold bright_yellow]" +859 str_comment = "[bold bright_yellow]" + shares[sharename]["comment"] + "[/bold bright_yellow]" 860 -861 @command_arguments_required -862 @active_smb_connection_needed -863 @smb_share_is_set -864 def command_umount(self, arguments, command): -865 # Command arguments required : Yes -866 # Active SMB connection needed : Yes -867 # SMB share needed : Yes -868 -869 local_mount_point = arguments[0] -870 -871 if self.config.debug: -872 print("[debug] Trying to unmount local mount point '%s'" % (local_mount_point)) -873 -874 self.smbSession.umount(local_mount_point) -875 -876 @command_arguments_required -877 @active_smb_connection_needed -878 def command_use(self, arguments, command): -879 # Command arguments required : Yes -880 # Active SMB connection needed : Yes -881 # SMB share needed : No +861 if do_check_rights: +862 access_rights = self.smbSession.test_rights(sharename=shares[sharename]["name"]) +863 str_access_rights = "[bold yellow]NO ACCESS[/bold yellow]" +864 if access_rights["readable"] and access_rights["writable"]: +865 str_access_rights = "[bold green]READ[/bold green], [bold red]WRITE[/bold red]" +866 elif access_rights["readable"]: +867 str_access_rights = "[bold green]READ[/bold green]" +868 elif access_rights["writable"]: +869 # Without READ?? This should not happen IMHO +870 str_access_rights = "[bold red]WRITE[/bold red]" +871 else: +872 str_access_rights = "[bold yellow]NO ACCESS[/bold yellow]" +873 +874 if do_check_rights: +875 table.add_row(str_sharename, str_hidden, str_types, str_comment, str_access_rights) +876 else: +877 table.add_row(str_sharename, str_hidden, str_types, str_comment) +878 +879 Console().print(table) +880 else: +881 print("[!] No share served on '%s'" % self.smbSession.address) 882 -883 sharename = ' '.join(arguments) -884 # Reload the list of shares -885 shares = self.smbSession.list_shares() -886 shares = [s.lower() for s in shares.keys()] -887 if sharename.lower() in shares: -888 self.smbSession.set_share(sharename) -889 else: -890 print("[!] No share named '%s' on '%s'" % (sharename, self.smbSession.address)) -891 -892 # Private functions ======================================================= -893 -894 def __load_modules(self): -895 -896 self.modules.clear() -897 -898 modules_dir = os.path.normpath(os.path.dirname(__file__) + os.path.sep + ".." + os.path.sep + "modules") -899 if self.config.debug: -900 print("[debug] Loading modules from %s ..." % modules_dir) -901 sys.path.extend([modules_dir]) +883 @active_smb_connection_needed +884 @smb_share_is_set +885 def command_tree(self, arguments, command): +886 # Command arguments required : No +887 # Active SMB connection needed : Yes +888 # SMB share needed : Yes +889 +890 if len(arguments) == 0: +891 self.smbSession.tree(path='.') +892 else: +893 self.smbSession.tree(path=' '.join(arguments)) +894 +895 @command_arguments_required +896 @active_smb_connection_needed +897 @smb_share_is_set +898 def command_umount(self, arguments, command): +899 # Command arguments required : Yes +900 # Active SMB connection needed : Yes +901 # SMB share needed : Yes 902 -903 for file in os.listdir(modules_dir): -904 filepath = os.path.normpath(modules_dir + os.path.sep + file) -905 if file.endswith('.py'): -906 if os.path.isfile(filepath) and file not in ["__init__.py"]: -907 try: -908 module_file = import_module('smbclientng.modules.%s' % (file[:-3])) -909 module = module_file.__getattribute__(file[:-3]) -910 self.modules[module.name.lower()] = module -911 except AttributeError as e: -912 pass -913 -914 if self.config.debug: -915 if len(self.modules.keys()) == 0: -916 print("[debug] Loaded 0 modules.") -917 elif len(self.modules.keys()) == 1: -918 print("[debug] Loaded 1 module:") -919 else: -920 print("[debug] Loaded %d modules:" % len(self.modules.keys())) -921 for modulename in sorted(self.modules.keys()): -922 print("[debug] %s : \"%s\" (%s)" % (self.modules[modulename].name, self.modules[modulename].description, self.modules[modulename])) -923 -924 if self.commandCompleterObject is not None: -925 self.commandCompleterObject.commands["module"]["subcommands"] = list(self.modules.keys()) -926 -927 def __prompt(self): -928 """ -929 Prints the command prompt for the interactive shell. -930 -931 This method constructs and returns the command prompt string based on the current state of the SMB session. -932 The prompt indicates the connection status with a visual symbol and displays the current working directory -933 or the SMB share path. The prompt appearance changes based on whether colors are enabled in the configuration. -934 -935 Returns: -936 str: The formatted command prompt string. -937 """ -938 -939 self.smbSession.ping_smb_session() -940 if self.smbSession.connected: -941 if self.config.no_colors: -942 connected_dot = "[v]" -943 else: -944 connected_dot = "\x1b[1;92m⏺\x1b[0m" -945 else: -946 if self.config.no_colors: -947 connected_dot = "[x]" -948 else: -949 connected_dot = "\x1b[1;91m⏺\x1b[0m" -950 -951 if self.smbSession.smb_share is None: -952 if self.config.no_colors: -953 str_prompt = "%s[\\\\%s\\]> " % (connected_dot, self.smbSession.address) -954 else: -955 str_prompt = "%s[\x1b[1;94m\\\\%s\\\x1b[0m]> " % (connected_dot, self.smbSession.address) -956 else: -957 str_path = "\\\\%s\\%s\\%s" % (self.smbSession.address, self.smbSession.smb_share, self.smbSession.smb_cwd.lstrip(ntpath.sep)) -958 if self.config.no_colors: -959 str_prompt = "%s[%s]> " % (connected_dot, str_path) -960 else: -961 str_prompt = "%s[\x1b[1;94m%s\x1b[0m]> " % (connected_dot, str_path) -962 -963 return str_prompt +903 local_mount_point = arguments[0] +904 +905 if self.config.debug: +906 print("[debug] Trying to unmount local mount point '%s'" % (local_mount_point)) +907 +908 self.smbSession.umount(local_mount_point) +909 +910 @command_arguments_required +911 @active_smb_connection_needed +912 def command_use(self, arguments, command): +913 # Command arguments required : Yes +914 # Active SMB connection needed : Yes +915 # SMB share needed : No +916 +917 sharename = ' '.join(arguments) +918 # Reload the list of shares +919 shares = self.smbSession.list_shares() +920 shares = [s.lower() for s in shares.keys()] +921 if sharename.lower() in shares: +922 self.smbSession.set_share(sharename) +923 else: +924 print("[!] No share named '%s' on '%s'" % (sharename, self.smbSession.address)) +925 +926 # Private functions ======================================================= +927 +928 def __load_modules(self): +929 +930 self.modules.clear() +931 +932 modules_dir = os.path.normpath(os.path.dirname(__file__) + os.path.sep + ".." + os.path.sep + "modules") +933 if self.config.debug: +934 print("[debug] Loading modules from %s ..." % modules_dir) +935 sys.path.extend([modules_dir]) +936 +937 for file in os.listdir(modules_dir): +938 filepath = os.path.normpath(modules_dir + os.path.sep + file) +939 if file.endswith('.py'): +940 if os.path.isfile(filepath) and file not in ["__init__.py"]: +941 try: +942 module_file = import_module('smbclientng.modules.%s' % (file[:-3])) +943 module = module_file.__getattribute__(file[:-3]) +944 self.modules[module.name.lower()] = module +945 except AttributeError as e: +946 pass +947 +948 if self.config.debug: +949 if len(self.modules.keys()) == 0: +950 print("[debug] Loaded 0 modules.") +951 elif len(self.modules.keys()) == 1: +952 print("[debug] Loaded 1 module:") +953 else: +954 print("[debug] Loaded %d modules:" % len(self.modules.keys())) +955 for modulename in sorted(self.modules.keys()): +956 print("[debug] %s : \"%s\" (%s)" % (self.modules[modulename].name, self.modules[modulename].description, self.modules[modulename])) +957 +958 if self.commandCompleterObject is not None: +959 self.commandCompleterObject.commands["module"]["subcommands"] = list(self.modules.keys()) +960 +961 def __prompt(self): +962 """ +963 Prints the command prompt for the interactive shell. +964 +965 This method constructs and returns the command prompt string based on the current state of the SMB session. +966 The prompt indicates the connection status with a visual symbol and displays the current working directory +967 or the SMB share path. The prompt appearance changes based on whether colors are enabled in the configuration. +968 +969 Returns: +970 str: The formatted command prompt string. +971 """ +972 +973 self.smbSession.ping_smb_session() +974 if self.smbSession.connected: +975 if self.config.no_colors: +976 connected_dot = "[v]" +977 else: +978 connected_dot = "\x1b[1;92m⏺\x1b[0m" +979 else: +980 if self.config.no_colors: +981 connected_dot = "[x]" +982 else: +983 connected_dot = "\x1b[1;91m⏺\x1b[0m" +984 +985 if self.smbSession.smb_share is None: +986 if self.config.no_colors: +987 str_prompt = "%s[\\\\%s\\]> " % (connected_dot, self.smbSession.address) +988 else: +989 str_prompt = "%s[\x1b[1;94m\\\\%s\\\x1b[0m]> " % (connected_dot, self.smbSession.address) +990 else: +991 str_path = "\\\\%s\\%s\\%s" % (self.smbSession.address, self.smbSession.smb_share, self.smbSession.smb_cwd.lstrip(ntpath.sep)) +992 if self.config.no_colors: +993 str_prompt = "%s[%s]> " % (connected_dot, str_path) +994 else: +995 str_prompt = "%s[\x1b[1;94m%s\x1b[0m]> " % (connected_dot, str_path) +996 +997 return str_prompt diff --git a/documentation/smbclientng/core/SMBSession.html b/documentation/smbclientng/core/SMBSession.html index 8a2ff4a..96605e1 100644 --- a/documentation/smbclientng/core/SMBSession.html +++ b/documentation/smbclientng/core/SMBSession.html @@ -147,6 +147,9 @@

API Documentation

  • umount
  • +
  • + test_rights +
  • set_share
  • @@ -188,1074 +191,1232 @@

    9import impacket.smbconnection 10import ntpath 11import os - 12import re - 13import sys - 14import traceback - 15from smbclientng.core.LocalFileIO import LocalFileIO - 16from smbclientng.core.utils import b_filesize, STYPE_MASK - 17 + 12import random + 13import re + 14import sys + 15import traceback + 16from smbclientng.core.LocalFileIO import LocalFileIO + 17from smbclientng.core.utils import b_filesize, STYPE_MASK 18 - 19class SMBSession(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 - 46 def __init__(self, address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, config=None): - 47 super(SMBSession, self).__init__() - 48 # Objects - 49 self.config = config - 50 - 51 # Target server - 52 self.address = address - 53 - 54 # Credentials - 55 self.domain = domain - 56 self.username = username - 57 self.password = password - 58 self.lmhash = lmhash - 59 self.nthash = nthash - 60 self.use_kerberos = use_kerberos - 61 self.kdcHost = kdcHost - 62 - 63 self.smbClient = None - 64 self.connected = False - 65 - 66 self.available_shares = {} - 67 self.smb_share = None - 68 self.smb_cwd = "" - 69 self.smb_tree_id = None - 70 - 71 self.list_shares() - 72 - 73 # Connect and disconnect SMB session - 74 - 75 def init_smb_session(self): - 76 """ - 77 Initializes and establishes a session with the SMB server. - 78 - 79 This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration. - 80 It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization. - 81 - 82 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. - 83 - 84 Returns: - 85 bool: True if the connection and authentication are successful, False otherwise. - 86 """ - 87 - 88 self.connected = False - 89 - 90 if self.config.debug: - 91 print("[debug] [>] Connecting to remote SMB server '%s' ... " % self.address) - 92 try: - 93 self.smbClient = impacket.smbconnection.SMBConnection( - 94 remoteName=self.address, - 95 remoteHost=self.address, - 96 sess_port=int(445) - 97 ) - 98 except OSError as err: - 99 print("[!] %s" % err) - 100 self.smbClient = None - 101 - 102 if self.smbClient is not None: - 103 if self.use_kerberos: - 104 if self.config.debug: - 105 print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... " % (self.domain, self.username)) - 106 try: - 107 self.connected = self.smbClient.kerberosLogin( - 108 user=self.username, - 109 password=self.password, - 110 domain=self.domain, - 111 lmhash=self.lmhash, - 112 nthash=self.nthash, - 113 aesKey=self.aesKey, - 114 kdcHost=self.kdcHost - 115 ) - 116 except impacket.smbconnection.SessionError as err: - 117 if self.config.debug: - 118 traceback.print_exc() - 119 print("[!] Could not login: %s" % err) - 120 self.connected = False - 121 - 122 else: - 123 if self.config.debug: - 124 print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... " % (self.domain, self.username)) - 125 try: - 126 self.connected = self.smbClient.login( - 127 user=self.username, - 128 password=self.password, - 129 domain=self.domain, - 130 lmhash=self.lmhash, - 131 nthash=self.nthash - 132 ) - 133 except impacket.smbconnection.SessionError as err: - 134 if self.config.debug: - 135 traceback.print_exc() - 136 print("[!] Could not login: %s" % err) - 137 self.connected = False - 138 - 139 if self.connected: - 140 print("[+] Successfully authenticated to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username)) - 141 else: - 142 print("[!] Failed to authenticate to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username)) - 143 - 144 return self.connected - 145 - 146 def close_smb_session(self): - 147 """ - 148 Closes the current SMB session by disconnecting the SMB client. - 149 - 150 This method ensures that the SMB client connection is properly closed. It checks if the client is connected - 151 and if so, it closes the connection and resets the connection status. - 152 - 153 Raises: - 154 Exception: If the SMB client is not initialized or if there's an error during the disconnection process. - 155 """ - 156 - 157 if self.smbClient is not None: - 158 if self.connected: - 159 self.smbClient.close() - 160 self.connected = False - 161 if self.config.debug: - 162 print("[+] SMB connection closed successfully.") - 163 else: - 164 if self.config.debug: - 165 print("[!] No active SMB connection to close.") - 166 else: - 167 raise Exception("SMB client is not initialized.") - 168 - 169 # Operations - 170 - 171 def read_file(self, path=None): - 172 if self.path_isfile(path=path): - 173 tmp_file_path = self.smb_cwd + ntpath.sep + path - 174 matches = self.smbClient.listPath( - 175 shareName=self.smb_share, - 176 path=tmp_file_path - 177 ) - 178 - 179 fh = io.BytesIO() - 180 try: - 181 # opening the files in streams instead of mounting shares allows - 182 # for running the script from unprivileged containers - 183 self.smbClient.getFile(self.smb_share, tmp_file_path, fh.write) - 184 except impacket.smbconnection.SessionError as e: - 185 return None - 186 rawdata = fh.getvalue() - 187 fh.close() - 188 return rawdata - 189 else: - 190 print("[!] Remote path '%s' is not a file." % path) - 191 - 192 def find(self, paths=[], callback=None): - 193 def recurse_action(paths=[], depth=0, callback=None): - 194 if callback is None: - 195 return [] - 196 - 197 next_directories_to_explore = [] - 198 - 199 for path in paths: - 200 remote_smb_path = ntpath.normpath(self.smb_cwd + ntpath.sep + path) - 201 entries = [] - 202 - 203 try: - 204 entries = self.smbClient.listPath( - 205 shareName=self.smb_share, - 206 path=(remote_smb_path + ntpath.sep + '*') - 207 ) - 208 except impacket.smbconnection.SessionError as err: - 209 continue - 210 # Remove dot names - 211 entries = [e for e in entries if e.get_longname() not in [".", ".."]] - 212 # Sort the entries ignoring case - 213 entries = sorted(entries, key=lambda x:x.get_longname().lower()) - 214 - 215 for entry in entries: - 216 if entry.is_directory(): - 217 callback(entry, path + ntpath.sep + entry.get_longname() + ntpath.sep, depth) - 218 else: - 219 callback(entry, path + ntpath.sep + entry.get_longname(), depth) - 220 - 221 # Next directories to explore - 222 for entry in entries: - 223 if entry.is_directory(): - 224 next_directories_to_explore.append(path + ntpath.sep + entry.get_longname() + ntpath.sep) - 225 - 226 return next_directories_to_explore - 227 # - 228 if callback is not None: - 229 depth = 0 - 230 while len(paths) != 0: - 231 paths = recurse_action( - 232 paths=paths, - 233 depth=depth, - 234 callback=callback - 235 ) - 236 depth = depth + 1 - 237 else: - 238 print("[!] SMBSession.find(), callback function cannot be None.") - 239 - 240 def get_file(self, path=None, keepRemotePath=False): - 241 """ - 242 Retrieves a file from the specified path on the SMB share. - 243 - 244 This method attempts to retrieve a file from the given path within the currently connected SMB share. - 245 If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local - 246 file object and writing the contents of the remote file to it using the SMB client's getFile method. - 247 - 248 Parameters: - 249 path (str): The path of the file to retrieve. If None, uses the current smb_path. - 250 - 251 Returns: - 252 None - 253 """ - 254 - 255 tmp_file_path = self.smb_cwd + ntpath.sep + path - 256 matches = self.smbClient.listPath( - 257 shareName=self.smb_share, - 258 path=tmp_file_path - 259 ) - 260 - 261 for entry in matches: - 262 if entry.is_directory(): - 263 print("[>] Skipping '%s' because it is a directory." % tmp_file_path) - 264 else: - 265 try: - 266 if ntpath.sep in path: - 267 outputfile = ntpath.dirname(path) + ntpath.sep + entry.get_longname() - 268 else: - 269 outputfile = entry.get_longname() - 270 f = LocalFileIO( - 271 mode="wb", - 272 path=outputfile, - 273 expected_size=entry.get_filesize(), - 274 debug=self.config.debug, - 275 keepRemotePath=keepRemotePath - 276 ) - 277 self.smbClient.getFile( - 278 shareName=self.smb_share, - 279 pathName=tmp_file_path, - 280 callback=f.write - 281 ) - 282 f.close() - 283 except (BrokenPipeError, KeyboardInterrupt) as e: - 284 f.close() - 285 print("\x1b[v\x1b[o\r[!] Interrupted.") - 286 self.close_smb_session() - 287 self.init_smb_session() - 288 - 289 return None - 290 - 291 def get_file_recursively(self, path=None): - 292 """ - 293 Recursively retrieves files from a specified path on the SMB share. - 294 - 295 This method navigates through all directories starting from the given path, - 296 and downloads all files found. It handles directories recursively, ensuring - 297 that all nested files are retrieved. The method skips over directory entries - 298 and handles errors gracefully, attempting to continue the operation where possible. - 299 - 300 Parameters: - 301 path (str): The initial directory path from which to start the recursive file retrieval. - 302 If None, it starts from the root of the configured SMB share. - 303 """ - 304 - 305 def recurse_action(base_dir="", path=[]): - 306 if len(base_dir) == 0: - 307 remote_smb_path = ntpath.sep.join(path) - 308 else: - 309 remote_smb_path = base_dir + ntpath.sep + ntpath.sep.join(path) - 310 remote_smb_path = ntpath.normpath(remote_smb_path) - 311 - 312 entries = self.smbClient.listPath( - 313 shareName=self.smb_share, - 314 path=remote_smb_path + '\\*' - 315 ) - 316 if len(entries) != 0: - 317 files = [entry for entry in entries if not entry.is_directory()] - 318 directories = [entry for entry in entries if entry.is_directory() and entry.get_longname() not in [".", ".."]] - 319 - 320 # Files - 321 if len(files) != 0: - 322 print("[>] Retrieving files of '%s'" % remote_smb_path) - 323 for entry_file in files: - 324 if not entry_file.is_directory(): - 325 f = LocalFileIO( - 326 mode="wb", - 327 path=remote_smb_path + ntpath.sep + entry_file.get_longname(), - 328 expected_size=entry_file.get_filesize(), - 329 keepRemotePath=True, - 330 debug=self.config.debug - 331 ) - 332 try: - 333 self.smbClient.getFile( - 334 shareName=self.smb_share, - 335 pathName=remote_smb_path + ntpath.sep + entry_file.get_longname(), - 336 callback=f.write - 337 ) - 338 f.close() - 339 except BrokenPipeError as err: - 340 f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err)) - 341 f.close(remove=True) - 342 break - 343 except Exception as err: - 344 f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err)) - 345 f.close(remove=True) - 346 - 347 # Directories - 348 for entry_directory in directories: - 349 if entry_directory.is_directory(): - 350 recurse_action( - 351 base_dir=self.smb_cwd, - 352 path=path+[entry_directory.get_longname()] - 353 ) - 354 # Entrypoint - 355 try: - 356 recurse_action( - 357 base_dir=self.smb_cwd, - 358 path=[path] - 359 ) - 360 except (BrokenPipeError, KeyboardInterrupt) as e: - 361 print("\x1b[v\x1b[o\r[!] Interrupted.") - 362 self.close_smb_session() - 363 self.init_smb_session() - 364 - 365 def get_entry(self, path=None): - 366 """ - 367 Retrieves information about a specific entry located at the provided path on the SMB share. - 368 - 369 This method checks if the specified path exists on the SMB share. If the path exists, it retrieves the details of the entry at that path, including the directory name and file name. If the entry is found, it returns the entry object; otherwise, it returns None. - 370 - 371 Args: - 372 path (str): The path of the entry to retrieve information about. - 373 - 374 Returns: - 375 Entry: An object representing the entry at the specified path, or None if the entry is not found. - 376 """ - 377 - 378 if self.path_exists(path=path): - 379 matches = self.smbClient.listPath(shareName=self.smb_share, path=path) - 380 - 381 if len(matches) == 1: - 382 return matches[0] - 383 else: - 384 return None - 385 - 386 else: - 387 return None - 388 - 389 def info(self, share=True, server=True): - 390 """ - 391 Displays information about the server and optionally the shares. - 392 - 393 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. + 19 + 20class SMBSession(object): + 21 """ + 22 Class SMBSession is designed to handle the session management for SMB (Server Message Block) protocol connections. + 23 It provides functionalities to connect to an SMB server, authenticate using either NTLM or Kerberos, and manage SMB shares. + 24 + 25 Attributes: + 26 address (str): The IP address or hostname of the SMB server. + 27 domain (str): The domain name for SMB server authentication. + 28 username (str): The username for SMB server authentication. + 29 password (str): The password for SMB server authentication. + 30 lmhash (str): The LM hash of the user's password, if available. + 31 nthash (str): The NT hash of the user's password, if available. + 32 use_kerberos (bool): A flag to determine whether to use Kerberos for authentication. + 33 kdcHost (str): The Key Distribution Center (KDC) host for Kerberos authentication. + 34 debug (bool): A flag to enable debug output. + 35 smbClient (object): The SMB client object used for the connection. + 36 connected (bool): A flag to check the status of the connection. + 37 smb_share (str): The current SMB share in use. + 38 smb_path (str): The current path within the SMB share. + 39 + 40 Methods: + 41 __init__(address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, debug=False): + 42 Initializes the SMBSession with the specified parameters. + 43 init_smb_session(): + 44 Initializes the SMB session by connecting to the server and authenticating using the specified method. + 45 """ + 46 + 47 def __init__(self, address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, config=None): + 48 super(SMBSession, self).__init__() + 49 # Objects + 50 self.config = config + 51 + 52 # Target server + 53 self.address = address + 54 + 55 # Credentials + 56 self.domain = domain + 57 self.username = username + 58 self.password = password + 59 self.lmhash = lmhash + 60 self.nthash = nthash + 61 self.use_kerberos = use_kerberos + 62 self.kdcHost = kdcHost + 63 + 64 self.smbClient = None + 65 self.connected = False + 66 + 67 self.available_shares = {} + 68 self.smb_share = None + 69 self.smb_cwd = "" + 70 self.smb_tree_id = None + 71 + 72 self.list_shares() + 73 + 74 # Connect and disconnect SMB session + 75 + 76 def init_smb_session(self): + 77 """ + 78 Initializes and establishes a session with the SMB server. + 79 + 80 This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration. + 81 It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization. + 82 + 83 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. + 84 + 85 Returns: + 86 bool: True if the connection and authentication are successful, False otherwise. + 87 """ + 88 + 89 self.connected = False + 90 + 91 if self.config.debug: + 92 print("[debug] [>] Connecting to remote SMB server '%s' ... " % self.address) + 93 try: + 94 self.smbClient = impacket.smbconnection.SMBConnection( + 95 remoteName=self.address, + 96 remoteHost=self.address, + 97 sess_port=int(445) + 98 ) + 99 except OSError as err: + 100 print("[!] %s" % err) + 101 self.smbClient = None + 102 + 103 if self.smbClient is not None: + 104 if self.use_kerberos: + 105 if self.config.debug: + 106 print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... " % (self.domain, self.username)) + 107 try: + 108 self.connected = self.smbClient.kerberosLogin( + 109 user=self.username, + 110 password=self.password, + 111 domain=self.domain, + 112 lmhash=self.lmhash, + 113 nthash=self.nthash, + 114 aesKey=self.aesKey, + 115 kdcHost=self.kdcHost + 116 ) + 117 except impacket.smbconnection.SessionError as err: + 118 if self.config.debug: + 119 traceback.print_exc() + 120 print("[!] Could not login: %s" % err) + 121 self.connected = False + 122 + 123 else: + 124 if self.config.debug: + 125 print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... " % (self.domain, self.username)) + 126 try: + 127 self.connected = self.smbClient.login( + 128 user=self.username, + 129 password=self.password, + 130 domain=self.domain, + 131 lmhash=self.lmhash, + 132 nthash=self.nthash + 133 ) + 134 except impacket.smbconnection.SessionError as err: + 135 if self.config.debug: + 136 traceback.print_exc() + 137 print("[!] Could not login: %s" % err) + 138 self.connected = False + 139 + 140 if self.connected: + 141 print("[+] Successfully authenticated to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username)) + 142 else: + 143 print("[!] Failed to authenticate to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username)) + 144 + 145 return self.connected + 146 + 147 def close_smb_session(self): + 148 """ + 149 Closes the current SMB session by disconnecting the SMB client. + 150 + 151 This method ensures that the SMB client connection is properly closed. It checks if the client is connected + 152 and if so, it closes the connection and resets the connection status. + 153 + 154 Raises: + 155 Exception: If the SMB client is not initialized or if there's an error during the disconnection process. + 156 """ + 157 + 158 if self.smbClient is not None: + 159 if self.connected: + 160 self.smbClient.close() + 161 self.connected = False + 162 if self.config.debug: + 163 print("[+] SMB connection closed successfully.") + 164 else: + 165 if self.config.debug: + 166 print("[!] No active SMB connection to close.") + 167 else: + 168 raise Exception("SMB client is not initialized.") + 169 + 170 # Operations + 171 + 172 def read_file(self, path=None): + 173 if self.path_isfile(path=path): + 174 tmp_file_path = self.smb_cwd + ntpath.sep + path + 175 matches = self.smbClient.listPath( + 176 shareName=self.smb_share, + 177 path=tmp_file_path + 178 ) + 179 + 180 fh = io.BytesIO() + 181 try: + 182 # opening the files in streams instead of mounting shares allows + 183 # for running the script from unprivileged containers + 184 self.smbClient.getFile(self.smb_share, tmp_file_path, fh.write) + 185 except impacket.smbconnection.SessionError as e: + 186 return None + 187 rawdata = fh.getvalue() + 188 fh.close() + 189 return rawdata + 190 else: + 191 print("[!] Remote path '%s' is not a file." % path) + 192 + 193 def find(self, paths=[], callback=None): + 194 def recurse_action(paths=[], depth=0, callback=None): + 195 if callback is None: + 196 return [] + 197 + 198 next_directories_to_explore = [] + 199 + 200 for path in paths: + 201 remote_smb_path = ntpath.normpath(self.smb_cwd + ntpath.sep + path) + 202 entries = [] + 203 + 204 try: + 205 entries = self.smbClient.listPath( + 206 shareName=self.smb_share, + 207 path=(remote_smb_path + ntpath.sep + '*') + 208 ) + 209 except impacket.smbconnection.SessionError as err: + 210 continue + 211 # Remove dot names + 212 entries = [e for e in entries if e.get_longname() not in [".", ".."]] + 213 # Sort the entries ignoring case + 214 entries = sorted(entries, key=lambda x:x.get_longname().lower()) + 215 + 216 for entry in entries: + 217 if entry.is_directory(): + 218 callback(entry, path + ntpath.sep + entry.get_longname() + ntpath.sep, depth) + 219 else: + 220 callback(entry, path + ntpath.sep + entry.get_longname(), depth) + 221 + 222 # Next directories to explore + 223 for entry in entries: + 224 if entry.is_directory(): + 225 next_directories_to_explore.append(path + ntpath.sep + entry.get_longname() + ntpath.sep) + 226 + 227 return next_directories_to_explore + 228 # + 229 if callback is not None: + 230 depth = 0 + 231 while len(paths) != 0: + 232 paths = recurse_action( + 233 paths=paths, + 234 depth=depth, + 235 callback=callback + 236 ) + 237 depth = depth + 1 + 238 else: + 239 print("[!] SMBSession.find(), callback function cannot be None.") + 240 + 241 def get_file(self, path=None, keepRemotePath=False): + 242 """ + 243 Retrieves a file from the specified path on the SMB share. + 244 + 245 This method attempts to retrieve a file from the given path within the currently connected SMB share. + 246 If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local + 247 file object and writing the contents of the remote file to it using the SMB client's getFile method. + 248 + 249 Parameters: + 250 path (str): The path of the file to retrieve. If None, uses the current smb_path. + 251 + 252 Returns: + 253 None + 254 """ + 255 + 256 # Parse path + 257 path = path.replace('/', ntpath.sep) + 258 if ntpath.sep in path: + 259 tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep + ntpath.dirname(path)) + 260 else: + 261 tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep) + 262 # Parse filename + 263 filename = ntpath.basename(path) + 264 + 265 # Search for the file + 266 matches = self.smbClient.listPath( + 267 shareName=self.smb_share, + 268 path=tmp_search_path + ntpath.sep + '*' + 269 ) + 270 + 271 # Filter the entries + 272 matching_entries = [] + 273 for entry in matches: + 274 if entry.is_directory(): + 275 # Skip directories + 276 continue + 277 if entry.get_longname() == filename: + 278 matching_entries.append(entry) + 279 elif '*' in filename: + 280 regexp = filename.replace('.', '\\.').replace('*', '.*') + 281 if re.match(regexp, entry.get_longname()): + 282 matching_entries.append(entry) + 283 + 284 matching_entries = sorted(list(set(matching_entries)), key=lambda x: x.get_longname()) + 285 + 286 for entry in matching_entries: + 287 if entry.is_directory(): + 288 if self.config.debug: + 289 print("[debug] [>] Skipping '%s' because it is a directory." % (tmp_search_path + ntpath.sep + entry.get_longname())) + 290 else: + 291 try: + 292 if ntpath.sep in path: + 293 outputfile = ntpath.dirname(path) + ntpath.sep + entry.get_longname() + 294 else: + 295 outputfile = entry.get_longname() + 296 f = LocalFileIO( + 297 mode="wb", + 298 path=outputfile, + 299 expected_size=entry.get_filesize(), + 300 debug=self.config.debug, + 301 keepRemotePath=keepRemotePath + 302 ) + 303 self.smbClient.getFile( + 304 shareName=self.smb_share, + 305 pathName=tmp_search_path + ntpath.sep + entry.get_longname(), + 306 callback=f.write + 307 ) + 308 f.close() + 309 except (BrokenPipeError, KeyboardInterrupt) as e: + 310 f.close() + 311 print("\x1b[v\x1b[o\r[!] Interrupted.") + 312 self.close_smb_session() + 313 self.init_smb_session() + 314 + 315 return None + 316 + 317 def get_file_recursively(self, path=None): + 318 """ + 319 Recursively retrieves files from a specified path on the SMB share. + 320 + 321 This method navigates through all directories starting from the given path, + 322 and downloads all files found. It handles directories recursively, ensuring + 323 that all nested files are retrieved. The method skips over directory entries + 324 and handles errors gracefully, attempting to continue the operation where possible. + 325 + 326 Parameters: + 327 path (str): The initial directory path from which to start the recursive file retrieval. + 328 If None, it starts from the root of the configured SMB share. + 329 """ + 330 + 331 def recurse_action(base_dir="", path=[]): + 332 if len(base_dir) == 0: + 333 remote_smb_path = ntpath.sep.join(path) + 334 else: + 335 remote_smb_path = base_dir + ntpath.sep + ntpath.sep.join(path) + 336 remote_smb_path = ntpath.normpath(remote_smb_path) + 337 + 338 entries = self.smbClient.listPath( + 339 shareName=self.smb_share, + 340 path=remote_smb_path + '\\*' + 341 ) + 342 if len(entries) != 0: + 343 files = [entry for entry in entries if not entry.is_directory()] + 344 directories = [entry for entry in entries if entry.is_directory() and entry.get_longname() not in [".", ".."]] + 345 + 346 # Files + 347 if len(files) != 0: + 348 print("[>] Retrieving files of '%s'" % remote_smb_path) + 349 for entry_file in files: + 350 if not entry_file.is_directory(): + 351 f = LocalFileIO( + 352 mode="wb", + 353 path=remote_smb_path + ntpath.sep + entry_file.get_longname(), + 354 expected_size=entry_file.get_filesize(), + 355 keepRemotePath=True, + 356 debug=self.config.debug + 357 ) + 358 try: + 359 self.smbClient.getFile( + 360 shareName=self.smb_share, + 361 pathName=remote_smb_path + ntpath.sep + entry_file.get_longname(), + 362 callback=f.write + 363 ) + 364 f.close() + 365 except BrokenPipeError as err: + 366 f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err)) + 367 f.close(remove=True) + 368 break + 369 except Exception as err: + 370 f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err)) + 371 f.close(remove=True) + 372 + 373 # Directories + 374 for entry_directory in directories: + 375 if entry_directory.is_directory(): + 376 recurse_action( + 377 base_dir=self.smb_cwd, + 378 path=path+[entry_directory.get_longname()] + 379 ) + 380 # Entrypoint + 381 try: + 382 recurse_action( + 383 base_dir=self.smb_cwd, + 384 path=[path] + 385 ) + 386 except (BrokenPipeError, KeyboardInterrupt) as e: + 387 print("\x1b[v\x1b[o\r[!] Interrupted.") + 388 self.close_smb_session() + 389 self.init_smb_session() + 390 + 391 def get_entry(self, path=None): + 392 """ + 393 Retrieves information about a specific entry located at the provided path on the SMB share. 394 - 395 Parameters: - 396 share (bool): If True, display information about the current share. - 397 server (bool): If True, display information about the server. - 398 - 399 Returns: - 400 None - 401 """ - 402 - 403 if server: - 404 if self.config.no_colors: - 405 print("[+] Server:") - 406 print(" ├─NetBIOS:") - 407 print(" │ ├─ NetBIOS Hostname ──────── : %s" % (self.smbClient.getServerName())) - 408 print(" │ └─ NetBIOS Domain ────────── : %s" % (self.smbClient.getServerDomain())) - 409 print(" ├─DNS:") - 410 print(" │ ├─ DNS Hostname ──────────── : %s" % (self.smbClient.getServerDNSHostName())) - 411 print(" │ └─ DNS Domain ────────────── : %s" % (self.smbClient.getServerDNSDomainName())) - 412 print(" ├─OS:") - 413 print(" │ ├─ OS Name ───────────────── : %s" % (self.smbClient.getServerOS())) - 414 print(" │ └─ OS Version ────────────── : %s.%s.%s" % (self.smbClient.getServerOSMajor(), self.smbClient.getServerOSMinor(), self.smbClient.getServerOSBuild())) - 415 print(" ├─Server:") - 416 print(" │ ├─ Signing Required ──────── : %s" % (self.smbClient.isSigningRequired())) - 417 print(" │ ├─ Login Required ────────── : %s" % (self.smbClient.isLoginRequired())) - 418 print(" │ ├─ Supports NTLMv2 ───────── : %s" % (self.smbClient.doesSupportNTLMv2())) - 419 MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"] - 420 print(" │ ├─ Max size of read chunk ── : %d bytes (%s)" % (MaxReadSize, b_filesize(MaxReadSize))) - 421 MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"] - 422 print(" │ └─ Max size of write chunk ─ : %d bytes (%s)" % (MaxWriteSize, b_filesize(MaxWriteSize))) - 423 print(" └─") - 424 else: - 425 print("[+] Server:") - 426 print(" ├─NetBIOS:") - 427 print(" │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerName())) - 428 print(" │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDomain())) - 429 print(" ├─DNS:") - 430 print(" │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSHostName())) - 431 print(" │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSDomainName())) - 432 print(" ├─OS:") - 433 print(" │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerOS())) - 434 print(" │ └─ \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())) - 435 print(" ├─Server:") - 436 print(" │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isSigningRequired())) - 437 print(" │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isLoginRequired())) - 438 print(" │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.doesSupportNTLMv2())) - 439 MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"] - 440 print(" │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxReadSize, b_filesize(MaxReadSize))) - 441 MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"] - 442 print(" │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxWriteSize, b_filesize(MaxWriteSize))) - 443 print(" └─") - 444 - 445 if share and self.smb_share is not None: - 446 share_name = self.available_shares.get(self.smb_share.lower(), "")["name"] - 447 share_comment = self.available_shares.get(self.smb_share.lower(), "")["comment"] - 448 share_type = self.available_shares.get(self.smb_share.lower(), "")["type"] - 449 share_type =', '.join([s.replace("STYPE_","") for s in share_type]) - 450 share_rawtype = self.available_shares.get(self.smb_share.lower(), "")["rawtype"] - 451 if self.config.no_colors: - 452 print("\n[+] Share:") - 453 print(" ├─ Name ──────────── : %s" % (share_name)) - 454 print(" ├─ Description ───── : %s" % (share_comment)) - 455 print(" ├─ Type ──────────── : %s" % (share_type)) - 456 print(" └─ Raw type value ── : %s" % (share_rawtype)) - 457 else: - 458 print("\n[+] Share:") - 459 print(" ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_name)) - 460 print(" ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_comment)) - 461 print(" ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_type)) - 462 print(" └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m" % (share_rawtype)) - 463 - 464 def list_contents(self, path=None): - 465 """ - 466 Lists the contents of a specified directory on the SMB share. - 467 - 468 This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path` - 469 is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with - 470 the long names of the files and directories as keys and their respective SMB entry objects as values. - 471 - 472 Args: - 473 shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None. - 474 path (str, optional): The directory path to list contents from. Defaults to the current path if None. - 475 - 476 Returns: - 477 dict: A dictionary with file and directory names as keys and their SMB entry objects as values. - 478 """ - 479 - 480 dest_path = [self.smb_cwd.rstrip(ntpath.sep),] - 481 if path is not None and len(path) > 0: - 482 dest_path.append(path.rstrip(ntpath.sep)) - 483 dest_path.append('*') - 484 path = ntpath.sep.join(dest_path) - 485 - 486 contents = {} - 487 entries = self.smbClient.listPath( - 488 shareName=self.smb_share, - 489 path=path - 490 ) - 491 for entry in entries: - 492 contents[entry.get_longname()] = entry + 395 This method checks if the specified path exists on the SMB share. If the path exists, it retrieves the details of the entry at that path, including the directory name and file name. If the entry is found, it returns the entry object; otherwise, it returns None. + 396 + 397 Args: + 398 path (str): The path of the entry to retrieve information about. + 399 + 400 Returns: + 401 Entry: An object representing the entry at the specified path, or None if the entry is not found. + 402 """ + 403 + 404 if self.path_exists(path=path): + 405 matches = self.smbClient.listPath(shareName=self.smb_share, path=path) + 406 + 407 if len(matches) == 1: + 408 return matches[0] + 409 else: + 410 return None + 411 + 412 else: + 413 return None + 414 + 415 def info(self, share=True, server=True): + 416 """ + 417 Displays information about the server and optionally the shares. + 418 + 419 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. + 420 + 421 Parameters: + 422 share (bool): If True, display information about the current share. + 423 server (bool): If True, display information about the server. + 424 + 425 Returns: + 426 None + 427 """ + 428 + 429 if server: + 430 if self.config.no_colors: + 431 print("[+] Server:") + 432 print(" ├─NetBIOS:") + 433 print(" │ ├─ NetBIOS Hostname ──────── : %s" % (self.smbClient.getServerName())) + 434 print(" │ └─ NetBIOS Domain ────────── : %s" % (self.smbClient.getServerDomain())) + 435 print(" ├─DNS:") + 436 print(" │ ├─ DNS Hostname ──────────── : %s" % (self.smbClient.getServerDNSHostName())) + 437 print(" │ └─ DNS Domain ────────────── : %s" % (self.smbClient.getServerDNSDomainName())) + 438 print(" ├─OS:") + 439 print(" │ ├─ OS Name ───────────────── : %s" % (self.smbClient.getServerOS())) + 440 print(" │ └─ OS Version ────────────── : %s.%s.%s" % (self.smbClient.getServerOSMajor(), self.smbClient.getServerOSMinor(), self.smbClient.getServerOSBuild())) + 441 print(" ├─Server:") + 442 print(" │ ├─ Signing Required ──────── : %s" % (self.smbClient.isSigningRequired())) + 443 print(" │ ├─ Login Required ────────── : %s" % (self.smbClient.isLoginRequired())) + 444 print(" │ ├─ Supports NTLMv2 ───────── : %s" % (self.smbClient.doesSupportNTLMv2())) + 445 MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"] + 446 print(" │ ├─ Max size of read chunk ── : %d bytes (%s)" % (MaxReadSize, b_filesize(MaxReadSize))) + 447 MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"] + 448 print(" │ └─ Max size of write chunk ─ : %d bytes (%s)" % (MaxWriteSize, b_filesize(MaxWriteSize))) + 449 print(" └─") + 450 else: + 451 print("[+] Server:") + 452 print(" ├─NetBIOS:") + 453 print(" │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerName())) + 454 print(" │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDomain())) + 455 print(" ├─DNS:") + 456 print(" │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSHostName())) + 457 print(" │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSDomainName())) + 458 print(" ├─OS:") + 459 print(" │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerOS())) + 460 print(" │ └─ \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())) + 461 print(" ├─Server:") + 462 print(" │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isSigningRequired())) + 463 print(" │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isLoginRequired())) + 464 print(" │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.doesSupportNTLMv2())) + 465 MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"] + 466 print(" │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxReadSize, b_filesize(MaxReadSize))) + 467 MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"] + 468 print(" │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxWriteSize, b_filesize(MaxWriteSize))) + 469 print(" └─") + 470 + 471 if share and self.smb_share is not None: + 472 share_name = self.available_shares.get(self.smb_share.lower(), "")["name"] + 473 share_comment = self.available_shares.get(self.smb_share.lower(), "")["comment"] + 474 share_type = self.available_shares.get(self.smb_share.lower(), "")["type"] + 475 share_type =', '.join([s.replace("STYPE_","") for s in share_type]) + 476 share_rawtype = self.available_shares.get(self.smb_share.lower(), "")["rawtype"] + 477 if self.config.no_colors: + 478 print("\n[+] Share:") + 479 print(" ├─ Name ──────────── : %s" % (share_name)) + 480 print(" ├─ Description ───── : %s" % (share_comment)) + 481 print(" ├─ Type ──────────── : %s" % (share_type)) + 482 print(" └─ Raw type value ── : %s" % (share_rawtype)) + 483 else: + 484 print("\n[+] Share:") + 485 print(" ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_name)) + 486 print(" ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_comment)) + 487 print(" ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_type)) + 488 print(" └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m" % (share_rawtype)) + 489 + 490 def list_contents(self, path=None): + 491 """ + 492 Lists the contents of a specified directory on the SMB share. 493 - 494 return contents - 495 - 496 def list_shares(self): - 497 """ - 498 Lists all the shares available on the connected SMB server. - 499 - 500 This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary - 501 with key-value pairs where the key is the share name and the value is a dictionary containing details about the share - 502 such as its name, type, raw type, and any comments associated with the share. - 503 - 504 Returns: - 505 dict: A dictionary containing information about each share available on the server. - 506 """ - 507 - 508 self.available_shares = {} - 509 - 510 if self.connected: - 511 if self.smbClient is not None: - 512 resp = self.smbClient.listShares() - 513 - 514 for share in resp: - 515 # SHARE_INFO_1 structure (lmshare.h) - 516 # https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1 - 517 sharename = share["shi1_netname"][:-1] - 518 sharecomment = share["shi1_remark"][:-1] - 519 sharetype = share["shi1_type"] - 520 - 521 self.available_shares[sharename.lower()] = { - 522 "name": sharename, - 523 "type": STYPE_MASK(sharetype), - 524 "rawtype": sharetype, - 525 "comment": sharecomment - 526 } - 527 else: - 528 print("[!] Error: SMBSession.smbClient is None.") + 494 This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path` + 495 is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with + 496 the long names of the files and directories as keys and their respective SMB entry objects as values. + 497 + 498 Args: + 499 shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None. + 500 path (str, optional): The directory path to list contents from. Defaults to the current path if None. + 501 + 502 Returns: + 503 dict: A dictionary with file and directory names as keys and their SMB entry objects as values. + 504 """ + 505 + 506 dest_path = [self.smb_cwd.rstrip(ntpath.sep),] + 507 if path is not None and len(path) > 0: + 508 dest_path.append(path.rstrip(ntpath.sep)) + 509 dest_path.append('*') + 510 path = ntpath.sep.join(dest_path) + 511 + 512 contents = {} + 513 entries = self.smbClient.listPath( + 514 shareName=self.smb_share, + 515 path=path + 516 ) + 517 for entry in entries: + 518 contents[entry.get_longname()] = entry + 519 + 520 return contents + 521 + 522 def list_shares(self): + 523 """ + 524 Lists all the shares available on the connected SMB server. + 525 + 526 This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary + 527 with key-value pairs where the key is the share name and the value is a dictionary containing details about the share + 528 such as its name, type, raw type, and any comments associated with the share. 529 - 530 return self.available_shares - 531 - 532 def mkdir(self, path=None): - 533 """ - 534 Creates a directory at the specified path on the SMB share. + 530 Returns: + 531 dict: A dictionary containing information about each share available on the server. + 532 """ + 533 + 534 self.available_shares = {} 535 - 536 This method takes a path and attempts to create the directory structure on the SMB share. If the path includes - 537 nested directories, it will create each directory in the sequence. If a directory already exists, it will skip - 538 the creation for that directory without raising an error. + 536 if self.connected: + 537 if self.smbClient is not None: + 538 resp = self.smbClient.listShares() 539 - 540 Args: - 541 path (str, optional): The full path of the directory to create on the SMB share. Defaults to None. - 542 - 543 Note: - 544 The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility. - 545 """ + 540 for share in resp: + 541 # SHARE_INFO_1 structure (lmshare.h) + 542 # https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1 + 543 sharename = share["shi1_netname"][:-1] + 544 sharecomment = share["shi1_remark"][:-1] + 545 sharetype = share["shi1_type"] 546 - 547 if path is not None: - 548 # Prepare path - 549 path = path.replace('/',ntpath.sep) - 550 if ntpath.sep in path: - 551 path = path.strip(ntpath.sep).split(ntpath.sep) - 552 else: - 553 path = [path] - 554 - 555 # Create each dir in the path - 556 for depth in range(1, len(path)+1): - 557 tmp_path = ntpath.sep.join(path[:depth]) - 558 try: - 559 self.smbClient.createDirectory( - 560 shareName=self.smb_share, - 561 pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + tmp_path + ntpath.sep) - 562 ) - 563 except impacket.smbconnection.SessionError as err: - 564 if err.getErrorCode() == 0xc0000035: - 565 # STATUS_OBJECT_NAME_COLLISION - 566 # Remote directory already created, this is normal - 567 # Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19 - 568 pass - 569 else: - 570 print("[!] Failed to create directory '%s': %s" % (tmp_path, err)) - 571 if self.config.debug: - 572 traceback.print_exc() - 573 else: - 574 pass - 575 - 576 def mount(self, local_mount_point, remote_path): - 577 - 578 if not os.path.exists(local_mount_point): - 579 pass + 547 self.available_shares[sharename.lower()] = { + 548 "name": sharename, + 549 "type": STYPE_MASK(sharetype), + 550 "rawtype": sharetype, + 551 "comment": sharecomment + 552 } + 553 else: + 554 print("[!] Error: SMBSession.smbClient is None.") + 555 + 556 return self.available_shares + 557 + 558 def mkdir(self, path=None): + 559 """ + 560 Creates a directory at the specified path on the SMB share. + 561 + 562 This method takes a path and attempts to create the directory structure on the SMB share. If the path includes + 563 nested directories, it will create each directory in the sequence. If a directory already exists, it will skip + 564 the creation for that directory without raising an error. + 565 + 566 Args: + 567 path (str, optional): The full path of the directory to create on the SMB share. Defaults to None. + 568 + 569 Note: + 570 The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility. + 571 """ + 572 + 573 if path is not None: + 574 # Prepare path + 575 path = path.replace('/',ntpath.sep) + 576 if ntpath.sep in path: + 577 path = path.strip(ntpath.sep).split(ntpath.sep) + 578 else: + 579 path = [path] 580 - 581 if sys.platform.startswith('win'): - 582 remote_path = remote_path.replace('/',ntpath.sep) - 583 command = f"net use {local_mount_point} \\\\{self.address}\\{self.smb_share}\\{remote_path}" - 584 - 585 elif sys.platform.startswith('linux'): - 586 remote_path = remote_path.replace(ntpath.sep,'/') - 587 command = f"mount -t cifs //{self.address}/{self.smb_share}/{remote_path} {local_mount_point} -o username={self.username},password={self.password}" - 588 - 589 elif sys.platform.startswith('darwin'): - 590 remote_path = remote_path.replace(ntpath.sep,'/') - 591 command = f"mount_smbfs //{self.username}:{self.password}@{self.address}/{self.smb_share}/{remote_path} {local_mount_point}" - 592 - 593 else: - 594 command = None - 595 print("[!] Unsupported platform for mounting SMB share.") - 596 - 597 if command is not None: - 598 if self.config.debug: - 599 print("[debug] Executing: %s" % command) - 600 os.system(command) + 581 # Create each dir in the path + 582 for depth in range(1, len(path)+1): + 583 tmp_path = ntpath.sep.join(path[:depth]) + 584 try: + 585 self.smbClient.createDirectory( + 586 shareName=self.smb_share, + 587 pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + tmp_path + ntpath.sep) + 588 ) + 589 except impacket.smbconnection.SessionError as err: + 590 if err.getErrorCode() == 0xc0000035: + 591 # STATUS_OBJECT_NAME_COLLISION + 592 # Remote directory already created, this is normal + 593 # Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19 + 594 pass + 595 else: + 596 print("[!] Failed to create directory '%s': %s" % (tmp_path, err)) + 597 if self.config.debug: + 598 traceback.print_exc() + 599 else: + 600 pass 601 - 602 def path_exists(self, path=None): + 602 def mount(self, local_mount_point, remote_path): 603 """ - 604 Checks if the specified path exists on the SMB share. + 604 Generates the command to mount an SMB share on different platforms. 605 - 606 This method determines if a given path exists on the SMB share by attempting to list the contents of the path. - 607 If the path listing is successful and returns one or more entries, the path is considered to exist. + 606 This method takes the local mount point and the remote path of the SMB share and generates the appropriate mount command based on the platform. + 607 It constructs the mount command using the provided parameters and executes it using the os.system() function. 608 609 Args: - 610 path (str, optional): The path to check on the SMB share. Defaults to None. - 611 - 612 Returns: - 613 bool: True if the path exists, False otherwise or if an error occurs. - 614 """ - 615 - 616 if path is not None: - 617 path = path.replace('*','') - 618 try: - 619 contents = self.smbClient.listPath( - 620 shareName=self.smb_share, - 621 path=ntpath.normpath(self.smb_cwd + ntpath.sep + path + ntpath.sep) - 622 ) - 623 return (len(contents) != 0) - 624 except Exception as e: - 625 return False - 626 else: - 627 return False - 628 - 629 def path_isdir(self, pathFromRoot=None): - 630 """ - 631 Checks if the specified path is a directory on the SMB share. - 632 - 633 This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the - 634 contents of the path and filtering for entries that match the basename of the path and are marked as directories. - 635 - 636 Args: - 637 path (str, optional): The path to check on the SMB share. Defaults to None. - 638 - 639 Returns: - 640 bool: True if the path is a directory, False otherwise or if an error occurs. - 641 """ - 642 - 643 if pathFromRoot is not None: - 644 # Replace slashes if any - 645 path = pathFromRoot.replace('/', ntpath.sep) - 646 - 647 # Strip wildcards to avoid injections - 648 path = path.replace('*','') - 649 - 650 # Normalize path and strip leading backslash - 651 path = ntpath.normpath(path + ntpath.sep).lstrip(ntpath.sep) - 652 - 653 if path.strip() in ['', '.', '..']: - 654 # By defininition they exist on the filesystem - 655 return True - 656 else: - 657 try: - 658 contents = self.smbClient.listPath( - 659 shareName=self.smb_share, - 660 path=path+'*' - 661 ) - 662 # Filter on directories - 663 contents = [ - 664 c for c in contents - 665 if c.get_longname() == ntpath.basename(path) and c.is_directory() - 666 ] - 667 return (len(contents) != 0) - 668 except Exception as e: - 669 return False - 670 else: - 671 return False - 672 - 673 def path_isfile(self, path=None): - 674 """ - 675 Checks if the specified path is a file on the SMB share. - 676 - 677 This method determines if a given path corresponds to a file on the SMB share. It does this by listing the - 678 contents of the path and filtering for entries that match the basename of the path and are not marked as directories. - 679 - 680 Args: - 681 path (str, optional): The path to check on the SMB share. Defaults to None. - 682 - 683 Returns: - 684 bool: True if the path is a file, False otherwise or if an error occurs. - 685 """ - 686 - 687 if path is not None: - 688 path = path.replace('*','') - 689 search_dir = ntpath.normpath(self.smb_cwd + ntpath.sep + path) - 690 search_dir = ntpath.dirname(search_dir) + ntpath.sep + '*' - 691 try: - 692 contents = self.smbClient.listPath( - 693 shareName=self.smb_share, - 694 path=search_dir - 695 ) - 696 # Filter on files - 697 contents = [ - 698 c for c in contents - 699 if c.get_longname() == ntpath.basename(path) and not c.is_directory() - 700 ] - 701 return (len(contents) != 0) - 702 except Exception as e: - 703 return False - 704 else: - 705 return False - 706 - 707 def ping_smb_session(self): - 708 """ - 709 Tests the connectivity to the SMB server by sending an echo command. - 710 - 711 This method attempts to send an echo command to the SMB server to check if the session is still active. - 712 It updates the `connected` attribute of the class based on the success or failure of the echo command. - 713 - 714 Returns: - 715 bool: True if the echo command succeeds (indicating the session is active), False otherwise. - 716 """ + 610 local_mount_point (str): The local directory where the SMB share will be mounted. + 611 remote_path (str): The remote path on the SMB share to be mounted. + 612 + 613 Note: + 614 - For Windows platform, the command uses 'net use' to mount the share. + 615 - For Linux platform, the command uses 'mount' to mount the share. + 616 - For macOS platform, the command uses 'mount_smbfs' to mount the share. + 617 - If the platform is not supported, an error message is displayed. + 618 + 619 Returns: + 620 None + 621 """ + 622 + 623 if not os.path.exists(local_mount_point): + 624 pass + 625 + 626 if sys.platform.startswith('win'): + 627 remote_path = remote_path.replace('/',ntpath.sep) + 628 command = f"net use {local_mount_point} \\\\{self.address}\\{self.smb_share}\\{remote_path}" + 629 + 630 elif sys.platform.startswith('linux'): + 631 remote_path = remote_path.replace(ntpath.sep,'/') + 632 command = f"mount -t cifs //{self.address}/{self.smb_share}/{remote_path} {local_mount_point} -o username={self.username},password={self.password}" + 633 + 634 elif sys.platform.startswith('darwin'): + 635 remote_path = remote_path.replace(ntpath.sep,'/') + 636 command = f"mount_smbfs //{self.username}:{self.password}@{self.address}/{self.smb_share}/{remote_path} {local_mount_point}" + 637 + 638 else: + 639 command = None + 640 print("[!] Unsupported platform for mounting SMB share.") + 641 + 642 if command is not None: + 643 if self.config.debug: + 644 print("[debug] Executing: %s" % command) + 645 os.system(command) + 646 + 647 def path_exists(self, path=None): + 648 """ + 649 Checks if the specified path exists on the SMB share. + 650 + 651 This method determines if a given path exists on the SMB share by attempting to list the contents of the path. + 652 If the path listing is successful and returns one or more entries, the path is considered to exist. + 653 + 654 Args: + 655 path (str, optional): The path to check on the SMB share. Defaults to None. + 656 + 657 Returns: + 658 bool: True if the path exists, False otherwise or if an error occurs. + 659 """ + 660 + 661 if path is not None: + 662 path = path.replace('*','') + 663 try: + 664 contents = self.smbClient.listPath( + 665 shareName=self.smb_share, + 666 path=ntpath.normpath(self.smb_cwd + ntpath.sep + path + ntpath.sep) + 667 ) + 668 return (len(contents) != 0) + 669 except Exception as e: + 670 return False + 671 else: + 672 return False + 673 + 674 def path_isdir(self, pathFromRoot=None): + 675 """ + 676 Checks if the specified path is a directory on the SMB share. + 677 + 678 This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the + 679 contents of the path and filtering for entries that match the basename of the path and are marked as directories. + 680 + 681 Args: + 682 path (str, optional): The path to check on the SMB share. Defaults to None. + 683 + 684 Returns: + 685 bool: True if the path is a directory, False otherwise or if an error occurs. + 686 """ + 687 + 688 if pathFromRoot is not None: + 689 # Replace slashes if any + 690 path = pathFromRoot.replace('/', ntpath.sep) + 691 + 692 # Strip wildcards to avoid injections + 693 path = path.replace('*','') + 694 + 695 # Normalize path and strip leading backslash + 696 path = ntpath.normpath(path + ntpath.sep).lstrip(ntpath.sep) + 697 + 698 if path.strip() in ['', '.', '..']: + 699 # By defininition they exist on the filesystem + 700 return True + 701 else: + 702 try: + 703 contents = self.smbClient.listPath( + 704 shareName=self.smb_share, + 705 path=path+'*' + 706 ) + 707 # Filter on directories + 708 contents = [ + 709 c for c in contents + 710 if c.get_longname() == ntpath.basename(path) and c.is_directory() + 711 ] + 712 return (len(contents) != 0) + 713 except Exception as e: + 714 return False + 715 else: + 716 return False 717 - 718 try: - 719 self.smbClient.getSMBServer().echo() - 720 except Exception as e: - 721 self.connected = False - 722 return self.connected - 723 - 724 def put_file(self, localpath=None): - 725 """ - 726 Uploads a single file to the SMB share. + 718 def path_isfile(self, path=None): + 719 """ + 720 Checks if the specified path is a file on the SMB share. + 721 + 722 This method determines if a given path corresponds to a file on the SMB share. It does this by listing the + 723 contents of the path and filtering for entries that match the basename of the path and are not marked as directories. + 724 + 725 Args: + 726 path (str, optional): The path to check on the SMB share. Defaults to None. 727 - 728 This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path. - 729 It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session. - 730 General exceptions are caught and logged, with a traceback provided if debugging is enabled. + 728 Returns: + 729 bool: True if the path is a file, False otherwise or if an error occurs. + 730 """ 731 - 732 Args: - 733 localpath (str, optional): The local file path of the file to be uploaded. Defaults to None. - 734 """ - 735 - 736 if os.path.exists(localpath): - 737 if os.path.isfile(localpath): - 738 try: - 739 localfile = os.path.basename(localpath) - 740 f = LocalFileIO( - 741 mode="rb", - 742 path=localpath, - 743 debug=self.config.debug - 744 ) - 745 self.smbClient.putFile( - 746 shareName=self.smb_share, - 747 pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + localfile + ntpath.sep), - 748 callback=f.read - 749 ) - 750 f.close() - 751 except (BrokenPipeError, KeyboardInterrupt) as err: - 752 print("[!] Interrupted.") - 753 self.close_smb_session() - 754 self.init_smb_session() - 755 except Exception as err: - 756 print("[!] Failed to upload '%s': %s" % (localfile, err)) - 757 if self.config.debug: - 758 traceback.print_exc() - 759 else: - 760 print("[!] The specified localpath is a directory. Use 'put -r <directory>' instead.") - 761 else: - 762 print("[!] The specified localpath does not exist.") - 763 - 764 def put_file_recursively(self, localpath=None): - 765 """ - 766 Recursively uploads files from a specified local directory to the SMB share. - 767 - 768 This method walks through the given local directory and all its subdirectories, uploading each file to the - 769 corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is, - 770 it iterates over all files and directories within the local path, creating necessary directories on the SMB share - 771 and uploading files. If the local path is not a directory, it prints an error message. + 732 if path is not None: + 733 path = path.replace('*','') + 734 search_dir = ntpath.normpath(self.smb_cwd + ntpath.sep + path) + 735 search_dir = ntpath.dirname(search_dir) + ntpath.sep + '*' + 736 try: + 737 contents = self.smbClient.listPath( + 738 shareName=self.smb_share, + 739 path=search_dir + 740 ) + 741 # Filter on files + 742 contents = [ + 743 c for c in contents + 744 if c.get_longname() == ntpath.basename(path) and not c.is_directory() + 745 ] + 746 return (len(contents) != 0) + 747 except Exception as e: + 748 return False + 749 else: + 750 return False + 751 + 752 def ping_smb_session(self): + 753 """ + 754 Tests the connectivity to the SMB server by sending an echo command. + 755 + 756 This method attempts to send an echo command to the SMB server to check if the session is still active. + 757 It updates the `connected` attribute of the class based on the success or failure of the echo command. + 758 + 759 Returns: + 760 bool: True if the echo command succeeds (indicating the session is active), False otherwise. + 761 """ + 762 + 763 try: + 764 self.smbClient.getSMBServer().echo() + 765 except Exception as e: + 766 self.connected = False + 767 return self.connected + 768 + 769 def put_file(self, localpath=None): + 770 """ + 771 Uploads a single file to the SMB share. 772 - 773 Args: - 774 localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None. - 775 """ + 773 This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path. + 774 It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session. + 775 General exceptions are caught and logged, with a traceback provided if debugging is enabled. 776 - 777 if os.path.exists(localpath): - 778 if os.path.isfile(localpath): - 779 # Iterate over all files and directories within the local path - 780 local_files = {} - 781 for root, dirs, files in os.walk(localpath): - 782 if len(files) != 0: - 783 local_files[root] = files - 784 - 785 # Iterate over the found files - 786 for local_dir_path in sorted(local_files.keys()): - 787 print("[>] Putting files of '%s'" % local_dir_path) - 788 - 789 # Create remote directory - 790 remote_dir_path = local_dir_path.replace(os.path.sep, ntpath.sep) - 791 self.mkdir( - 792 path=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep) - 793 ) - 794 - 795 for local_file_path in local_files[local_dir_path]: - 796 try: - 797 f = LocalFileIO( - 798 mode="rb", - 799 path=local_dir_path + os.path.sep + local_file_path, - 800 debug=self.config.debug - 801 ) - 802 self.smbClient.putFile( - 803 shareName=self.smb_share, - 804 pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep + local_file_path), - 805 callback=f.read - 806 ) - 807 f.close() - 808 - 809 except BrokenPipeError as err: - 810 f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err)) - 811 f.close(remove=True) - 812 break - 813 except Exception as err: - 814 f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err)) - 815 f.close(remove=True) - 816 else: - 817 print("[!] The specified localpath is a file. Use 'put <file>' instead.") - 818 else: - 819 print("[!] The specified localpath does not exist.") - 820 - 821 def rmdir(self, path=None): - 822 """ - 823 Removes a directory from the SMB share at the specified path. - 824 - 825 This method attempts to delete a directory located at the given path on the SMB share. If the operation fails, - 826 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints - 827 the stack trace of the exception. - 828 - 829 Args: - 830 path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None. - 831 """ - 832 try: - 833 self.smbClient.deleteDirectory( - 834 shareName=self.smb_share, - 835 pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + path), - 836 ) - 837 except Exception as err: - 838 print("[!] Failed to remove directory '%s': %s" % (path, err)) - 839 if self.config.debug: - 840 traceback.print_exc() - 841 - 842 def rm(self, path=None): - 843 """ - 844 Removes a file from the SMB share at the specified path. - 845 - 846 This method attempts to delete a file located at the given path on the SMB share. If the operation fails, - 847 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints - 848 the stack trace of the exception. - 849 - 850 Args: - 851 path (str, optional): The path of the file to be removed on the SMB share. Defaults to None. - 852 """ - 853 try: - 854 self.smbClient.deleteFile( - 855 shareName=self.smb_share, - 856 pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + path), - 857 ) - 858 except Exception as err: - 859 print("[!] Failed to remove file '%s': %s" % (path, err)) - 860 if self.config.debug: - 861 traceback.print_exc() - 862 - 863 def tree(self, path=None): - 864 """ - 865 Recursively lists the directory structure of the SMB share starting from the specified path. + 777 Args: + 778 localpath (str, optional): The local file path of the file to be uploaded. Defaults to None. + 779 """ + 780 + 781 # Parse path + 782 localpath = localpath.replace('/', os.path.sep) + 783 if os.path.sep in localpath: + 784 tmp_search_path = os.path.normpath(os.getcwd() + os.path.sep + os.path.dirname(localpath)) + 785 else: + 786 tmp_search_path = os.path.normpath(os.getcwd() + os.path.sep) + 787 # Parse filename + 788 filename = os.path.basename(localpath) + 789 + 790 # Search for the file + 791 matches = os.listdir(tmp_search_path) + 792 # Filter the entries + 793 matching_entries = [] + 794 for entry in matches: + 795 if entry == filename: + 796 matching_entries.append(entry) + 797 elif '*' in filename: + 798 regexp = filename.replace('.', '\\.').replace('*', '.*') + 799 if re.match(regexp, entry): + 800 matching_entries.append(entry) + 801 + 802 matching_entries = sorted(list(set(matching_entries))) + 803 + 804 # Loop and upload + 805 for localpath in matching_entries: + 806 if os.path.exists(localpath): + 807 if os.path.isfile(localpath): + 808 try: + 809 localfile = os.path.basename(localpath) + 810 f = LocalFileIO( + 811 mode="rb", + 812 path=localpath, + 813 debug=self.config.debug + 814 ) + 815 self.smbClient.putFile( + 816 shareName=self.smb_share, + 817 pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + localfile + ntpath.sep), + 818 callback=f.read + 819 ) + 820 f.close() + 821 except (BrokenPipeError, KeyboardInterrupt) as err: + 822 print("[!] Interrupted.") + 823 self.close_smb_session() + 824 self.init_smb_session() + 825 except Exception as err: + 826 print("[!] Failed to upload '%s': %s" % (localfile, err)) + 827 if self.config.debug: + 828 traceback.print_exc() + 829 else: + 830 # [!] The specified localpath is a directory. Use 'put -r <directory>' instead. + 831 pass + 832 else: + 833 # [!] The specified localpath does not exist. + 834 pass + 835 + 836 def put_file_recursively(self, localpath=None): + 837 """ + 838 Recursively uploads files from a specified local directory to the SMB share. + 839 + 840 This method walks through the given local directory and all its subdirectories, uploading each file to the + 841 corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is, + 842 it iterates over all files and directories within the local path, creating necessary directories on the SMB share + 843 and uploading files. If the local path is not a directory, it prints an error message. + 844 + 845 Args: + 846 localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None. + 847 """ + 848 + 849 if os.path.exists(localpath): + 850 if os.path.isfile(localpath): + 851 # Iterate over all files and directories within the local path + 852 local_files = {} + 853 for root, dirs, files in os.walk(localpath): + 854 if len(files) != 0: + 855 local_files[root] = files + 856 + 857 # Iterate over the found files + 858 for local_dir_path in sorted(local_files.keys()): + 859 print("[>] Putting files of '%s'" % local_dir_path) + 860 + 861 # Create remote directory + 862 remote_dir_path = local_dir_path.replace(os.path.sep, ntpath.sep) + 863 self.mkdir( + 864 path=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep) + 865 ) 866 - 867 This function prints a visual representation of the directory tree of the remote SMB share. It uses - 868 recursion to navigate through directories and lists all files and subdirectories in each directory. - 869 The output is color-coded and formatted to enhance readability, with directories highlighted in cyan. - 870 - 871 Args: - 872 path (str, optional): The starting path on the SMB share from which to begin listing the tree. - 873 Defaults to the root of the current share. - 874 """ - 875 - 876 def recurse_action(base_dir="", path=[], prompt=[]): - 877 bars = ["│ ", "├── ", "└── "] - 878 - 879 remote_smb_path = ntpath.normpath(base_dir + ntpath.sep + ntpath.sep.join(path)) + 867 for local_file_path in local_files[local_dir_path]: + 868 try: + 869 f = LocalFileIO( + 870 mode="rb", + 871 path=local_dir_path + os.path.sep + local_file_path, + 872 debug=self.config.debug + 873 ) + 874 self.smbClient.putFile( + 875 shareName=self.smb_share, + 876 pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep + local_file_path), + 877 callback=f.read + 878 ) + 879 f.close() 880 - 881 entries = [] - 882 try: - 883 entries = self.smbClient.listPath( - 884 shareName=self.smb_share, - 885 path=remote_smb_path+'\\*' - 886 ) - 887 except impacket.smbconnection.SessionError as err: - 888 code, const, text = err.getErrorCode(), err.getErrorString()[0], err.getErrorString()[1] - 889 errmsg = "Error 0x%08x (%s): %s" % (code, const, text) - 890 if self.config.no_colors: - 891 print("%s%s" % (''.join(prompt+[bars[2]]), errmsg)) - 892 else: - 893 print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), errmsg)) - 894 return - 895 - 896 entries = [e for e in entries if e.get_longname() not in [".", ".."]] - 897 entries = sorted(entries, key=lambda x:x.get_longname()) - 898 - 899 # - 900 if len(entries) > 1: - 901 index = 0 - 902 for entry in entries: - 903 index += 1 - 904 # This is the first entry - 905 if index == 0: - 906 if entry.is_directory(): - 907 if self.config.no_colors: - 908 print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname())) - 909 else: - 910 print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname())) - 911 recurse_action( - 912 base_dir=base_dir, - 913 path=path+[entry.get_longname()], - 914 prompt=prompt+["│ "] - 915 ) - 916 else: - 917 if self.config.no_colors: - 918 print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname())) - 919 else: - 920 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname())) + 881 except BrokenPipeError as err: + 882 f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err)) + 883 f.close(remove=True) + 884 break + 885 except Exception as err: + 886 f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err)) + 887 f.close(remove=True) + 888 else: + 889 print("[!] The specified localpath is a file. Use 'put <file>' instead.") + 890 else: + 891 print("[!] The specified localpath does not exist.") + 892 + 893 def rmdir(self, path=None): + 894 """ + 895 Removes a directory from the SMB share at the specified path. + 896 + 897 This method attempts to delete a directory located at the given path on the SMB share. If the operation fails, + 898 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints + 899 the stack trace of the exception. + 900 + 901 Args: + 902 path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None. + 903 """ + 904 try: + 905 self.smbClient.deleteDirectory( + 906 shareName=self.smb_share, + 907 pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + path), + 908 ) + 909 except Exception as err: + 910 print("[!] Failed to remove directory '%s': %s" % (path, err)) + 911 if self.config.debug: + 912 traceback.print_exc() + 913 + 914 def rm(self, path=None): + 915 """ + 916 Removes a file from the SMB share at the specified path. + 917 + 918 This method attempts to delete a file located at the given path on the SMB share. If the operation fails, + 919 it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints + 920 the stack trace of the exception. 921 - 922 # This is the last entry - 923 elif index == len(entries): - 924 if entry.is_directory(): - 925 if self.config.no_colors: - 926 print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname())) - 927 else: - 928 print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname())) - 929 recurse_action( - 930 base_dir=base_dir, - 931 path=path+[entry.get_longname()], - 932 prompt=prompt+[" "] - 933 ) - 934 else: - 935 if self.config.no_colors: - 936 print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname())) - 937 else: - 938 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname())) - 939 - 940 # These are entries in the middle - 941 else: - 942 if entry.is_directory(): - 943 if self.config.no_colors: - 944 print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname())) - 945 else: - 946 print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname())) - 947 recurse_action( - 948 base_dir=base_dir, - 949 path=path+[entry.get_longname()], - 950 prompt=prompt+["│ "] - 951 ) - 952 else: - 953 if self.config.no_colors: - 954 print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname())) - 955 else: - 956 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname())) - 957 - 958 # - 959 elif len(entries) == 1: - 960 entry = entries[0] - 961 if entry.is_directory(): - 962 if self.config.no_colors: - 963 print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname())) - 964 else: - 965 print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname())) - 966 recurse_action( - 967 base_dir=base_dir, - 968 path=path+[entry.get_longname()], - 969 prompt=prompt+[" "] - 970 ) - 971 else: - 972 if self.config.no_colors: - 973 print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname())) - 974 else: - 975 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname())) - 976 - 977 # Entrypoint - 978 try: - 979 if self.config.no_colors: - 980 print("%s\\" % path) - 981 else: - 982 print("\x1b[1;96m%s\x1b[0m\\" % path) - 983 recurse_action( - 984 base_dir=self.smb_cwd, - 985 path=[path], - 986 prompt=[""] - 987 ) - 988 except (BrokenPipeError, KeyboardInterrupt) as e: - 989 print("[!] Interrupted.") - 990 self.close_smb_session() - 991 self.init_smb_session() - 992 - 993 def umount(self, local_mount_point): - 994 if os.path.exists(local_mount_point): - 995 if sys.platform.startswith('win'): - 996 command = f"net use {local_mount_point} /delete" - 997 - 998 elif sys.platform.startswith('linux') or sys.platform.startswith('darwin'): - 999 command = f"umount {local_mount_point}" -1000 -1001 else: -1002 command = None -1003 print("[!] Unsupported platform for unmounting SMB share.") -1004 -1005 if command is not None: -1006 if self.config.debug: -1007 print("[debug] Executing: %s" % command) -1008 os.system(command) -1009 else: -1010 print("[!] Cannot unmount a non existing path.") -1011 -1012 # Setter / Getter -1013 -1014 def set_share(self, shareName): -1015 """ -1016 Sets the current SMB share to the specified share name. -1017 -1018 This method updates the SMB session to use the specified share name. It checks if the share name is valid -1019 and updates the smb_share attribute of the SMBSession instance. -1020 -1021 Parameters: -1022 shareName (str): The name of the share to set as the current SMB share. -1023 -1024 Raises: -1025 ValueError: If the shareName is None or an empty string. -1026 """ -1027 -1028 if shareName is not None: -1029 self.list_shares() -1030 if shareName.lower() in self.available_shares.keys(): -1031 # Doing this in order to keep the case of the share adevertised by the remote machine -1032 self.smb_share = self.available_shares[shareName.lower()]["name"] -1033 # Connects the tree -1034 self.smb_tree_id = self.smbClient.connectTree(self.smb_share) -1035 else: -1036 print("[!] Could not set share '%s', it does not exist remotely." % shareName) -1037 -1038 def set_cwd(self, path=None): -1039 """ -1040 Sets the current working directory on the SMB share to the specified path. -1041 -1042 This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory. -1043 If the specified path is not a directory, the cwd remains unchanged. -1044 -1045 Parameters: -1046 path (str): The path to set as the current working directory. -1047 -1048 Raises: -1049 ValueError: If the specified path is not a directory. -1050 """ -1051 -1052 if path is not None: -1053 # Set path separators to ntpath sep -1054 if '/' in path: -1055 path = path.replace('/', ntpath.sep) -1056 -1057 if path.startswith(ntpath.sep): -1058 # Absolute path -1059 path = path + ntpath.sep -1060 else: -1061 # Relative path to the CWD -1062 if len(self.smb_cwd) == 0: -1063 path = path + ntpath.sep -1064 else: -1065 path = self.smb_cwd + ntpath.sep + path -1066 -1067 # Path normalization -1068 path = ntpath.normpath(path) -1069 path = re.sub(r'\\+', r'\\', path) -1070 -1071 if path in ["", ".", ".."]: -1072 self.smb_cwd = "" -1073 else: -1074 if self.path_isdir(pathFromRoot=path.strip(ntpath.sep)): -1075 # Path exists on the remote -1076 self.smb_cwd = ntpath.normpath(path) -1077 else: -1078 # Path does not exists or is not a directory on the remote -1079 print("[!] Remote directory '%s' does not exist." % path) + 922 Args: + 923 path (str, optional): The path of the file to be removed on the SMB share. Defaults to None. + 924 """ + 925 + 926 # Parse path + 927 path = path.replace('/', ntpath.sep) + 928 if ntpath.sep in path: + 929 tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep + ntpath.dirname(path)) + 930 else: + 931 tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep) + 932 # Parse filename + 933 filename = ntpath.basename(path) + 934 + 935 # Search for the file + 936 matches = self.smbClient.listPath( + 937 shareName=self.smb_share, + 938 path=tmp_search_path + ntpath.sep + '*' + 939 ) + 940 + 941 # Filter the entries + 942 matching_entries = [] + 943 for entry in matches: + 944 if entry.is_directory(): + 945 # Skip directories + 946 continue + 947 if entry.get_longname() == filename: + 948 matching_entries.append(entry) + 949 elif '*' in filename: + 950 regexp = filename.replace('.', '\\.').replace('*', '.*') + 951 if re.match(regexp, entry.get_longname()): + 952 matching_entries.append(entry) + 953 + 954 matching_entries = sorted(list(set(matching_entries)), key=lambda x: x.get_longname()) + 955 + 956 for entry in matching_entries: + 957 try: + 958 self.smbClient.deleteFile( + 959 shareName=self.smb_share, + 960 pathName=ntpath.normpath(tmp_search_path + ntpath.sep + entry.get_longname()), + 961 ) + 962 except Exception as err: + 963 print("[!] Failed to remove file '%s': %s" % (path, err)) + 964 if self.config.debug: + 965 traceback.print_exc() + 966 + 967 def tree(self, path=None): + 968 """ + 969 Recursively lists the directory structure of the SMB share starting from the specified path. + 970 + 971 This function prints a visual representation of the directory tree of the remote SMB share. It uses + 972 recursion to navigate through directories and lists all files and subdirectories in each directory. + 973 The output is color-coded and formatted to enhance readability, with directories highlighted in cyan. + 974 + 975 Args: + 976 path (str, optional): The starting path on the SMB share from which to begin listing the tree. + 977 Defaults to the root of the current share. + 978 """ + 979 + 980 def recurse_action(base_dir="", path=[], prompt=[]): + 981 bars = ["│ ", "├── ", "└── "] + 982 + 983 remote_smb_path = ntpath.normpath(base_dir + ntpath.sep + ntpath.sep.join(path)) + 984 + 985 entries = [] + 986 try: + 987 entries = self.smbClient.listPath( + 988 shareName=self.smb_share, + 989 path=remote_smb_path+'\\*' + 990 ) + 991 except impacket.smbconnection.SessionError as err: + 992 code, const, text = err.getErrorCode(), err.getErrorString()[0], err.getErrorString()[1] + 993 errmsg = "Error 0x%08x (%s): %s" % (code, const, text) + 994 if self.config.no_colors: + 995 print("%s%s" % (''.join(prompt+[bars[2]]), errmsg)) + 996 else: + 997 print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), errmsg)) + 998 return + 999 +1000 entries = [e for e in entries if e.get_longname() not in [".", ".."]] +1001 entries = sorted(entries, key=lambda x:x.get_longname()) +1002 +1003 # +1004 if len(entries) > 1: +1005 index = 0 +1006 for entry in entries: +1007 index += 1 +1008 # This is the first entry +1009 if index == 0: +1010 if entry.is_directory(): +1011 if self.config.no_colors: +1012 print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname())) +1013 else: +1014 print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname())) +1015 recurse_action( +1016 base_dir=base_dir, +1017 path=path+[entry.get_longname()], +1018 prompt=prompt+["│ "] +1019 ) +1020 else: +1021 if self.config.no_colors: +1022 print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname())) +1023 else: +1024 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname())) +1025 +1026 # This is the last entry +1027 elif index == len(entries): +1028 if entry.is_directory(): +1029 if self.config.no_colors: +1030 print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname())) +1031 else: +1032 print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname())) +1033 recurse_action( +1034 base_dir=base_dir, +1035 path=path+[entry.get_longname()], +1036 prompt=prompt+[" "] +1037 ) +1038 else: +1039 if self.config.no_colors: +1040 print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname())) +1041 else: +1042 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname())) +1043 +1044 # These are entries in the middle +1045 else: +1046 if entry.is_directory(): +1047 if self.config.no_colors: +1048 print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname())) +1049 else: +1050 print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname())) +1051 recurse_action( +1052 base_dir=base_dir, +1053 path=path+[entry.get_longname()], +1054 prompt=prompt+["│ "] +1055 ) +1056 else: +1057 if self.config.no_colors: +1058 print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname())) +1059 else: +1060 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname())) +1061 +1062 # +1063 elif len(entries) == 1: +1064 entry = entries[0] +1065 if entry.is_directory(): +1066 if self.config.no_colors: +1067 print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname())) +1068 else: +1069 print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname())) +1070 recurse_action( +1071 base_dir=base_dir, +1072 path=path+[entry.get_longname()], +1073 prompt=prompt+[" "] +1074 ) +1075 else: +1076 if self.config.no_colors: +1077 print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname())) +1078 else: +1079 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname())) +1080 +1081 # Entrypoint +1082 try: +1083 if self.config.no_colors: +1084 print("%s\\" % path) +1085 else: +1086 print("\x1b[1;96m%s\x1b[0m\\" % path) +1087 recurse_action( +1088 base_dir=self.smb_cwd, +1089 path=[path], +1090 prompt=[""] +1091 ) +1092 except (BrokenPipeError, KeyboardInterrupt) as e: +1093 print("[!] Interrupted.") +1094 self.close_smb_session() +1095 self.init_smb_session() +1096 +1097 def umount(self, local_mount_point): +1098 """ +1099 Unmounts the specified local mount point of the remote share. +1100 +1101 This method unmounts the specified local mount point of the remote share based on the platform. +1102 It supports Windows, Linux, and macOS platforms for unmounting. +1103 +1104 Parameters: +1105 local_mount_point (str): The local mount point to unmount. +1106 +1107 Raises: +1108 None +1109 """ +1110 +1111 if os.path.exists(local_mount_point): +1112 if sys.platform.startswith('win'): +1113 command = f"net use {local_mount_point} /delete" +1114 +1115 elif sys.platform.startswith('linux') or sys.platform.startswith('darwin'): +1116 command = f"umount {local_mount_point}" +1117 +1118 else: +1119 command = None +1120 print("[!] Unsupported platform for unmounting SMB share.") +1121 +1122 if command is not None: +1123 if self.config.debug: +1124 print("[debug] Executing: %s" % command) +1125 os.system(command) +1126 else: +1127 print("[!] Cannot unmount a non existing path.") +1128 +1129 # Other functions +1130 +1131 def test_rights(self, sharename): +1132 """ +1133 Tests the read and write access rights of the current SMB session. +1134 +1135 This method checks the read and write access rights of the current SMB session by attempting to list paths and create/delete temporary directories. +1136 +1137 Returns: +1138 dict: A dictionary containing the read and write access rights status. +1139 - "readable" (bool): Indicates if the session has read access rights. +1140 - "writable" (bool): Indicates if the session has write access rights. +1141 """ +1142 +1143 # Restore the current share +1144 current_share = self.smb_share +1145 self.set_share(shareName=sharename) +1146 +1147 access_rights = {"readable": False, "writable": False} +1148 try: +1149 self.smbClient.listPath(self.smb_share, '*', password=None) +1150 access_rights["readable"] = True +1151 except impacket.smbconnection.SessionError as e: +1152 access_rights["readable"] = False +1153 +1154 try: +1155 temp_dir = ntpath.normpath("\\" + ''.join([random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ0123456759") for k in range(16)])) +1156 self.smbClient.createDirectory(self.smb_share, temp_dir) +1157 self.smbClient.deleteDirectory(self.smb_share, temp_dir) +1158 access_rights["writable"] = True +1159 except impacket.smbconnection.SessionError as e: +1160 access_rights["writable"] = False +1161 +1162 # Restore the current share +1163 self.set_share(shareName=current_share) +1164 +1165 return access_rights +1166 +1167 # Setter / Getter +1168 +1169 def set_share(self, shareName): +1170 """ +1171 Sets the current SMB share to the specified share name. +1172 +1173 This method updates the SMB session to use the specified share name. It checks if the share name is valid +1174 and updates the smb_share attribute of the SMBSession instance. +1175 +1176 Parameters: +1177 shareName (str): The name of the share to set as the current SMB share. +1178 +1179 Raises: +1180 ValueError: If the shareName is None or an empty string. +1181 """ +1182 +1183 if shareName is not None: +1184 self.list_shares() +1185 if shareName.lower() in self.available_shares.keys(): +1186 # Doing this in order to keep the case of the share adevertised by the remote machine +1187 self.smb_share = self.available_shares[shareName.lower()]["name"] +1188 self.smb_cwd = "" +1189 # Connects the tree +1190 self.smb_tree_id = self.smbClient.connectTree(self.smb_share) +1191 else: +1192 print("[!] Could not set share '%s', it does not exist remotely." % shareName) +1193 else: +1194 self.smb_share = None +1195 +1196 def set_cwd(self, path=None): +1197 """ +1198 Sets the current working directory on the SMB share to the specified path. +1199 +1200 This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory. +1201 If the specified path is not a directory, the cwd remains unchanged. +1202 +1203 Parameters: +1204 path (str): The path to set as the current working directory. +1205 +1206 Raises: +1207 ValueError: If the specified path is not a directory. +1208 """ +1209 +1210 if path is not None: +1211 # Set path separators to ntpath sep +1212 if '/' in path: +1213 path = path.replace('/', ntpath.sep) +1214 +1215 if path.startswith(ntpath.sep): +1216 # Absolute path +1217 path = path + ntpath.sep +1218 else: +1219 # Relative path to the CWD +1220 if len(self.smb_cwd) == 0: +1221 path = path + ntpath.sep +1222 else: +1223 path = self.smb_cwd + ntpath.sep + path +1224 +1225 # Path normalization +1226 path = ntpath.normpath(path) +1227 path = re.sub(r'\\+', r'\\', path) +1228 +1229 if path in ["", ".", ".."]: +1230 self.smb_cwd = "" +1231 else: +1232 if self.path_isdir(pathFromRoot=path.strip(ntpath.sep)): +1233 # Path exists on the remote +1234 self.smb_cwd = ntpath.normpath(path) +1235 else: +1236 # Path does not exists or is not a directory on the remote +1237 print("[!] Remote directory '%s' does not exist." % path) @@ -1271,1067 +1432,1224 @@

    -
      20class SMBSession(object):
    -  21    """
    -  22    Class SMBSession is designed to handle the session management for SMB (Server Message Block) protocol connections.
    -  23    It provides functionalities to connect to an SMB server, authenticate using either NTLM or Kerberos, and manage SMB shares.
    -  24
    -  25    Attributes:
    -  26        address (str): The IP address or hostname of the SMB server.
    -  27        domain (str): The domain name for SMB server authentication.
    -  28        username (str): The username for SMB server authentication.
    -  29        password (str): The password for SMB server authentication.
    -  30        lmhash (str): The LM hash of the user's password, if available.
    -  31        nthash (str): The NT hash of the user's password, if available.
    -  32        use_kerberos (bool): A flag to determine whether to use Kerberos for authentication.
    -  33        kdcHost (str): The Key Distribution Center (KDC) host for Kerberos authentication.
    -  34        debug (bool): A flag to enable debug output.
    -  35        smbClient (object): The SMB client object used for the connection.
    -  36        connected (bool): A flag to check the status of the connection.
    -  37        smb_share (str): The current SMB share in use.
    -  38        smb_path (str): The current path within the SMB share.
    -  39
    -  40    Methods:
    -  41        __init__(address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, debug=False):
    -  42            Initializes the SMBSession with the specified parameters.
    -  43        init_smb_session():
    -  44            Initializes the SMB session by connecting to the server and authenticating using the specified method.
    -  45    """
    -  46
    -  47    def __init__(self, address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, config=None):
    -  48        super(SMBSession, self).__init__()
    -  49        # Objects
    -  50        self.config = config
    -  51
    -  52        # Target server
    -  53        self.address = address
    -  54
    -  55        # Credentials
    -  56        self.domain = domain
    -  57        self.username = username
    -  58        self.password = password 
    -  59        self.lmhash = lmhash
    -  60        self.nthash = nthash
    -  61        self.use_kerberos = use_kerberos
    -  62        self.kdcHost = kdcHost
    -  63
    -  64        self.smbClient = None
    -  65        self.connected = False
    -  66
    -  67        self.available_shares = {}
    -  68        self.smb_share = None
    -  69        self.smb_cwd = ""
    -  70        self.smb_tree_id = None
    -  71
    -  72        self.list_shares()
    -  73
    -  74    # Connect and disconnect SMB session
    -  75
    -  76    def init_smb_session(self):
    -  77        """
    -  78        Initializes and establishes a session with the SMB server.
    -  79
    -  80        This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.
    -  81        It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization.
    -  82
    -  83        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.
    -  84
    -  85        Returns:
    -  86            bool: True if the connection and authentication are successful, False otherwise.
    -  87        """
    -  88
    -  89        self.connected = False
    -  90
    -  91        if self.config.debug:
    -  92            print("[debug] [>] Connecting to remote SMB server '%s' ... " % self.address)
    -  93        try:
    -  94            self.smbClient = impacket.smbconnection.SMBConnection(
    -  95                remoteName=self.address,
    -  96                remoteHost=self.address,
    -  97                sess_port=int(445)
    -  98            )
    -  99        except OSError as err:
    - 100            print("[!] %s" % err)
    - 101            self.smbClient = None
    - 102
    - 103        if self.smbClient is not None:
    - 104            if self.use_kerberos:
    - 105                if self.config.debug:
    - 106                    print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... " % (self.domain, self.username))
    - 107                try:
    - 108                    self.connected = self.smbClient.kerberosLogin(
    - 109                        user=self.username,
    - 110                        password=self.password,
    - 111                        domain=self.domain,
    - 112                        lmhash=self.lmhash,
    - 113                        nthash=self.nthash,
    - 114                        aesKey=self.aesKey,
    - 115                        kdcHost=self.kdcHost
    - 116                    )
    - 117                except impacket.smbconnection.SessionError as err:
    - 118                    if self.config.debug:
    - 119                        traceback.print_exc()
    - 120                    print("[!] Could not login: %s" % err)
    - 121                    self.connected = False
    - 122
    - 123            else:
    - 124                if self.config.debug:
    - 125                    print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... " % (self.domain, self.username))
    - 126                try:
    - 127                    self.connected = self.smbClient.login(
    - 128                        user=self.username,
    - 129                        password=self.password,
    - 130                        domain=self.domain,
    - 131                        lmhash=self.lmhash,
    - 132                        nthash=self.nthash
    - 133                    )
    - 134                except impacket.smbconnection.SessionError as err:
    - 135                    if self.config.debug:
    - 136                        traceback.print_exc()
    - 137                    print("[!] Could not login: %s" % err)
    - 138                    self.connected = False
    - 139
    - 140            if self.connected:
    - 141                print("[+] Successfully authenticated to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username))
    - 142            else:
    - 143                print("[!] Failed to authenticate to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username))
    - 144
    - 145        return self.connected
    - 146
    - 147    def close_smb_session(self):
    - 148        """
    - 149        Closes the current SMB session by disconnecting the SMB client.
    - 150
    - 151        This method ensures that the SMB client connection is properly closed. It checks if the client is connected
    - 152        and if so, it closes the connection and resets the connection status.
    - 153
    - 154        Raises:
    - 155            Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
    - 156        """
    - 157
    - 158        if self.smbClient is not None:
    - 159            if self.connected:
    - 160                self.smbClient.close()
    - 161                self.connected = False
    - 162                if self.config.debug:
    - 163                    print("[+] SMB connection closed successfully.")
    - 164            else:
    - 165                if self.config.debug:
    - 166                    print("[!] No active SMB connection to close.")
    - 167        else:
    - 168            raise Exception("SMB client is not initialized.")
    - 169
    - 170    # Operations
    - 171
    - 172    def read_file(self, path=None):
    - 173        if self.path_isfile(path=path):
    - 174            tmp_file_path = self.smb_cwd + ntpath.sep + path
    - 175            matches = self.smbClient.listPath(
    - 176                shareName=self.smb_share, 
    - 177                path=tmp_file_path
    - 178            )
    - 179
    - 180            fh = io.BytesIO()
    - 181            try:
    - 182                # opening the files in streams instead of mounting shares allows 
    - 183                # for running the script from unprivileged containers
    - 184                self.smbClient.getFile(self.smb_share, tmp_file_path, fh.write)
    - 185            except impacket.smbconnection.SessionError as e:
    - 186                return None
    - 187            rawdata = fh.getvalue()
    - 188            fh.close()
    - 189            return rawdata
    - 190        else:
    - 191            print("[!] Remote path '%s' is not a file." % path)
    - 192
    - 193    def find(self, paths=[], callback=None):
    - 194        def recurse_action(paths=[], depth=0, callback=None):
    - 195            if callback is None:
    - 196                return []
    - 197            
    - 198            next_directories_to_explore = []
    - 199
    - 200            for path in paths:
    - 201                remote_smb_path = ntpath.normpath(self.smb_cwd + ntpath.sep + path)
    - 202                entries = []
    - 203                
    - 204                try:
    - 205                    entries = self.smbClient.listPath(
    - 206                        shareName=self.smb_share, 
    - 207                        path=(remote_smb_path + ntpath.sep + '*')
    - 208                    )
    - 209                except impacket.smbconnection.SessionError as err:
    - 210                    continue 
    - 211                # Remove dot names
    - 212                entries = [e for e in entries if e.get_longname() not in [".", ".."]]
    - 213                # Sort the entries ignoring case
    - 214                entries = sorted(entries, key=lambda x:x.get_longname().lower())
    - 215                
    - 216                for entry in entries:
    - 217                    if entry.is_directory():
    - 218                        callback(entry, path + ntpath.sep + entry.get_longname() + ntpath.sep, depth)
    - 219                    else:
    - 220                        callback(entry, path + ntpath.sep + entry.get_longname(), depth)
    - 221
    - 222                # Next directories to explore
    - 223                for entry in entries:
    - 224                    if entry.is_directory():
    - 225                        next_directories_to_explore.append(path + ntpath.sep + entry.get_longname() + ntpath.sep)
    - 226            
    - 227            return next_directories_to_explore
    - 228        # 
    - 229        if callback is not None:
    - 230            depth = 0
    - 231            while len(paths) != 0:
    - 232                paths = recurse_action(
    - 233                    paths=paths,
    - 234                    depth=depth,
    - 235                    callback=callback
    - 236                )
    - 237                depth = depth + 1
    - 238        else:
    - 239            print("[!] SMBSession.find(), callback function cannot be None.")
    - 240
    - 241    def get_file(self, path=None, keepRemotePath=False):
    - 242        """
    - 243        Retrieves a file from the specified path on the SMB share.
    - 244
    - 245        This method attempts to retrieve a file from the given path within the currently connected SMB share.
    - 246        If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local
    - 247        file object and writing the contents of the remote file to it using the SMB client's getFile method.
    - 248
    - 249        Parameters:
    - 250            path (str): The path of the file to retrieve. If None, uses the current smb_path.
    - 251
    - 252        Returns:
    - 253            None
    - 254        """
    - 255
    - 256        tmp_file_path = self.smb_cwd + ntpath.sep + path
    - 257        matches = self.smbClient.listPath(
    - 258            shareName=self.smb_share, 
    - 259            path=tmp_file_path
    - 260        )
    - 261        
    - 262        for entry in matches:
    - 263            if entry.is_directory():
    - 264                print("[>] Skipping '%s' because it is a directory." % tmp_file_path)
    - 265            else:
    - 266                try:
    - 267                    if ntpath.sep in path:
    - 268                        outputfile = ntpath.dirname(path) + ntpath.sep + entry.get_longname()
    - 269                    else:
    - 270                        outputfile = entry.get_longname()
    - 271                    f = LocalFileIO(
    - 272                        mode="wb", 
    - 273                        path=outputfile,
    - 274                        expected_size=entry.get_filesize(), 
    - 275                        debug=self.config.debug,
    - 276                        keepRemotePath=keepRemotePath
    - 277                    )
    - 278                    self.smbClient.getFile(
    - 279                        shareName=self.smb_share, 
    - 280                        pathName=tmp_file_path, 
    - 281                        callback=f.write
    - 282                    )
    - 283                    f.close()
    - 284                except (BrokenPipeError, KeyboardInterrupt) as e:
    - 285                    f.close()
    - 286                    print("\x1b[v\x1b[o\r[!] Interrupted.")
    - 287                    self.close_smb_session()
    - 288                    self.init_smb_session()
    - 289                        
    - 290        return None
    - 291
    - 292    def get_file_recursively(self, path=None):
    - 293        """
    - 294        Recursively retrieves files from a specified path on the SMB share.
    - 295
    - 296        This method navigates through all directories starting from the given path,
    - 297        and downloads all files found. It handles directories recursively, ensuring
    - 298        that all nested files are retrieved. The method skips over directory entries
    - 299        and handles errors gracefully, attempting to continue the operation where possible.
    - 300
    - 301        Parameters:
    - 302            path (str): The initial directory path from which to start the recursive file retrieval.
    - 303                        If None, it starts from the root of the configured SMB share.
    - 304        """
    - 305        
    - 306        def recurse_action(base_dir="", path=[]):
    - 307            if len(base_dir) == 0:
    - 308                remote_smb_path = ntpath.sep.join(path)
    - 309            else:
    - 310                remote_smb_path = base_dir + ntpath.sep + ntpath.sep.join(path)
    - 311            remote_smb_path = ntpath.normpath(remote_smb_path)
    - 312
    - 313            entries = self.smbClient.listPath(
    - 314                shareName=self.smb_share, 
    - 315                path=remote_smb_path + '\\*'
    - 316            )
    - 317            if len(entries) != 0:
    - 318                files = [entry for entry in entries if not entry.is_directory()]
    - 319                directories = [entry for entry in entries if entry.is_directory() and entry.get_longname() not in [".", ".."]]
    - 320
    - 321                # Files
    - 322                if len(files) != 0:
    - 323                    print("[>] Retrieving files of '%s'" % remote_smb_path)
    - 324                for entry_file in files:
    - 325                    if not entry_file.is_directory():
    - 326                        f = LocalFileIO(
    - 327                            mode="wb",
    - 328                            path=remote_smb_path + ntpath.sep + entry_file.get_longname(), 
    - 329                            expected_size=entry_file.get_filesize(),
    - 330                            keepRemotePath=True,
    - 331                            debug=self.config.debug
    - 332                        )
    - 333                        try:
    - 334                            self.smbClient.getFile(
    - 335                                shareName=self.smb_share, 
    - 336                                pathName=remote_smb_path + ntpath.sep + entry_file.get_longname(), 
    - 337                                callback=f.write
    - 338                            )
    - 339                            f.close()
    - 340                        except BrokenPipeError as err:
    - 341                            f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err))
    - 342                            f.close(remove=True)
    - 343                            break
    - 344                        except Exception as err:
    - 345                            f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err))
    - 346                            f.close(remove=True)
    - 347                
    - 348                # Directories
    - 349                for entry_directory in directories:
    - 350                    if entry_directory.is_directory():
    - 351                        recurse_action(
    - 352                            base_dir=self.smb_cwd, 
    - 353                            path=path+[entry_directory.get_longname()]
    - 354                        )                   
    - 355        # Entrypoint
    - 356        try:
    - 357            recurse_action(
    - 358                base_dir=self.smb_cwd, 
    - 359                path=[path]
    - 360            )
    - 361        except (BrokenPipeError, KeyboardInterrupt) as e:
    - 362            print("\x1b[v\x1b[o\r[!] Interrupted.")
    - 363            self.close_smb_session()
    - 364            self.init_smb_session()
    - 365
    - 366    def get_entry(self, path=None):
    - 367        """
    - 368        Retrieves information about a specific entry located at the provided path on the SMB share.
    - 369
    - 370        This method checks if the specified path exists on the SMB share. If the path exists, it retrieves the details of the entry at that path, including the directory name and file name. If the entry is found, it returns the entry object; otherwise, it returns None.
    - 371
    - 372        Args:
    - 373            path (str): The path of the entry to retrieve information about.
    - 374
    - 375        Returns:
    - 376            Entry: An object representing the entry at the specified path, or None if the entry is not found.
    - 377        """
    - 378
    - 379        if self.path_exists(path=path):
    - 380            matches = self.smbClient.listPath(shareName=self.smb_share, path=path)
    - 381
    - 382            if len(matches) == 1:
    - 383                return matches[0]
    - 384            else:
    - 385                return None
    - 386            
    - 387        else:
    - 388            return None 
    - 389
    - 390    def info(self, share=True, server=True):
    - 391        """
    - 392        Displays information about the server and optionally the shares.
    - 393
    - 394        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.
    +            
      21class SMBSession(object):
    +  22    """
    +  23    Class SMBSession is designed to handle the session management for SMB (Server Message Block) protocol connections.
    +  24    It provides functionalities to connect to an SMB server, authenticate using either NTLM or Kerberos, and manage SMB shares.
    +  25
    +  26    Attributes:
    +  27        address (str): The IP address or hostname of the SMB server.
    +  28        domain (str): The domain name for SMB server authentication.
    +  29        username (str): The username for SMB server authentication.
    +  30        password (str): The password for SMB server authentication.
    +  31        lmhash (str): The LM hash of the user's password, if available.
    +  32        nthash (str): The NT hash of the user's password, if available.
    +  33        use_kerberos (bool): A flag to determine whether to use Kerberos for authentication.
    +  34        kdcHost (str): The Key Distribution Center (KDC) host for Kerberos authentication.
    +  35        debug (bool): A flag to enable debug output.
    +  36        smbClient (object): The SMB client object used for the connection.
    +  37        connected (bool): A flag to check the status of the connection.
    +  38        smb_share (str): The current SMB share in use.
    +  39        smb_path (str): The current path within the SMB share.
    +  40
    +  41    Methods:
    +  42        __init__(address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, debug=False):
    +  43            Initializes the SMBSession with the specified parameters.
    +  44        init_smb_session():
    +  45            Initializes the SMB session by connecting to the server and authenticating using the specified method.
    +  46    """
    +  47
    +  48    def __init__(self, address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, config=None):
    +  49        super(SMBSession, self).__init__()
    +  50        # Objects
    +  51        self.config = config
    +  52
    +  53        # Target server
    +  54        self.address = address
    +  55
    +  56        # Credentials
    +  57        self.domain = domain
    +  58        self.username = username
    +  59        self.password = password 
    +  60        self.lmhash = lmhash
    +  61        self.nthash = nthash
    +  62        self.use_kerberos = use_kerberos
    +  63        self.kdcHost = kdcHost
    +  64
    +  65        self.smbClient = None
    +  66        self.connected = False
    +  67
    +  68        self.available_shares = {}
    +  69        self.smb_share = None
    +  70        self.smb_cwd = ""
    +  71        self.smb_tree_id = None
    +  72
    +  73        self.list_shares()
    +  74
    +  75    # Connect and disconnect SMB session
    +  76
    +  77    def init_smb_session(self):
    +  78        """
    +  79        Initializes and establishes a session with the SMB server.
    +  80
    +  81        This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.
    +  82        It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization.
    +  83
    +  84        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.
    +  85
    +  86        Returns:
    +  87            bool: True if the connection and authentication are successful, False otherwise.
    +  88        """
    +  89
    +  90        self.connected = False
    +  91
    +  92        if self.config.debug:
    +  93            print("[debug] [>] Connecting to remote SMB server '%s' ... " % self.address)
    +  94        try:
    +  95            self.smbClient = impacket.smbconnection.SMBConnection(
    +  96                remoteName=self.address,
    +  97                remoteHost=self.address,
    +  98                sess_port=int(445)
    +  99            )
    + 100        except OSError as err:
    + 101            print("[!] %s" % err)
    + 102            self.smbClient = None
    + 103
    + 104        if self.smbClient is not None:
    + 105            if self.use_kerberos:
    + 106                if self.config.debug:
    + 107                    print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... " % (self.domain, self.username))
    + 108                try:
    + 109                    self.connected = self.smbClient.kerberosLogin(
    + 110                        user=self.username,
    + 111                        password=self.password,
    + 112                        domain=self.domain,
    + 113                        lmhash=self.lmhash,
    + 114                        nthash=self.nthash,
    + 115                        aesKey=self.aesKey,
    + 116                        kdcHost=self.kdcHost
    + 117                    )
    + 118                except impacket.smbconnection.SessionError as err:
    + 119                    if self.config.debug:
    + 120                        traceback.print_exc()
    + 121                    print("[!] Could not login: %s" % err)
    + 122                    self.connected = False
    + 123
    + 124            else:
    + 125                if self.config.debug:
    + 126                    print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... " % (self.domain, self.username))
    + 127                try:
    + 128                    self.connected = self.smbClient.login(
    + 129                        user=self.username,
    + 130                        password=self.password,
    + 131                        domain=self.domain,
    + 132                        lmhash=self.lmhash,
    + 133                        nthash=self.nthash
    + 134                    )
    + 135                except impacket.smbconnection.SessionError as err:
    + 136                    if self.config.debug:
    + 137                        traceback.print_exc()
    + 138                    print("[!] Could not login: %s" % err)
    + 139                    self.connected = False
    + 140
    + 141            if self.connected:
    + 142                print("[+] Successfully authenticated to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username))
    + 143            else:
    + 144                print("[!] Failed to authenticate to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username))
    + 145
    + 146        return self.connected
    + 147
    + 148    def close_smb_session(self):
    + 149        """
    + 150        Closes the current SMB session by disconnecting the SMB client.
    + 151
    + 152        This method ensures that the SMB client connection is properly closed. It checks if the client is connected
    + 153        and if so, it closes the connection and resets the connection status.
    + 154
    + 155        Raises:
    + 156            Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
    + 157        """
    + 158
    + 159        if self.smbClient is not None:
    + 160            if self.connected:
    + 161                self.smbClient.close()
    + 162                self.connected = False
    + 163                if self.config.debug:
    + 164                    print("[+] SMB connection closed successfully.")
    + 165            else:
    + 166                if self.config.debug:
    + 167                    print("[!] No active SMB connection to close.")
    + 168        else:
    + 169            raise Exception("SMB client is not initialized.")
    + 170
    + 171    # Operations
    + 172
    + 173    def read_file(self, path=None):
    + 174        if self.path_isfile(path=path):
    + 175            tmp_file_path = self.smb_cwd + ntpath.sep + path
    + 176            matches = self.smbClient.listPath(
    + 177                shareName=self.smb_share, 
    + 178                path=tmp_file_path
    + 179            )
    + 180
    + 181            fh = io.BytesIO()
    + 182            try:
    + 183                # opening the files in streams instead of mounting shares allows 
    + 184                # for running the script from unprivileged containers
    + 185                self.smbClient.getFile(self.smb_share, tmp_file_path, fh.write)
    + 186            except impacket.smbconnection.SessionError as e:
    + 187                return None
    + 188            rawdata = fh.getvalue()
    + 189            fh.close()
    + 190            return rawdata
    + 191        else:
    + 192            print("[!] Remote path '%s' is not a file." % path)
    + 193
    + 194    def find(self, paths=[], callback=None):
    + 195        def recurse_action(paths=[], depth=0, callback=None):
    + 196            if callback is None:
    + 197                return []
    + 198            
    + 199            next_directories_to_explore = []
    + 200
    + 201            for path in paths:
    + 202                remote_smb_path = ntpath.normpath(self.smb_cwd + ntpath.sep + path)
    + 203                entries = []
    + 204                
    + 205                try:
    + 206                    entries = self.smbClient.listPath(
    + 207                        shareName=self.smb_share, 
    + 208                        path=(remote_smb_path + ntpath.sep + '*')
    + 209                    )
    + 210                except impacket.smbconnection.SessionError as err:
    + 211                    continue 
    + 212                # Remove dot names
    + 213                entries = [e for e in entries if e.get_longname() not in [".", ".."]]
    + 214                # Sort the entries ignoring case
    + 215                entries = sorted(entries, key=lambda x:x.get_longname().lower())
    + 216                
    + 217                for entry in entries:
    + 218                    if entry.is_directory():
    + 219                        callback(entry, path + ntpath.sep + entry.get_longname() + ntpath.sep, depth)
    + 220                    else:
    + 221                        callback(entry, path + ntpath.sep + entry.get_longname(), depth)
    + 222
    + 223                # Next directories to explore
    + 224                for entry in entries:
    + 225                    if entry.is_directory():
    + 226                        next_directories_to_explore.append(path + ntpath.sep + entry.get_longname() + ntpath.sep)
    + 227            
    + 228            return next_directories_to_explore
    + 229        # 
    + 230        if callback is not None:
    + 231            depth = 0
    + 232            while len(paths) != 0:
    + 233                paths = recurse_action(
    + 234                    paths=paths,
    + 235                    depth=depth,
    + 236                    callback=callback
    + 237                )
    + 238                depth = depth + 1
    + 239        else:
    + 240            print("[!] SMBSession.find(), callback function cannot be None.")
    + 241
    + 242    def get_file(self, path=None, keepRemotePath=False):
    + 243        """
    + 244        Retrieves a file from the specified path on the SMB share.
    + 245
    + 246        This method attempts to retrieve a file from the given path within the currently connected SMB share.
    + 247        If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local
    + 248        file object and writing the contents of the remote file to it using the SMB client's getFile method.
    + 249
    + 250        Parameters:
    + 251            path (str): The path of the file to retrieve. If None, uses the current smb_path.
    + 252
    + 253        Returns:
    + 254            None
    + 255        """
    + 256
    + 257        # Parse path
    + 258        path = path.replace('/', ntpath.sep)
    + 259        if ntpath.sep in path:
    + 260            tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep + ntpath.dirname(path))
    + 261        else:
    + 262            tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep)
    + 263        # Parse filename
    + 264        filename = ntpath.basename(path)
    + 265
    + 266        # Search for the file
    + 267        matches = self.smbClient.listPath(
    + 268            shareName=self.smb_share, 
    + 269            path=tmp_search_path + ntpath.sep + '*'
    + 270        )   
    + 271
    + 272        # Filter the entries
    + 273        matching_entries = []
    + 274        for entry in matches:
    + 275            if entry.is_directory():
    + 276                # Skip directories
    + 277                continue
    + 278            if entry.get_longname() == filename:
    + 279                matching_entries.append(entry)
    + 280            elif '*' in filename:
    + 281                regexp = filename.replace('.', '\\.').replace('*', '.*')
    + 282                if re.match(regexp, entry.get_longname()):
    + 283                    matching_entries.append(entry)
    + 284        
    + 285        matching_entries = sorted(list(set(matching_entries)), key=lambda x: x.get_longname())
    + 286
    + 287        for entry in matching_entries:
    + 288            if entry.is_directory():
    + 289                if self.config.debug:
    + 290                    print("[debug] [>] Skipping '%s' because it is a directory." % (tmp_search_path + ntpath.sep + entry.get_longname()))
    + 291            else:
    + 292                try:
    + 293                    if ntpath.sep in path:
    + 294                        outputfile = ntpath.dirname(path) + ntpath.sep + entry.get_longname()
    + 295                    else:
    + 296                        outputfile = entry.get_longname()
    + 297                    f = LocalFileIO(
    + 298                        mode="wb", 
    + 299                        path=outputfile,
    + 300                        expected_size=entry.get_filesize(), 
    + 301                        debug=self.config.debug,
    + 302                        keepRemotePath=keepRemotePath
    + 303                    )
    + 304                    self.smbClient.getFile(
    + 305                        shareName=self.smb_share, 
    + 306                        pathName=tmp_search_path + ntpath.sep + entry.get_longname(), 
    + 307                        callback=f.write
    + 308                    )
    + 309                    f.close()
    + 310                except (BrokenPipeError, KeyboardInterrupt) as e:
    + 311                    f.close()
    + 312                    print("\x1b[v\x1b[o\r[!] Interrupted.")
    + 313                    self.close_smb_session()
    + 314                    self.init_smb_session()
    + 315                        
    + 316        return None
    + 317
    + 318    def get_file_recursively(self, path=None):
    + 319        """
    + 320        Recursively retrieves files from a specified path on the SMB share.
    + 321
    + 322        This method navigates through all directories starting from the given path,
    + 323        and downloads all files found. It handles directories recursively, ensuring
    + 324        that all nested files are retrieved. The method skips over directory entries
    + 325        and handles errors gracefully, attempting to continue the operation where possible.
    + 326
    + 327        Parameters:
    + 328            path (str): The initial directory path from which to start the recursive file retrieval.
    + 329                        If None, it starts from the root of the configured SMB share.
    + 330        """
    + 331        
    + 332        def recurse_action(base_dir="", path=[]):
    + 333            if len(base_dir) == 0:
    + 334                remote_smb_path = ntpath.sep.join(path)
    + 335            else:
    + 336                remote_smb_path = base_dir + ntpath.sep + ntpath.sep.join(path)
    + 337            remote_smb_path = ntpath.normpath(remote_smb_path)
    + 338
    + 339            entries = self.smbClient.listPath(
    + 340                shareName=self.smb_share, 
    + 341                path=remote_smb_path + '\\*'
    + 342            )
    + 343            if len(entries) != 0:
    + 344                files = [entry for entry in entries if not entry.is_directory()]
    + 345                directories = [entry for entry in entries if entry.is_directory() and entry.get_longname() not in [".", ".."]]
    + 346
    + 347                # Files
    + 348                if len(files) != 0:
    + 349                    print("[>] Retrieving files of '%s'" % remote_smb_path)
    + 350                for entry_file in files:
    + 351                    if not entry_file.is_directory():
    + 352                        f = LocalFileIO(
    + 353                            mode="wb",
    + 354                            path=remote_smb_path + ntpath.sep + entry_file.get_longname(), 
    + 355                            expected_size=entry_file.get_filesize(),
    + 356                            keepRemotePath=True,
    + 357                            debug=self.config.debug
    + 358                        )
    + 359                        try:
    + 360                            self.smbClient.getFile(
    + 361                                shareName=self.smb_share, 
    + 362                                pathName=remote_smb_path + ntpath.sep + entry_file.get_longname(), 
    + 363                                callback=f.write
    + 364                            )
    + 365                            f.close()
    + 366                        except BrokenPipeError as err:
    + 367                            f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err))
    + 368                            f.close(remove=True)
    + 369                            break
    + 370                        except Exception as err:
    + 371                            f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err))
    + 372                            f.close(remove=True)
    + 373                
    + 374                # Directories
    + 375                for entry_directory in directories:
    + 376                    if entry_directory.is_directory():
    + 377                        recurse_action(
    + 378                            base_dir=self.smb_cwd, 
    + 379                            path=path+[entry_directory.get_longname()]
    + 380                        )                   
    + 381        # Entrypoint
    + 382        try:
    + 383            recurse_action(
    + 384                base_dir=self.smb_cwd, 
    + 385                path=[path]
    + 386            )
    + 387        except (BrokenPipeError, KeyboardInterrupt) as e:
    + 388            print("\x1b[v\x1b[o\r[!] Interrupted.")
    + 389            self.close_smb_session()
    + 390            self.init_smb_session()
    + 391
    + 392    def get_entry(self, path=None):
    + 393        """
    + 394        Retrieves information about a specific entry located at the provided path on the SMB share.
      395
    - 396        Parameters:
    - 397            share (bool): If True, display information about the current share.
    - 398            server (bool): If True, display information about the server.
    - 399
    - 400        Returns:
    - 401            None
    - 402        """
    - 403
    - 404        if server:
    - 405            if self.config.no_colors:
    - 406                print("[+] Server:")
    - 407                print("  ├─NetBIOS:")
    - 408                print("  │ ├─ NetBIOS Hostname ──────── : %s" % (self.smbClient.getServerName()))
    - 409                print("  │ └─ NetBIOS Domain ────────── : %s" % (self.smbClient.getServerDomain()))
    - 410                print("  ├─DNS:")
    - 411                print("  │ ├─ DNS Hostname ──────────── : %s" % (self.smbClient.getServerDNSHostName()))
    - 412                print("  │ └─ DNS Domain ────────────── : %s" % (self.smbClient.getServerDNSDomainName()))
    - 413                print("  ├─OS:")
    - 414                print("  │ ├─ OS Name ───────────────── : %s" % (self.smbClient.getServerOS()))
    - 415                print("  │ └─ OS Version ────────────── : %s.%s.%s" % (self.smbClient.getServerOSMajor(), self.smbClient.getServerOSMinor(), self.smbClient.getServerOSBuild()))
    - 416                print("  ├─Server:")
    - 417                print("  │ ├─ Signing Required ──────── : %s" % (self.smbClient.isSigningRequired()))
    - 418                print("  │ ├─ Login Required ────────── : %s" % (self.smbClient.isLoginRequired()))
    - 419                print("  │ ├─ Supports NTLMv2 ───────── : %s" % (self.smbClient.doesSupportNTLMv2()))
    - 420                MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"]
    - 421                print("  │ ├─ Max size of read chunk ── : %d bytes (%s)" % (MaxReadSize, b_filesize(MaxReadSize)))
    - 422                MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"]
    - 423                print("  │ └─ Max size of write chunk ─ : %d bytes (%s)" % (MaxWriteSize, b_filesize(MaxWriteSize)))
    - 424                print("  └─")
    - 425            else:
    - 426                print("[+] Server:")
    - 427                print("  ├─NetBIOS:")
    - 428                print("  │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerName()))
    - 429                print("  │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDomain()))
    - 430                print("  ├─DNS:")
    - 431                print("  │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSHostName()))
    - 432                print("  │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSDomainName()))
    - 433                print("  ├─OS:")
    - 434                print("  │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerOS()))
    - 435                print("  │ └─ \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()))
    - 436                print("  ├─Server:")
    - 437                print("  │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isSigningRequired()))
    - 438                print("  │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isLoginRequired()))
    - 439                print("  │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.doesSupportNTLMv2()))
    - 440                MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"]
    - 441                print("  │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxReadSize, b_filesize(MaxReadSize)))
    - 442                MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"]
    - 443                print("  │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxWriteSize, b_filesize(MaxWriteSize)))
    - 444                print("  └─")
    - 445
    - 446        if share and self.smb_share is not None:
    - 447            share_name = self.available_shares.get(self.smb_share.lower(), "")["name"]
    - 448            share_comment = self.available_shares.get(self.smb_share.lower(), "")["comment"]
    - 449            share_type = self.available_shares.get(self.smb_share.lower(), "")["type"]
    - 450            share_type =', '.join([s.replace("STYPE_","") for s in share_type])
    - 451            share_rawtype = self.available_shares.get(self.smb_share.lower(), "")["rawtype"]
    - 452            if self.config.no_colors:
    - 453                print("\n[+] Share:")
    - 454                print("  ├─ Name ──────────── : %s" % (share_name))
    - 455                print("  ├─ Description ───── : %s" % (share_comment))
    - 456                print("  ├─ Type ──────────── : %s" % (share_type))
    - 457                print("  └─ Raw type value ── : %s" % (share_rawtype))
    - 458            else:
    - 459                print("\n[+] Share:")
    - 460                print("  ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_name))
    - 461                print("  ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_comment))
    - 462                print("  ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_type))
    - 463                print("  └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m" % (share_rawtype))
    - 464
    - 465    def list_contents(self, path=None):
    - 466        """
    - 467        Lists the contents of a specified directory on the SMB share.
    - 468
    - 469        This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path`
    - 470        is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with
    - 471        the long names of the files and directories as keys and their respective SMB entry objects as values.
    - 472
    - 473        Args:
    - 474            shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.
    - 475            path (str, optional): The directory path to list contents from. Defaults to the current path if None.
    - 476
    - 477        Returns:
    - 478            dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
    - 479        """
    - 480        
    - 481        dest_path = [self.smb_cwd.rstrip(ntpath.sep),]
    - 482        if path is not None and len(path) > 0:
    - 483            dest_path.append(path.rstrip(ntpath.sep))
    - 484        dest_path.append('*')
    - 485        path = ntpath.sep.join(dest_path)
    - 486
    - 487        contents = {}
    - 488        entries = self.smbClient.listPath(
    - 489            shareName=self.smb_share, 
    - 490            path=path
    - 491        )
    - 492        for entry in entries:
    - 493            contents[entry.get_longname()] = entry
    + 396        This method checks if the specified path exists on the SMB share. If the path exists, it retrieves the details of the entry at that path, including the directory name and file name. If the entry is found, it returns the entry object; otherwise, it returns None.
    + 397
    + 398        Args:
    + 399            path (str): The path of the entry to retrieve information about.
    + 400
    + 401        Returns:
    + 402            Entry: An object representing the entry at the specified path, or None if the entry is not found.
    + 403        """
    + 404
    + 405        if self.path_exists(path=path):
    + 406            matches = self.smbClient.listPath(shareName=self.smb_share, path=path)
    + 407
    + 408            if len(matches) == 1:
    + 409                return matches[0]
    + 410            else:
    + 411                return None
    + 412            
    + 413        else:
    + 414            return None 
    + 415
    + 416    def info(self, share=True, server=True):
    + 417        """
    + 418        Displays information about the server and optionally the shares.
    + 419
    + 420        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.
    + 421
    + 422        Parameters:
    + 423            share (bool): If True, display information about the current share.
    + 424            server (bool): If True, display information about the server.
    + 425
    + 426        Returns:
    + 427            None
    + 428        """
    + 429
    + 430        if server:
    + 431            if self.config.no_colors:
    + 432                print("[+] Server:")
    + 433                print("  ├─NetBIOS:")
    + 434                print("  │ ├─ NetBIOS Hostname ──────── : %s" % (self.smbClient.getServerName()))
    + 435                print("  │ └─ NetBIOS Domain ────────── : %s" % (self.smbClient.getServerDomain()))
    + 436                print("  ├─DNS:")
    + 437                print("  │ ├─ DNS Hostname ──────────── : %s" % (self.smbClient.getServerDNSHostName()))
    + 438                print("  │ └─ DNS Domain ────────────── : %s" % (self.smbClient.getServerDNSDomainName()))
    + 439                print("  ├─OS:")
    + 440                print("  │ ├─ OS Name ───────────────── : %s" % (self.smbClient.getServerOS()))
    + 441                print("  │ └─ OS Version ────────────── : %s.%s.%s" % (self.smbClient.getServerOSMajor(), self.smbClient.getServerOSMinor(), self.smbClient.getServerOSBuild()))
    + 442                print("  ├─Server:")
    + 443                print("  │ ├─ Signing Required ──────── : %s" % (self.smbClient.isSigningRequired()))
    + 444                print("  │ ├─ Login Required ────────── : %s" % (self.smbClient.isLoginRequired()))
    + 445                print("  │ ├─ Supports NTLMv2 ───────── : %s" % (self.smbClient.doesSupportNTLMv2()))
    + 446                MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"]
    + 447                print("  │ ├─ Max size of read chunk ── : %d bytes (%s)" % (MaxReadSize, b_filesize(MaxReadSize)))
    + 448                MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"]
    + 449                print("  │ └─ Max size of write chunk ─ : %d bytes (%s)" % (MaxWriteSize, b_filesize(MaxWriteSize)))
    + 450                print("  └─")
    + 451            else:
    + 452                print("[+] Server:")
    + 453                print("  ├─NetBIOS:")
    + 454                print("  │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerName()))
    + 455                print("  │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDomain()))
    + 456                print("  ├─DNS:")
    + 457                print("  │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSHostName()))
    + 458                print("  │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSDomainName()))
    + 459                print("  ├─OS:")
    + 460                print("  │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerOS()))
    + 461                print("  │ └─ \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()))
    + 462                print("  ├─Server:")
    + 463                print("  │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isSigningRequired()))
    + 464                print("  │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isLoginRequired()))
    + 465                print("  │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.doesSupportNTLMv2()))
    + 466                MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"]
    + 467                print("  │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxReadSize, b_filesize(MaxReadSize)))
    + 468                MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"]
    + 469                print("  │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxWriteSize, b_filesize(MaxWriteSize)))
    + 470                print("  └─")
    + 471
    + 472        if share and self.smb_share is not None:
    + 473            share_name = self.available_shares.get(self.smb_share.lower(), "")["name"]
    + 474            share_comment = self.available_shares.get(self.smb_share.lower(), "")["comment"]
    + 475            share_type = self.available_shares.get(self.smb_share.lower(), "")["type"]
    + 476            share_type =', '.join([s.replace("STYPE_","") for s in share_type])
    + 477            share_rawtype = self.available_shares.get(self.smb_share.lower(), "")["rawtype"]
    + 478            if self.config.no_colors:
    + 479                print("\n[+] Share:")
    + 480                print("  ├─ Name ──────────── : %s" % (share_name))
    + 481                print("  ├─ Description ───── : %s" % (share_comment))
    + 482                print("  ├─ Type ──────────── : %s" % (share_type))
    + 483                print("  └─ Raw type value ── : %s" % (share_rawtype))
    + 484            else:
    + 485                print("\n[+] Share:")
    + 486                print("  ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_name))
    + 487                print("  ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_comment))
    + 488                print("  ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_type))
    + 489                print("  └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m" % (share_rawtype))
    + 490
    + 491    def list_contents(self, path=None):
    + 492        """
    + 493        Lists the contents of a specified directory on the SMB share.
      494
    - 495        return contents
    - 496
    - 497    def list_shares(self):
    - 498        """
    - 499        Lists all the shares available on the connected SMB server.
    - 500
    - 501        This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary
    - 502        with key-value pairs where the key is the share name and the value is a dictionary containing details about the share
    - 503        such as its name, type, raw type, and any comments associated with the share.
    - 504
    - 505        Returns:
    - 506            dict: A dictionary containing information about each share available on the server.
    - 507        """
    - 508
    - 509        self.available_shares = {}
    - 510
    - 511        if self.connected:
    - 512            if self.smbClient is not None:
    - 513                resp = self.smbClient.listShares()
    - 514
    - 515                for share in resp:
    - 516                    # SHARE_INFO_1 structure (lmshare.h)
    - 517                    # https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1
    - 518                    sharename = share["shi1_netname"][:-1]
    - 519                    sharecomment = share["shi1_remark"][:-1]
    - 520                    sharetype = share["shi1_type"]
    - 521
    - 522                    self.available_shares[sharename.lower()] = {
    - 523                        "name": sharename, 
    - 524                        "type": STYPE_MASK(sharetype), 
    - 525                        "rawtype": sharetype, 
    - 526                        "comment": sharecomment
    - 527                    }
    - 528            else:
    - 529                print("[!] Error: SMBSession.smbClient is None.")
    + 495        This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path`
    + 496        is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with
    + 497        the long names of the files and directories as keys and their respective SMB entry objects as values.
    + 498
    + 499        Args:
    + 500            shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.
    + 501            path (str, optional): The directory path to list contents from. Defaults to the current path if None.
    + 502
    + 503        Returns:
    + 504            dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
    + 505        """
    + 506        
    + 507        dest_path = [self.smb_cwd.rstrip(ntpath.sep),]
    + 508        if path is not None and len(path) > 0:
    + 509            dest_path.append(path.rstrip(ntpath.sep))
    + 510        dest_path.append('*')
    + 511        path = ntpath.sep.join(dest_path)
    + 512
    + 513        contents = {}
    + 514        entries = self.smbClient.listPath(
    + 515            shareName=self.smb_share, 
    + 516            path=path
    + 517        )
    + 518        for entry in entries:
    + 519            contents[entry.get_longname()] = entry
    + 520
    + 521        return contents
    + 522
    + 523    def list_shares(self):
    + 524        """
    + 525        Lists all the shares available on the connected SMB server.
    + 526
    + 527        This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary
    + 528        with key-value pairs where the key is the share name and the value is a dictionary containing details about the share
    + 529        such as its name, type, raw type, and any comments associated with the share.
      530
    - 531        return self.available_shares
    - 532
    - 533    def mkdir(self, path=None):
    - 534        """
    - 535        Creates a directory at the specified path on the SMB share.
    + 531        Returns:
    + 532            dict: A dictionary containing information about each share available on the server.
    + 533        """
    + 534
    + 535        self.available_shares = {}
      536
    - 537        This method takes a path and attempts to create the directory structure on the SMB share. If the path includes
    - 538        nested directories, it will create each directory in the sequence. If a directory already exists, it will skip
    - 539        the creation for that directory without raising an error.
    + 537        if self.connected:
    + 538            if self.smbClient is not None:
    + 539                resp = self.smbClient.listShares()
      540
    - 541        Args:
    - 542            path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
    - 543
    - 544        Note:
    - 545            The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
    - 546        """
    + 541                for share in resp:
    + 542                    # SHARE_INFO_1 structure (lmshare.h)
    + 543                    # https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1
    + 544                    sharename = share["shi1_netname"][:-1]
    + 545                    sharecomment = share["shi1_remark"][:-1]
    + 546                    sharetype = share["shi1_type"]
      547
    - 548        if path is not None:
    - 549            # Prepare path
    - 550            path = path.replace('/',ntpath.sep)
    - 551            if ntpath.sep in path:
    - 552                path = path.strip(ntpath.sep).split(ntpath.sep)
    - 553            else:
    - 554                path = [path]
    - 555
    - 556            # Create each dir in the path
    - 557            for depth in range(1, len(path)+1):
    - 558                tmp_path = ntpath.sep.join(path[:depth])
    - 559                try:
    - 560                    self.smbClient.createDirectory(
    - 561                        shareName=self.smb_share, 
    - 562                        pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + tmp_path + ntpath.sep)
    - 563                    )
    - 564                except impacket.smbconnection.SessionError as err:
    - 565                    if err.getErrorCode() == 0xc0000035:
    - 566                        # STATUS_OBJECT_NAME_COLLISION
    - 567                        # Remote directory already created, this is normal
    - 568                        # Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19
    - 569                        pass
    - 570                    else:
    - 571                        print("[!] Failed to create directory '%s': %s" % (tmp_path, err))
    - 572                        if self.config.debug:
    - 573                            traceback.print_exc()
    - 574        else:
    - 575            pass
    - 576
    - 577    def mount(self, local_mount_point, remote_path):
    - 578
    - 579        if not os.path.exists(local_mount_point):
    - 580            pass
    + 548                    self.available_shares[sharename.lower()] = {
    + 549                        "name": sharename, 
    + 550                        "type": STYPE_MASK(sharetype), 
    + 551                        "rawtype": sharetype, 
    + 552                        "comment": sharecomment
    + 553                    }
    + 554            else:
    + 555                print("[!] Error: SMBSession.smbClient is None.")
    + 556
    + 557        return self.available_shares
    + 558
    + 559    def mkdir(self, path=None):
    + 560        """
    + 561        Creates a directory at the specified path on the SMB share.
    + 562
    + 563        This method takes a path and attempts to create the directory structure on the SMB share. If the path includes
    + 564        nested directories, it will create each directory in the sequence. If a directory already exists, it will skip
    + 565        the creation for that directory without raising an error.
    + 566
    + 567        Args:
    + 568            path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
    + 569
    + 570        Note:
    + 571            The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
    + 572        """
    + 573
    + 574        if path is not None:
    + 575            # Prepare path
    + 576            path = path.replace('/',ntpath.sep)
    + 577            if ntpath.sep in path:
    + 578                path = path.strip(ntpath.sep).split(ntpath.sep)
    + 579            else:
    + 580                path = [path]
      581
    - 582        if sys.platform.startswith('win'):
    - 583            remote_path = remote_path.replace('/',ntpath.sep)
    - 584            command = f"net use {local_mount_point} \\\\{self.address}\\{self.smb_share}\\{remote_path}"
    - 585        
    - 586        elif sys.platform.startswith('linux'):
    - 587            remote_path = remote_path.replace(ntpath.sep,'/')
    - 588            command = f"mount -t cifs //{self.address}/{self.smb_share}/{remote_path} {local_mount_point} -o username={self.username},password={self.password}"
    - 589        
    - 590        elif sys.platform.startswith('darwin'):
    - 591            remote_path = remote_path.replace(ntpath.sep,'/')
    - 592            command = f"mount_smbfs //{self.username}:{self.password}@{self.address}/{self.smb_share}/{remote_path} {local_mount_point}"
    - 593        
    - 594        else:
    - 595            command = None
    - 596            print("[!] Unsupported platform for mounting SMB share.")
    - 597        
    - 598        if command is not None:
    - 599            if self.config.debug:
    - 600                print("[debug] Executing: %s" % command)
    - 601            os.system(command)
    + 582            # Create each dir in the path
    + 583            for depth in range(1, len(path)+1):
    + 584                tmp_path = ntpath.sep.join(path[:depth])
    + 585                try:
    + 586                    self.smbClient.createDirectory(
    + 587                        shareName=self.smb_share, 
    + 588                        pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + tmp_path + ntpath.sep)
    + 589                    )
    + 590                except impacket.smbconnection.SessionError as err:
    + 591                    if err.getErrorCode() == 0xc0000035:
    + 592                        # STATUS_OBJECT_NAME_COLLISION
    + 593                        # Remote directory already created, this is normal
    + 594                        # Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19
    + 595                        pass
    + 596                    else:
    + 597                        print("[!] Failed to create directory '%s': %s" % (tmp_path, err))
    + 598                        if self.config.debug:
    + 599                            traceback.print_exc()
    + 600        else:
    + 601            pass
      602
    - 603    def path_exists(self, path=None):
    + 603    def mount(self, local_mount_point, remote_path):
      604        """
    - 605        Checks if the specified path exists on the SMB share.
    + 605        Generates the command to mount an SMB share on different platforms.
      606
    - 607        This method determines if a given path exists on the SMB share by attempting to list the contents of the path.
    - 608        If the path listing is successful and returns one or more entries, the path is considered to exist.
    + 607        This method takes the local mount point and the remote path of the SMB share and generates the appropriate mount command based on the platform.
    + 608        It constructs the mount command using the provided parameters and executes it using the os.system() function.
      609
      610        Args:
    - 611            path (str, optional): The path to check on the SMB share. Defaults to None.
    - 612
    - 613        Returns:
    - 614            bool: True if the path exists, False otherwise or if an error occurs.
    - 615        """
    - 616
    - 617        if path is not None:
    - 618            path = path.replace('*','')
    - 619            try:
    - 620                contents = self.smbClient.listPath(
    - 621                    shareName=self.smb_share,
    - 622                    path=ntpath.normpath(self.smb_cwd + ntpath.sep + path + ntpath.sep)
    - 623                )
    - 624                return (len(contents) != 0)
    - 625            except Exception as e:
    - 626                return False
    - 627        else:
    - 628            return False
    - 629   
    - 630    def path_isdir(self, pathFromRoot=None):
    - 631        """
    - 632        Checks if the specified path is a directory on the SMB share.
    - 633
    - 634        This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the
    - 635        contents of the path and filtering for entries that match the basename of the path and are marked as directories.
    - 636
    - 637        Args:
    - 638            path (str, optional): The path to check on the SMB share. Defaults to None.
    - 639
    - 640        Returns:
    - 641            bool: True if the path is a directory, False otherwise or if an error occurs.
    - 642        """
    - 643
    - 644        if pathFromRoot is not None:
    - 645            # Replace slashes if any
    - 646            path = pathFromRoot.replace('/', ntpath.sep)
    - 647            
    - 648            # Strip wildcards to avoid injections
    - 649            path = path.replace('*','')
    - 650
    - 651            # Normalize path and strip leading backslash
    - 652            path = ntpath.normpath(path + ntpath.sep).lstrip(ntpath.sep)
    - 653
    - 654            if path.strip() in ['', '.', '..']:
    - 655                # By defininition they exist on the filesystem
    - 656                return True
    - 657            else:
    - 658                try:
    - 659                    contents = self.smbClient.listPath(
    - 660                        shareName=self.smb_share,
    - 661                        path=path+'*'
    - 662                    )
    - 663                    # Filter on directories
    - 664                    contents = [
    - 665                        c for c in contents
    - 666                        if c.get_longname() == ntpath.basename(path) and c.is_directory()
    - 667                    ]
    - 668                    return (len(contents) != 0)
    - 669                except Exception as e:
    - 670                    return False
    - 671        else:
    - 672            return False
    - 673
    - 674    def path_isfile(self, path=None):
    - 675        """
    - 676        Checks if the specified path is a file on the SMB share.
    - 677
    - 678        This method determines if a given path corresponds to a file on the SMB share. It does this by listing the
    - 679        contents of the path and filtering for entries that match the basename of the path and are not marked as directories.
    - 680
    - 681        Args:
    - 682            path (str, optional): The path to check on the SMB share. Defaults to None.
    - 683
    - 684        Returns:
    - 685            bool: True if the path is a file, False otherwise or if an error occurs.
    - 686        """
    - 687
    - 688        if path is not None:
    - 689            path = path.replace('*','')
    - 690            search_dir = ntpath.normpath(self.smb_cwd + ntpath.sep + path)
    - 691            search_dir = ntpath.dirname(search_dir) + ntpath.sep + '*'
    - 692            try:
    - 693                contents = self.smbClient.listPath(
    - 694                    shareName=self.smb_share,
    - 695                    path=search_dir
    - 696                )
    - 697                # Filter on files
    - 698                contents = [
    - 699                    c for c in contents
    - 700                    if c.get_longname() == ntpath.basename(path) and not c.is_directory()
    - 701                ]
    - 702                return (len(contents) != 0)
    - 703            except Exception as e:
    - 704                return False
    - 705        else:
    - 706            return False
    - 707
    - 708    def ping_smb_session(self):
    - 709        """
    - 710        Tests the connectivity to the SMB server by sending an echo command.
    - 711
    - 712        This method attempts to send an echo command to the SMB server to check if the session is still active.
    - 713        It updates the `connected` attribute of the class based on the success or failure of the echo command.
    - 714
    - 715        Returns:
    - 716            bool: True if the echo command succeeds (indicating the session is active), False otherwise.
    - 717        """
    + 611            local_mount_point (str): The local directory where the SMB share will be mounted.
    + 612            remote_path (str): The remote path on the SMB share to be mounted.
    + 613
    + 614        Note:
    + 615            - For Windows platform, the command uses 'net use' to mount the share.
    + 616            - For Linux platform, the command uses 'mount' to mount the share.
    + 617            - For macOS platform, the command uses 'mount_smbfs' to mount the share.
    + 618            - If the platform is not supported, an error message is displayed.
    + 619
    + 620        Returns:
    + 621            None
    + 622        """
    + 623
    + 624        if not os.path.exists(local_mount_point):
    + 625            pass
    + 626
    + 627        if sys.platform.startswith('win'):
    + 628            remote_path = remote_path.replace('/',ntpath.sep)
    + 629            command = f"net use {local_mount_point} \\\\{self.address}\\{self.smb_share}\\{remote_path}"
    + 630        
    + 631        elif sys.platform.startswith('linux'):
    + 632            remote_path = remote_path.replace(ntpath.sep,'/')
    + 633            command = f"mount -t cifs //{self.address}/{self.smb_share}/{remote_path} {local_mount_point} -o username={self.username},password={self.password}"
    + 634        
    + 635        elif sys.platform.startswith('darwin'):
    + 636            remote_path = remote_path.replace(ntpath.sep,'/')
    + 637            command = f"mount_smbfs //{self.username}:{self.password}@{self.address}/{self.smb_share}/{remote_path} {local_mount_point}"
    + 638        
    + 639        else:
    + 640            command = None
    + 641            print("[!] Unsupported platform for mounting SMB share.")
    + 642        
    + 643        if command is not None:
    + 644            if self.config.debug:
    + 645                print("[debug] Executing: %s" % command)
    + 646            os.system(command)
    + 647
    + 648    def path_exists(self, path=None):
    + 649        """
    + 650        Checks if the specified path exists on the SMB share.
    + 651
    + 652        This method determines if a given path exists on the SMB share by attempting to list the contents of the path.
    + 653        If the path listing is successful and returns one or more entries, the path is considered to exist.
    + 654
    + 655        Args:
    + 656            path (str, optional): The path to check on the SMB share. Defaults to None.
    + 657
    + 658        Returns:
    + 659            bool: True if the path exists, False otherwise or if an error occurs.
    + 660        """
    + 661
    + 662        if path is not None:
    + 663            path = path.replace('*','')
    + 664            try:
    + 665                contents = self.smbClient.listPath(
    + 666                    shareName=self.smb_share,
    + 667                    path=ntpath.normpath(self.smb_cwd + ntpath.sep + path + ntpath.sep)
    + 668                )
    + 669                return (len(contents) != 0)
    + 670            except Exception as e:
    + 671                return False
    + 672        else:
    + 673            return False
    + 674   
    + 675    def path_isdir(self, pathFromRoot=None):
    + 676        """
    + 677        Checks if the specified path is a directory on the SMB share.
    + 678
    + 679        This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the
    + 680        contents of the path and filtering for entries that match the basename of the path and are marked as directories.
    + 681
    + 682        Args:
    + 683            path (str, optional): The path to check on the SMB share. Defaults to None.
    + 684
    + 685        Returns:
    + 686            bool: True if the path is a directory, False otherwise or if an error occurs.
    + 687        """
    + 688
    + 689        if pathFromRoot is not None:
    + 690            # Replace slashes if any
    + 691            path = pathFromRoot.replace('/', ntpath.sep)
    + 692            
    + 693            # Strip wildcards to avoid injections
    + 694            path = path.replace('*','')
    + 695
    + 696            # Normalize path and strip leading backslash
    + 697            path = ntpath.normpath(path + ntpath.sep).lstrip(ntpath.sep)
    + 698
    + 699            if path.strip() in ['', '.', '..']:
    + 700                # By defininition they exist on the filesystem
    + 701                return True
    + 702            else:
    + 703                try:
    + 704                    contents = self.smbClient.listPath(
    + 705                        shareName=self.smb_share,
    + 706                        path=path+'*'
    + 707                    )
    + 708                    # Filter on directories
    + 709                    contents = [
    + 710                        c for c in contents
    + 711                        if c.get_longname() == ntpath.basename(path) and c.is_directory()
    + 712                    ]
    + 713                    return (len(contents) != 0)
    + 714                except Exception as e:
    + 715                    return False
    + 716        else:
    + 717            return False
      718
    - 719        try:
    - 720            self.smbClient.getSMBServer().echo()
    - 721        except Exception as e:
    - 722            self.connected = False
    - 723        return self.connected
    - 724
    - 725    def put_file(self, localpath=None):
    - 726        """
    - 727        Uploads a single file to the SMB share.
    + 719    def path_isfile(self, path=None):
    + 720        """
    + 721        Checks if the specified path is a file on the SMB share.
    + 722
    + 723        This method determines if a given path corresponds to a file on the SMB share. It does this by listing the
    + 724        contents of the path and filtering for entries that match the basename of the path and are not marked as directories.
    + 725
    + 726        Args:
    + 727            path (str, optional): The path to check on the SMB share. Defaults to None.
      728
    - 729        This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.
    - 730        It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.
    - 731        General exceptions are caught and logged, with a traceback provided if debugging is enabled.
    + 729        Returns:
    + 730            bool: True if the path is a file, False otherwise or if an error occurs.
    + 731        """
      732
    - 733        Args:
    - 734            localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
    - 735        """
    - 736
    - 737        if os.path.exists(localpath):
    - 738            if os.path.isfile(localpath):
    - 739                try:
    - 740                    localfile = os.path.basename(localpath)
    - 741                    f = LocalFileIO(
    - 742                        mode="rb", 
    - 743                        path=localpath, 
    - 744                        debug=self.config.debug
    - 745                    )
    - 746                    self.smbClient.putFile(
    - 747                        shareName=self.smb_share, 
    - 748                        pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + localfile + ntpath.sep), 
    - 749                        callback=f.read
    - 750                    )
    - 751                    f.close()
    - 752                except (BrokenPipeError, KeyboardInterrupt) as err:
    - 753                    print("[!] Interrupted.")
    - 754                    self.close_smb_session()
    - 755                    self.init_smb_session()
    - 756                except Exception as err:
    - 757                    print("[!] Failed to upload '%s': %s" % (localfile, err))
    - 758                    if self.config.debug:
    - 759                        traceback.print_exc()
    - 760            else:
    - 761                print("[!] The specified localpath is a directory. Use 'put -r <directory>' instead.")
    - 762        else:
    - 763            print("[!] The specified localpath does not exist.")
    - 764
    - 765    def put_file_recursively(self, localpath=None):
    - 766        """
    - 767        Recursively uploads files from a specified local directory to the SMB share.
    - 768
    - 769        This method walks through the given local directory and all its subdirectories, uploading each file to the
    - 770        corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,
    - 771        it iterates over all files and directories within the local path, creating necessary directories on the SMB share
    - 772        and uploading files. If the local path is not a directory, it prints an error message.
    + 733        if path is not None:
    + 734            path = path.replace('*','')
    + 735            search_dir = ntpath.normpath(self.smb_cwd + ntpath.sep + path)
    + 736            search_dir = ntpath.dirname(search_dir) + ntpath.sep + '*'
    + 737            try:
    + 738                contents = self.smbClient.listPath(
    + 739                    shareName=self.smb_share,
    + 740                    path=search_dir
    + 741                )
    + 742                # Filter on files
    + 743                contents = [
    + 744                    c for c in contents
    + 745                    if c.get_longname() == ntpath.basename(path) and not c.is_directory()
    + 746                ]
    + 747                return (len(contents) != 0)
    + 748            except Exception as e:
    + 749                return False
    + 750        else:
    + 751            return False
    + 752
    + 753    def ping_smb_session(self):
    + 754        """
    + 755        Tests the connectivity to the SMB server by sending an echo command.
    + 756
    + 757        This method attempts to send an echo command to the SMB server to check if the session is still active.
    + 758        It updates the `connected` attribute of the class based on the success or failure of the echo command.
    + 759
    + 760        Returns:
    + 761            bool: True if the echo command succeeds (indicating the session is active), False otherwise.
    + 762        """
    + 763
    + 764        try:
    + 765            self.smbClient.getSMBServer().echo()
    + 766        except Exception as e:
    + 767            self.connected = False
    + 768        return self.connected
    + 769
    + 770    def put_file(self, localpath=None):
    + 771        """
    + 772        Uploads a single file to the SMB share.
      773
    - 774        Args:
    - 775            localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
    - 776        """
    + 774        This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.
    + 775        It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.
    + 776        General exceptions are caught and logged, with a traceback provided if debugging is enabled.
      777
    - 778        if os.path.exists(localpath):
    - 779            if os.path.isfile(localpath):
    - 780                # Iterate over all files and directories within the local path
    - 781                local_files = {}
    - 782                for root, dirs, files in os.walk(localpath):
    - 783                    if len(files) != 0:
    - 784                        local_files[root] = files
    - 785
    - 786                # Iterate over the found files
    - 787                for local_dir_path in sorted(local_files.keys()):
    - 788                    print("[>] Putting files of '%s'" % local_dir_path)
    - 789
    - 790                    # Create remote directory
    - 791                    remote_dir_path = local_dir_path.replace(os.path.sep, ntpath.sep)
    - 792                    self.mkdir(
    - 793                        path=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep)
    - 794                    )
    - 795
    - 796                    for local_file_path in local_files[local_dir_path]:
    - 797                        try:
    - 798                            f = LocalFileIO(
    - 799                                mode="rb", 
    - 800                                path=local_dir_path + os.path.sep + local_file_path, 
    - 801                                debug=self.config.debug
    - 802                            )
    - 803                            self.smbClient.putFile(
    - 804                                shareName=self.smb_share, 
    - 805                                pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep + local_file_path), 
    - 806                                callback=f.read
    - 807                            )
    - 808                            f.close()
    - 809
    - 810                        except BrokenPipeError as err:
    - 811                            f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err))
    - 812                            f.close(remove=True)
    - 813                            break
    - 814                        except Exception as err:
    - 815                            f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err))
    - 816                            f.close(remove=True)
    - 817                else:
    - 818                    print("[!] The specified localpath is a file. Use 'put <file>' instead.")
    - 819        else:
    - 820            print("[!] The specified localpath does not exist.")
    - 821
    - 822    def rmdir(self, path=None):
    - 823        """
    - 824        Removes a directory from the SMB share at the specified path.
    - 825
    - 826        This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,
    - 827        it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
    - 828        the stack trace of the exception.
    - 829
    - 830        Args:
    - 831            path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
    - 832        """
    - 833        try:
    - 834            self.smbClient.deleteDirectory(
    - 835                shareName=self.smb_share, 
    - 836                pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + path), 
    - 837            )
    - 838        except Exception as err:
    - 839            print("[!] Failed to remove directory '%s': %s" % (path, err))
    - 840            if self.config.debug:
    - 841                traceback.print_exc()
    - 842
    - 843    def rm(self, path=None):
    - 844        """
    - 845        Removes a file from the SMB share at the specified path.
    - 846
    - 847        This method attempts to delete a file located at the given path on the SMB share. If the operation fails,
    - 848        it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
    - 849        the stack trace of the exception.
    - 850
    - 851        Args:
    - 852            path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
    - 853        """
    - 854        try:
    - 855            self.smbClient.deleteFile(
    - 856                shareName=self.smb_share, 
    - 857                pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + path), 
    - 858            )
    - 859        except Exception as err:
    - 860            print("[!] Failed to remove file '%s': %s" % (path, err))
    - 861            if self.config.debug:
    - 862                traceback.print_exc()
    - 863
    - 864    def tree(self, path=None):
    - 865        """
    - 866        Recursively lists the directory structure of the SMB share starting from the specified path.
    + 778        Args:
    + 779            localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
    + 780        """
    + 781
    + 782        # Parse path
    + 783        localpath = localpath.replace('/', os.path.sep)
    + 784        if os.path.sep in localpath:
    + 785            tmp_search_path = os.path.normpath(os.getcwd() + os.path.sep + os.path.dirname(localpath))
    + 786        else:
    + 787            tmp_search_path = os.path.normpath(os.getcwd() + os.path.sep)
    + 788        # Parse filename
    + 789        filename = os.path.basename(localpath)
    + 790
    + 791        # Search for the file
    + 792        matches = os.listdir(tmp_search_path)
    + 793        # Filter the entries
    + 794        matching_entries = []
    + 795        for entry in matches:
    + 796            if entry == filename:
    + 797                matching_entries.append(entry)
    + 798            elif '*' in filename:
    + 799                regexp = filename.replace('.', '\\.').replace('*', '.*')
    + 800                if re.match(regexp, entry):
    + 801                    matching_entries.append(entry)
    + 802
    + 803        matching_entries = sorted(list(set(matching_entries)))
    + 804
    + 805        # Loop and upload
    + 806        for localpath in matching_entries:
    + 807            if os.path.exists(localpath):
    + 808                if os.path.isfile(localpath):
    + 809                    try:
    + 810                        localfile = os.path.basename(localpath)
    + 811                        f = LocalFileIO(
    + 812                            mode="rb", 
    + 813                            path=localpath, 
    + 814                            debug=self.config.debug
    + 815                        )
    + 816                        self.smbClient.putFile(
    + 817                            shareName=self.smb_share, 
    + 818                            pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + localfile + ntpath.sep), 
    + 819                            callback=f.read
    + 820                        )
    + 821                        f.close()
    + 822                    except (BrokenPipeError, KeyboardInterrupt) as err:
    + 823                        print("[!] Interrupted.")
    + 824                        self.close_smb_session()
    + 825                        self.init_smb_session()
    + 826                    except Exception as err:
    + 827                        print("[!] Failed to upload '%s': %s" % (localfile, err))
    + 828                        if self.config.debug:
    + 829                            traceback.print_exc()
    + 830                else:
    + 831                    # [!] The specified localpath is a directory. Use 'put -r <directory>' instead.
    + 832                    pass
    + 833            else:
    + 834                # [!] The specified localpath does not exist.
    + 835                pass
    + 836
    + 837    def put_file_recursively(self, localpath=None):
    + 838        """
    + 839        Recursively uploads files from a specified local directory to the SMB share.
    + 840
    + 841        This method walks through the given local directory and all its subdirectories, uploading each file to the
    + 842        corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,
    + 843        it iterates over all files and directories within the local path, creating necessary directories on the SMB share
    + 844        and uploading files. If the local path is not a directory, it prints an error message.
    + 845
    + 846        Args:
    + 847            localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
    + 848        """
    + 849
    + 850        if os.path.exists(localpath):
    + 851            if os.path.isfile(localpath):
    + 852                # Iterate over all files and directories within the local path
    + 853                local_files = {}
    + 854                for root, dirs, files in os.walk(localpath):
    + 855                    if len(files) != 0:
    + 856                        local_files[root] = files
    + 857
    + 858                # Iterate over the found files
    + 859                for local_dir_path in sorted(local_files.keys()):
    + 860                    print("[>] Putting files of '%s'" % local_dir_path)
    + 861
    + 862                    # Create remote directory
    + 863                    remote_dir_path = local_dir_path.replace(os.path.sep, ntpath.sep)
    + 864                    self.mkdir(
    + 865                        path=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep)
    + 866                    )
      867
    - 868        This function prints a visual representation of the directory tree of the remote SMB share. It uses
    - 869        recursion to navigate through directories and lists all files and subdirectories in each directory.
    - 870        The output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
    - 871
    - 872        Args:
    - 873            path (str, optional): The starting path on the SMB share from which to begin listing the tree.
    - 874                                  Defaults to the root of the current share.
    - 875        """
    - 876        
    - 877        def recurse_action(base_dir="", path=[], prompt=[]):
    - 878            bars = ["│   ", "├── ", "└── "]
    - 879
    - 880            remote_smb_path = ntpath.normpath(base_dir + ntpath.sep + ntpath.sep.join(path))
    + 868                    for local_file_path in local_files[local_dir_path]:
    + 869                        try:
    + 870                            f = LocalFileIO(
    + 871                                mode="rb", 
    + 872                                path=local_dir_path + os.path.sep + local_file_path, 
    + 873                                debug=self.config.debug
    + 874                            )
    + 875                            self.smbClient.putFile(
    + 876                                shareName=self.smb_share, 
    + 877                                pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep + local_file_path), 
    + 878                                callback=f.read
    + 879                            )
    + 880                            f.close()
      881
    - 882            entries = []
    - 883            try:
    - 884                entries = self.smbClient.listPath(
    - 885                    shareName=self.smb_share, 
    - 886                    path=remote_smb_path+'\\*'
    - 887                )
    - 888            except impacket.smbconnection.SessionError as err:
    - 889                code, const, text = err.getErrorCode(), err.getErrorString()[0], err.getErrorString()[1]
    - 890                errmsg = "Error 0x%08x (%s): %s" % (code, const, text)
    - 891                if self.config.no_colors:
    - 892                    print("%s%s" % (''.join(prompt+[bars[2]]), errmsg))
    - 893                else:
    - 894                    print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), errmsg))
    - 895                return 
    - 896
    - 897            entries = [e for e in entries if e.get_longname() not in [".", ".."]]
    - 898            entries = sorted(entries, key=lambda x:x.get_longname())
    - 899
    - 900            # 
    - 901            if len(entries) > 1:
    - 902                index = 0
    - 903                for entry in entries:
    - 904                    index += 1
    - 905                    # This is the first entry 
    - 906                    if index == 0:
    - 907                        if entry.is_directory():
    - 908                            if self.config.no_colors:
    - 909                                print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    - 910                            else:
    - 911                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    - 912                            recurse_action(
    - 913                                base_dir=base_dir, 
    - 914                                path=path+[entry.get_longname()],
    - 915                                prompt=prompt+["│   "]
    - 916                            )
    - 917                        else:
    - 918                            if self.config.no_colors:
    - 919                                print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    - 920                            else:
    - 921                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    + 882                        except BrokenPipeError as err:
    + 883                            f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err))
    + 884                            f.close(remove=True)
    + 885                            break
    + 886                        except Exception as err:
    + 887                            f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err))
    + 888                            f.close(remove=True)
    + 889                else:
    + 890                    print("[!] The specified localpath is a file. Use 'put <file>' instead.")
    + 891        else:
    + 892            print("[!] The specified localpath does not exist.")
    + 893
    + 894    def rmdir(self, path=None):
    + 895        """
    + 896        Removes a directory from the SMB share at the specified path.
    + 897
    + 898        This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,
    + 899        it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
    + 900        the stack trace of the exception.
    + 901
    + 902        Args:
    + 903            path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
    + 904        """
    + 905        try:
    + 906            self.smbClient.deleteDirectory(
    + 907                shareName=self.smb_share, 
    + 908                pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + path), 
    + 909            )
    + 910        except Exception as err:
    + 911            print("[!] Failed to remove directory '%s': %s" % (path, err))
    + 912            if self.config.debug:
    + 913                traceback.print_exc()
    + 914
    + 915    def rm(self, path=None):
    + 916        """
    + 917        Removes a file from the SMB share at the specified path.
    + 918
    + 919        This method attempts to delete a file located at the given path on the SMB share. If the operation fails,
    + 920        it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
    + 921        the stack trace of the exception.
      922
    - 923                    # This is the last entry
    - 924                    elif index == len(entries):
    - 925                        if entry.is_directory():
    - 926                            if self.config.no_colors:
    - 927                                print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    - 928                            else:
    - 929                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    - 930                            recurse_action(
    - 931                                base_dir=base_dir, 
    - 932                                path=path+[entry.get_longname()],
    - 933                                prompt=prompt+["    "]
    - 934                            )
    - 935                        else:
    - 936                            if self.config.no_colors:
    - 937                                print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    - 938                            else:
    - 939                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    - 940                        
    - 941                    # These are entries in the middle
    - 942                    else:
    - 943                        if entry.is_directory():
    - 944                            if self.config.no_colors:
    - 945                                print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    - 946                            else:
    - 947                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    - 948                            recurse_action(
    - 949                                base_dir=base_dir, 
    - 950                                path=path+[entry.get_longname()],
    - 951                                prompt=prompt+["│   "]
    - 952                            )
    - 953                        else:
    - 954                            if self.config.no_colors:
    - 955                                print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    - 956                            else:
    - 957                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    - 958
    - 959            # 
    - 960            elif len(entries) == 1:
    - 961                entry = entries[0]
    - 962                if entry.is_directory():
    - 963                    if self.config.no_colors:
    - 964                        print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    - 965                    else:
    - 966                        print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    - 967                    recurse_action(
    - 968                        base_dir=base_dir, 
    - 969                        path=path+[entry.get_longname()],
    - 970                        prompt=prompt+["    "]
    - 971                    )
    - 972                else:
    - 973                    if self.config.no_colors:
    - 974                        print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    - 975                    else:
    - 976                        print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    - 977
    - 978        # Entrypoint
    - 979        try:
    - 980            if self.config.no_colors:
    - 981                print("%s\\" % path)
    - 982            else:
    - 983                print("\x1b[1;96m%s\x1b[0m\\" % path)
    - 984            recurse_action(
    - 985                base_dir=self.smb_cwd, 
    - 986                path=[path],
    - 987                prompt=[""]
    - 988            )
    - 989        except (BrokenPipeError, KeyboardInterrupt) as e:
    - 990            print("[!] Interrupted.")
    - 991            self.close_smb_session()
    - 992            self.init_smb_session()
    - 993
    - 994    def umount(self, local_mount_point):
    - 995        if os.path.exists(local_mount_point):
    - 996            if sys.platform.startswith('win'):
    - 997                command = f"net use {local_mount_point} /delete"
    - 998
    - 999            elif sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
    -1000                command = f"umount {local_mount_point}"
    -1001
    -1002            else:
    -1003                command = None
    -1004                print("[!] Unsupported platform for unmounting SMB share.")
    -1005        
    -1006            if command is not None:
    -1007                if self.config.debug:
    -1008                    print("[debug] Executing: %s" % command)
    -1009                os.system(command)
    -1010        else:
    -1011            print("[!] Cannot unmount a non existing path.")        
    -1012
    -1013    # Setter / Getter
    -1014
    -1015    def set_share(self, shareName):
    -1016        """
    -1017        Sets the current SMB share to the specified share name.
    -1018
    -1019        This method updates the SMB session to use the specified share name. It checks if the share name is valid
    -1020        and updates the smb_share attribute of the SMBSession instance.
    -1021
    -1022        Parameters:
    -1023            shareName (str): The name of the share to set as the current SMB share.
    -1024
    -1025        Raises:
    -1026            ValueError: If the shareName is None or an empty string.
    -1027        """
    -1028
    -1029        if shareName is not None:
    -1030            self.list_shares()
    -1031            if shareName.lower() in self.available_shares.keys():
    -1032                # Doing this in order to keep the case of the share adevertised by the remote machine
    -1033                self.smb_share = self.available_shares[shareName.lower()]["name"]
    -1034                # Connects the tree
    -1035                self.smb_tree_id = self.smbClient.connectTree(self.smb_share)
    -1036            else:
    -1037                print("[!] Could not set share '%s', it does not exist remotely." % shareName)
    -1038
    -1039    def set_cwd(self, path=None):
    -1040        """
    -1041        Sets the current working directory on the SMB share to the specified path.
    -1042
    -1043        This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.
    -1044        If the specified path is not a directory, the cwd remains unchanged.
    -1045
    -1046        Parameters:
    -1047            path (str): The path to set as the current working directory.
    -1048
    -1049        Raises:
    -1050            ValueError: If the specified path is not a directory.
    -1051        """
    -1052
    -1053        if path is not None:
    -1054            # Set path separators to ntpath sep 
    -1055            if '/' in path:
    -1056                path = path.replace('/', ntpath.sep)
    -1057
    -1058            if path.startswith(ntpath.sep):
    -1059                # Absolute path
    -1060                path = path + ntpath.sep
    -1061            else:
    -1062                # Relative path to the CWD
    -1063                if len(self.smb_cwd) == 0:
    -1064                    path = path + ntpath.sep
    -1065                else:
    -1066                    path = self.smb_cwd + ntpath.sep + path
    -1067            
    -1068            # Path normalization
    -1069            path = ntpath.normpath(path)
    -1070            path = re.sub(r'\\+', r'\\', path)
    -1071
    -1072            if path in ["", ".", ".."]:
    -1073                self.smb_cwd = ""
    -1074            else:
    -1075                if self.path_isdir(pathFromRoot=path.strip(ntpath.sep)):
    -1076                    # Path exists on the remote 
    -1077                    self.smb_cwd = ntpath.normpath(path)
    -1078                else:
    -1079                    # Path does not exists or is not a directory on the remote 
    -1080                    print("[!] Remote directory '%s' does not exist." % path)
    + 923        Args:
    + 924            path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
    + 925        """
    + 926
    + 927        # Parse path
    + 928        path = path.replace('/', ntpath.sep)
    + 929        if ntpath.sep in path:
    + 930            tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep + ntpath.dirname(path))
    + 931        else:
    + 932            tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep)
    + 933        # Parse filename
    + 934        filename = ntpath.basename(path)
    + 935
    + 936        # Search for the file
    + 937        matches = self.smbClient.listPath(
    + 938            shareName=self.smb_share, 
    + 939            path=tmp_search_path + ntpath.sep + '*'
    + 940        )   
    + 941
    + 942        # Filter the entries
    + 943        matching_entries = []
    + 944        for entry in matches:
    + 945            if entry.is_directory():
    + 946                # Skip directories
    + 947                continue
    + 948            if entry.get_longname() == filename:
    + 949                matching_entries.append(entry)
    + 950            elif '*' in filename:
    + 951                regexp = filename.replace('.', '\\.').replace('*', '.*')
    + 952                if re.match(regexp, entry.get_longname()):
    + 953                    matching_entries.append(entry)
    + 954        
    + 955        matching_entries = sorted(list(set(matching_entries)), key=lambda x: x.get_longname())
    + 956
    + 957        for entry in matching_entries:
    + 958            try:
    + 959                self.smbClient.deleteFile(
    + 960                    shareName=self.smb_share, 
    + 961                    pathName=ntpath.normpath(tmp_search_path + ntpath.sep + entry.get_longname()), 
    + 962                )
    + 963            except Exception as err:
    + 964                print("[!] Failed to remove file '%s': %s" % (path, err))
    + 965                if self.config.debug:
    + 966                    traceback.print_exc()
    + 967
    + 968    def tree(self, path=None):
    + 969        """
    + 970        Recursively lists the directory structure of the SMB share starting from the specified path.
    + 971
    + 972        This function prints a visual representation of the directory tree of the remote SMB share. It uses
    + 973        recursion to navigate through directories and lists all files and subdirectories in each directory.
    + 974        The output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
    + 975
    + 976        Args:
    + 977            path (str, optional): The starting path on the SMB share from which to begin listing the tree.
    + 978                                  Defaults to the root of the current share.
    + 979        """
    + 980        
    + 981        def recurse_action(base_dir="", path=[], prompt=[]):
    + 982            bars = ["│   ", "├── ", "└── "]
    + 983
    + 984            remote_smb_path = ntpath.normpath(base_dir + ntpath.sep + ntpath.sep.join(path))
    + 985
    + 986            entries = []
    + 987            try:
    + 988                entries = self.smbClient.listPath(
    + 989                    shareName=self.smb_share, 
    + 990                    path=remote_smb_path+'\\*'
    + 991                )
    + 992            except impacket.smbconnection.SessionError as err:
    + 993                code, const, text = err.getErrorCode(), err.getErrorString()[0], err.getErrorString()[1]
    + 994                errmsg = "Error 0x%08x (%s): %s" % (code, const, text)
    + 995                if self.config.no_colors:
    + 996                    print("%s%s" % (''.join(prompt+[bars[2]]), errmsg))
    + 997                else:
    + 998                    print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), errmsg))
    + 999                return 
    +1000
    +1001            entries = [e for e in entries if e.get_longname() not in [".", ".."]]
    +1002            entries = sorted(entries, key=lambda x:x.get_longname())
    +1003
    +1004            # 
    +1005            if len(entries) > 1:
    +1006                index = 0
    +1007                for entry in entries:
    +1008                    index += 1
    +1009                    # This is the first entry 
    +1010                    if index == 0:
    +1011                        if entry.is_directory():
    +1012                            if self.config.no_colors:
    +1013                                print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1014                            else:
    +1015                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1016                            recurse_action(
    +1017                                base_dir=base_dir, 
    +1018                                path=path+[entry.get_longname()],
    +1019                                prompt=prompt+["│   "]
    +1020                            )
    +1021                        else:
    +1022                            if self.config.no_colors:
    +1023                                print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1024                            else:
    +1025                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1026
    +1027                    # This is the last entry
    +1028                    elif index == len(entries):
    +1029                        if entry.is_directory():
    +1030                            if self.config.no_colors:
    +1031                                print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1032                            else:
    +1033                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1034                            recurse_action(
    +1035                                base_dir=base_dir, 
    +1036                                path=path+[entry.get_longname()],
    +1037                                prompt=prompt+["    "]
    +1038                            )
    +1039                        else:
    +1040                            if self.config.no_colors:
    +1041                                print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1042                            else:
    +1043                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1044                        
    +1045                    # These are entries in the middle
    +1046                    else:
    +1047                        if entry.is_directory():
    +1048                            if self.config.no_colors:
    +1049                                print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1050                            else:
    +1051                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1052                            recurse_action(
    +1053                                base_dir=base_dir, 
    +1054                                path=path+[entry.get_longname()],
    +1055                                prompt=prompt+["│   "]
    +1056                            )
    +1057                        else:
    +1058                            if self.config.no_colors:
    +1059                                print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1060                            else:
    +1061                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1062
    +1063            # 
    +1064            elif len(entries) == 1:
    +1065                entry = entries[0]
    +1066                if entry.is_directory():
    +1067                    if self.config.no_colors:
    +1068                        print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1069                    else:
    +1070                        print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1071                    recurse_action(
    +1072                        base_dir=base_dir, 
    +1073                        path=path+[entry.get_longname()],
    +1074                        prompt=prompt+["    "]
    +1075                    )
    +1076                else:
    +1077                    if self.config.no_colors:
    +1078                        print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1079                    else:
    +1080                        print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1081
    +1082        # Entrypoint
    +1083        try:
    +1084            if self.config.no_colors:
    +1085                print("%s\\" % path)
    +1086            else:
    +1087                print("\x1b[1;96m%s\x1b[0m\\" % path)
    +1088            recurse_action(
    +1089                base_dir=self.smb_cwd, 
    +1090                path=[path],
    +1091                prompt=[""]
    +1092            )
    +1093        except (BrokenPipeError, KeyboardInterrupt) as e:
    +1094            print("[!] Interrupted.")
    +1095            self.close_smb_session()
    +1096            self.init_smb_session()
    +1097
    +1098    def umount(self, local_mount_point):
    +1099        """
    +1100        Unmounts the specified local mount point of the remote share.
    +1101
    +1102        This method unmounts the specified local mount point of the remote share based on the platform.
    +1103        It supports Windows, Linux, and macOS platforms for unmounting.
    +1104
    +1105        Parameters:
    +1106            local_mount_point (str): The local mount point to unmount.
    +1107
    +1108        Raises:
    +1109            None
    +1110        """
    +1111
    +1112        if os.path.exists(local_mount_point):
    +1113            if sys.platform.startswith('win'):
    +1114                command = f"net use {local_mount_point} /delete"
    +1115
    +1116            elif sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
    +1117                command = f"umount {local_mount_point}"
    +1118
    +1119            else:
    +1120                command = None
    +1121                print("[!] Unsupported platform for unmounting SMB share.")
    +1122        
    +1123            if command is not None:
    +1124                if self.config.debug:
    +1125                    print("[debug] Executing: %s" % command)
    +1126                os.system(command)
    +1127        else:
    +1128            print("[!] Cannot unmount a non existing path.")        
    +1129
    +1130    # Other functions
    +1131
    +1132    def test_rights(self, sharename): 
    +1133        """
    +1134        Tests the read and write access rights of the current SMB session.
    +1135
    +1136        This method checks the read and write access rights of the current SMB session by attempting to list paths and create/delete temporary directories.
    +1137        
    +1138        Returns:
    +1139            dict: A dictionary containing the read and write access rights status.
    +1140                - "readable" (bool): Indicates if the session has read access rights.
    +1141                - "writable" (bool): Indicates if the session has write access rights.
    +1142        """
    +1143
    +1144        # Restore the current share
    +1145        current_share = self.smb_share
    +1146        self.set_share(shareName=sharename)
    +1147
    +1148        access_rights = {"readable": False, "writable": False}
    +1149        try:
    +1150            self.smbClient.listPath(self.smb_share, '*', password=None)
    +1151            access_rights["readable"] = True
    +1152        except impacket.smbconnection.SessionError as e:
    +1153            access_rights["readable"] = False
    +1154
    +1155        try:
    +1156            temp_dir = ntpath.normpath("\\" + ''.join([random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ0123456759") for k in range(16)]))
    +1157            self.smbClient.createDirectory(self.smb_share, temp_dir)
    +1158            self.smbClient.deleteDirectory(self.smb_share, temp_dir)
    +1159            access_rights["writable"] = True
    +1160        except impacket.smbconnection.SessionError as e:
    +1161            access_rights["writable"] = False
    +1162
    +1163        # Restore the current share
    +1164        self.set_share(shareName=current_share)
    +1165
    +1166        return access_rights
    +1167
    +1168    # Setter / Getter
    +1169
    +1170    def set_share(self, shareName):
    +1171        """
    +1172        Sets the current SMB share to the specified share name.
    +1173
    +1174        This method updates the SMB session to use the specified share name. It checks if the share name is valid
    +1175        and updates the smb_share attribute of the SMBSession instance.
    +1176
    +1177        Parameters:
    +1178            shareName (str): The name of the share to set as the current SMB share.
    +1179
    +1180        Raises:
    +1181            ValueError: If the shareName is None or an empty string.
    +1182        """
    +1183
    +1184        if shareName is not None:
    +1185            self.list_shares()
    +1186            if shareName.lower() in self.available_shares.keys():
    +1187                # Doing this in order to keep the case of the share adevertised by the remote machine
    +1188                self.smb_share = self.available_shares[shareName.lower()]["name"]
    +1189                self.smb_cwd = ""
    +1190                # Connects the tree
    +1191                self.smb_tree_id = self.smbClient.connectTree(self.smb_share)
    +1192            else:
    +1193                print("[!] Could not set share '%s', it does not exist remotely." % shareName)
    +1194        else:
    +1195            self.smb_share = None
    +1196            
    +1197    def set_cwd(self, path=None):
    +1198        """
    +1199        Sets the current working directory on the SMB share to the specified path.
    +1200
    +1201        This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.
    +1202        If the specified path is not a directory, the cwd remains unchanged.
    +1203
    +1204        Parameters:
    +1205            path (str): The path to set as the current working directory.
    +1206
    +1207        Raises:
    +1208            ValueError: If the specified path is not a directory.
    +1209        """
    +1210
    +1211        if path is not None:
    +1212            # Set path separators to ntpath sep 
    +1213            if '/' in path:
    +1214                path = path.replace('/', ntpath.sep)
    +1215
    +1216            if path.startswith(ntpath.sep):
    +1217                # Absolute path
    +1218                path = path + ntpath.sep
    +1219            else:
    +1220                # Relative path to the CWD
    +1221                if len(self.smb_cwd) == 0:
    +1222                    path = path + ntpath.sep
    +1223                else:
    +1224                    path = self.smb_cwd + ntpath.sep + path
    +1225            
    +1226            # Path normalization
    +1227            path = ntpath.normpath(path)
    +1228            path = re.sub(r'\\+', r'\\', path)
    +1229
    +1230            if path in ["", ".", ".."]:
    +1231                self.smb_cwd = ""
    +1232            else:
    +1233                if self.path_isdir(pathFromRoot=path.strip(ntpath.sep)):
    +1234                    # Path exists on the remote 
    +1235                    self.smb_cwd = ntpath.normpath(path)
    +1236                else:
    +1237                    # Path does not exists or is not a directory on the remote 
    +1238                    print("[!] Remote directory '%s' does not exist." % path)
     
    @@ -2371,32 +2689,32 @@

    -
    47    def __init__(self, address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, config=None):
    -48        super(SMBSession, self).__init__()
    -49        # Objects
    -50        self.config = config
    -51
    -52        # Target server
    -53        self.address = address
    -54
    -55        # Credentials
    -56        self.domain = domain
    -57        self.username = username
    -58        self.password = password 
    -59        self.lmhash = lmhash
    -60        self.nthash = nthash
    -61        self.use_kerberos = use_kerberos
    -62        self.kdcHost = kdcHost
    -63
    -64        self.smbClient = None
    -65        self.connected = False
    -66
    -67        self.available_shares = {}
    -68        self.smb_share = None
    -69        self.smb_cwd = ""
    -70        self.smb_tree_id = None
    -71
    -72        self.list_shares()
    +            
    48    def __init__(self, address, domain, username, password, lmhash, nthash, use_kerberos=False, kdcHost=None, config=None):
    +49        super(SMBSession, self).__init__()
    +50        # Objects
    +51        self.config = config
    +52
    +53        # Target server
    +54        self.address = address
    +55
    +56        # Credentials
    +57        self.domain = domain
    +58        self.username = username
    +59        self.password = password 
    +60        self.lmhash = lmhash
    +61        self.nthash = nthash
    +62        self.use_kerberos = use_kerberos
    +63        self.kdcHost = kdcHost
    +64
    +65        self.smbClient = None
    +66        self.connected = False
    +67
    +68        self.available_shares = {}
    +69        self.smb_share = None
    +70        self.smb_cwd = ""
    +71        self.smb_tree_id = None
    +72
    +73        self.list_shares()
     
    @@ -2579,76 +2897,76 @@

    -
     76    def init_smb_session(self):
    - 77        """
    - 78        Initializes and establishes a session with the SMB server.
    - 79
    - 80        This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.
    - 81        It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization.
    - 82
    - 83        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.
    - 84
    - 85        Returns:
    - 86            bool: True if the connection and authentication are successful, False otherwise.
    - 87        """
    - 88
    - 89        self.connected = False
    - 90
    - 91        if self.config.debug:
    - 92            print("[debug] [>] Connecting to remote SMB server '%s' ... " % self.address)
    - 93        try:
    - 94            self.smbClient = impacket.smbconnection.SMBConnection(
    - 95                remoteName=self.address,
    - 96                remoteHost=self.address,
    - 97                sess_port=int(445)
    - 98            )
    - 99        except OSError as err:
    -100            print("[!] %s" % err)
    -101            self.smbClient = None
    -102
    -103        if self.smbClient is not None:
    -104            if self.use_kerberos:
    -105                if self.config.debug:
    -106                    print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... " % (self.domain, self.username))
    -107                try:
    -108                    self.connected = self.smbClient.kerberosLogin(
    -109                        user=self.username,
    -110                        password=self.password,
    -111                        domain=self.domain,
    -112                        lmhash=self.lmhash,
    -113                        nthash=self.nthash,
    -114                        aesKey=self.aesKey,
    -115                        kdcHost=self.kdcHost
    -116                    )
    -117                except impacket.smbconnection.SessionError as err:
    -118                    if self.config.debug:
    -119                        traceback.print_exc()
    -120                    print("[!] Could not login: %s" % err)
    -121                    self.connected = False
    -122
    -123            else:
    -124                if self.config.debug:
    -125                    print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... " % (self.domain, self.username))
    -126                try:
    -127                    self.connected = self.smbClient.login(
    -128                        user=self.username,
    -129                        password=self.password,
    -130                        domain=self.domain,
    -131                        lmhash=self.lmhash,
    -132                        nthash=self.nthash
    -133                    )
    -134                except impacket.smbconnection.SessionError as err:
    -135                    if self.config.debug:
    -136                        traceback.print_exc()
    -137                    print("[!] Could not login: %s" % err)
    -138                    self.connected = False
    -139
    -140            if self.connected:
    -141                print("[+] Successfully authenticated to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username))
    -142            else:
    -143                print("[!] Failed to authenticate to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username))
    -144
    -145        return self.connected
    +            
     77    def init_smb_session(self):
    + 78        """
    + 79        Initializes and establishes a session with the SMB server.
    + 80
    + 81        This method sets up the SMB connection using either Kerberos or NTLM authentication based on the configuration.
    + 82        It attempts to connect to the SMB server specified by the `address` attribute and authenticate using the credentials provided during the object's initialization.
    + 83
    + 84        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.
    + 85
    + 86        Returns:
    + 87            bool: True if the connection and authentication are successful, False otherwise.
    + 88        """
    + 89
    + 90        self.connected = False
    + 91
    + 92        if self.config.debug:
    + 93            print("[debug] [>] Connecting to remote SMB server '%s' ... " % self.address)
    + 94        try:
    + 95            self.smbClient = impacket.smbconnection.SMBConnection(
    + 96                remoteName=self.address,
    + 97                remoteHost=self.address,
    + 98                sess_port=int(445)
    + 99            )
    +100        except OSError as err:
    +101            print("[!] %s" % err)
    +102            self.smbClient = None
    +103
    +104        if self.smbClient is not None:
    +105            if self.use_kerberos:
    +106                if self.config.debug:
    +107                    print("[debug] [>] Authenticating as '%s\\%s' with kerberos ... " % (self.domain, self.username))
    +108                try:
    +109                    self.connected = self.smbClient.kerberosLogin(
    +110                        user=self.username,
    +111                        password=self.password,
    +112                        domain=self.domain,
    +113                        lmhash=self.lmhash,
    +114                        nthash=self.nthash,
    +115                        aesKey=self.aesKey,
    +116                        kdcHost=self.kdcHost
    +117                    )
    +118                except impacket.smbconnection.SessionError as err:
    +119                    if self.config.debug:
    +120                        traceback.print_exc()
    +121                    print("[!] Could not login: %s" % err)
    +122                    self.connected = False
    +123
    +124            else:
    +125                if self.config.debug:
    +126                    print("[debug] [>] Authenticating as '%s\\%s' with NTLM ... " % (self.domain, self.username))
    +127                try:
    +128                    self.connected = self.smbClient.login(
    +129                        user=self.username,
    +130                        password=self.password,
    +131                        domain=self.domain,
    +132                        lmhash=self.lmhash,
    +133                        nthash=self.nthash
    +134                    )
    +135                except impacket.smbconnection.SessionError as err:
    +136                    if self.config.debug:
    +137                        traceback.print_exc()
    +138                    print("[!] Could not login: %s" % err)
    +139                    self.connected = False
    +140
    +141            if self.connected:
    +142                print("[+] Successfully authenticated to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username))
    +143            else:
    +144                print("[!] Failed to authenticate to '%s' as '%s\\%s'!" % (self.address, self.domain, self.username))
    +145
    +146        return self.connected
     
    @@ -2676,28 +2994,28 @@

    -
    147    def close_smb_session(self):
    -148        """
    -149        Closes the current SMB session by disconnecting the SMB client.
    -150
    -151        This method ensures that the SMB client connection is properly closed. It checks if the client is connected
    -152        and if so, it closes the connection and resets the connection status.
    -153
    -154        Raises:
    -155            Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
    -156        """
    -157
    -158        if self.smbClient is not None:
    -159            if self.connected:
    -160                self.smbClient.close()
    -161                self.connected = False
    -162                if self.config.debug:
    -163                    print("[+] SMB connection closed successfully.")
    -164            else:
    -165                if self.config.debug:
    -166                    print("[!] No active SMB connection to close.")
    -167        else:
    -168            raise Exception("SMB client is not initialized.")
    +            
    148    def close_smb_session(self):
    +149        """
    +150        Closes the current SMB session by disconnecting the SMB client.
    +151
    +152        This method ensures that the SMB client connection is properly closed. It checks if the client is connected
    +153        and if so, it closes the connection and resets the connection status.
    +154
    +155        Raises:
    +156            Exception: If the SMB client is not initialized or if there's an error during the disconnection process.
    +157        """
    +158
    +159        if self.smbClient is not None:
    +160            if self.connected:
    +161                self.smbClient.close()
    +162                self.connected = False
    +163                if self.config.debug:
    +164                    print("[+] SMB connection closed successfully.")
    +165            else:
    +166                if self.config.debug:
    +167                    print("[!] No active SMB connection to close.")
    +168        else:
    +169            raise Exception("SMB client is not initialized.")
     
    @@ -2723,26 +3041,26 @@

    -
    172    def read_file(self, path=None):
    -173        if self.path_isfile(path=path):
    -174            tmp_file_path = self.smb_cwd + ntpath.sep + path
    -175            matches = self.smbClient.listPath(
    -176                shareName=self.smb_share, 
    -177                path=tmp_file_path
    -178            )
    -179
    -180            fh = io.BytesIO()
    -181            try:
    -182                # opening the files in streams instead of mounting shares allows 
    -183                # for running the script from unprivileged containers
    -184                self.smbClient.getFile(self.smb_share, tmp_file_path, fh.write)
    -185            except impacket.smbconnection.SessionError as e:
    -186                return None
    -187            rawdata = fh.getvalue()
    -188            fh.close()
    -189            return rawdata
    -190        else:
    -191            print("[!] Remote path '%s' is not a file." % path)
    +            
    173    def read_file(self, path=None):
    +174        if self.path_isfile(path=path):
    +175            tmp_file_path = self.smb_cwd + ntpath.sep + path
    +176            matches = self.smbClient.listPath(
    +177                shareName=self.smb_share, 
    +178                path=tmp_file_path
    +179            )
    +180
    +181            fh = io.BytesIO()
    +182            try:
    +183                # opening the files in streams instead of mounting shares allows 
    +184                # for running the script from unprivileged containers
    +185                self.smbClient.getFile(self.smb_share, tmp_file_path, fh.write)
    +186            except impacket.smbconnection.SessionError as e:
    +187                return None
    +188            rawdata = fh.getvalue()
    +189            fh.close()
    +190            return rawdata
    +191        else:
    +192            print("[!] Remote path '%s' is not a file." % path)
     
    @@ -2760,53 +3078,53 @@

    -
    193    def find(self, paths=[], callback=None):
    -194        def recurse_action(paths=[], depth=0, callback=None):
    -195            if callback is None:
    -196                return []
    -197            
    -198            next_directories_to_explore = []
    -199
    -200            for path in paths:
    -201                remote_smb_path = ntpath.normpath(self.smb_cwd + ntpath.sep + path)
    -202                entries = []
    -203                
    -204                try:
    -205                    entries = self.smbClient.listPath(
    -206                        shareName=self.smb_share, 
    -207                        path=(remote_smb_path + ntpath.sep + '*')
    -208                    )
    -209                except impacket.smbconnection.SessionError as err:
    -210                    continue 
    -211                # Remove dot names
    -212                entries = [e for e in entries if e.get_longname() not in [".", ".."]]
    -213                # Sort the entries ignoring case
    -214                entries = sorted(entries, key=lambda x:x.get_longname().lower())
    -215                
    -216                for entry in entries:
    -217                    if entry.is_directory():
    -218                        callback(entry, path + ntpath.sep + entry.get_longname() + ntpath.sep, depth)
    -219                    else:
    -220                        callback(entry, path + ntpath.sep + entry.get_longname(), depth)
    -221
    -222                # Next directories to explore
    -223                for entry in entries:
    -224                    if entry.is_directory():
    -225                        next_directories_to_explore.append(path + ntpath.sep + entry.get_longname() + ntpath.sep)
    -226            
    -227            return next_directories_to_explore
    -228        # 
    -229        if callback is not None:
    -230            depth = 0
    -231            while len(paths) != 0:
    -232                paths = recurse_action(
    -233                    paths=paths,
    -234                    depth=depth,
    -235                    callback=callback
    -236                )
    -237                depth = depth + 1
    -238        else:
    -239            print("[!] SMBSession.find(), callback function cannot be None.")
    +            
    194    def find(self, paths=[], callback=None):
    +195        def recurse_action(paths=[], depth=0, callback=None):
    +196            if callback is None:
    +197                return []
    +198            
    +199            next_directories_to_explore = []
    +200
    +201            for path in paths:
    +202                remote_smb_path = ntpath.normpath(self.smb_cwd + ntpath.sep + path)
    +203                entries = []
    +204                
    +205                try:
    +206                    entries = self.smbClient.listPath(
    +207                        shareName=self.smb_share, 
    +208                        path=(remote_smb_path + ntpath.sep + '*')
    +209                    )
    +210                except impacket.smbconnection.SessionError as err:
    +211                    continue 
    +212                # Remove dot names
    +213                entries = [e for e in entries if e.get_longname() not in [".", ".."]]
    +214                # Sort the entries ignoring case
    +215                entries = sorted(entries, key=lambda x:x.get_longname().lower())
    +216                
    +217                for entry in entries:
    +218                    if entry.is_directory():
    +219                        callback(entry, path + ntpath.sep + entry.get_longname() + ntpath.sep, depth)
    +220                    else:
    +221                        callback(entry, path + ntpath.sep + entry.get_longname(), depth)
    +222
    +223                # Next directories to explore
    +224                for entry in entries:
    +225                    if entry.is_directory():
    +226                        next_directories_to_explore.append(path + ntpath.sep + entry.get_longname() + ntpath.sep)
    +227            
    +228            return next_directories_to_explore
    +229        # 
    +230        if callback is not None:
    +231            depth = 0
    +232            while len(paths) != 0:
    +233                paths = recurse_action(
    +234                    paths=paths,
    +235                    depth=depth,
    +236                    callback=callback
    +237                )
    +238                depth = depth + 1
    +239        else:
    +240            print("[!] SMBSession.find(), callback function cannot be None.")
     
    @@ -2824,56 +3142,81 @@

    -
    241    def get_file(self, path=None, keepRemotePath=False):
    -242        """
    -243        Retrieves a file from the specified path on the SMB share.
    -244
    -245        This method attempts to retrieve a file from the given path within the currently connected SMB share.
    -246        If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local
    -247        file object and writing the contents of the remote file to it using the SMB client's getFile method.
    -248
    -249        Parameters:
    -250            path (str): The path of the file to retrieve. If None, uses the current smb_path.
    -251
    -252        Returns:
    -253            None
    -254        """
    -255
    -256        tmp_file_path = self.smb_cwd + ntpath.sep + path
    -257        matches = self.smbClient.listPath(
    -258            shareName=self.smb_share, 
    -259            path=tmp_file_path
    -260        )
    -261        
    -262        for entry in matches:
    -263            if entry.is_directory():
    -264                print("[>] Skipping '%s' because it is a directory." % tmp_file_path)
    -265            else:
    -266                try:
    -267                    if ntpath.sep in path:
    -268                        outputfile = ntpath.dirname(path) + ntpath.sep + entry.get_longname()
    -269                    else:
    -270                        outputfile = entry.get_longname()
    -271                    f = LocalFileIO(
    -272                        mode="wb", 
    -273                        path=outputfile,
    -274                        expected_size=entry.get_filesize(), 
    -275                        debug=self.config.debug,
    -276                        keepRemotePath=keepRemotePath
    -277                    )
    -278                    self.smbClient.getFile(
    -279                        shareName=self.smb_share, 
    -280                        pathName=tmp_file_path, 
    -281                        callback=f.write
    -282                    )
    -283                    f.close()
    -284                except (BrokenPipeError, KeyboardInterrupt) as e:
    -285                    f.close()
    -286                    print("\x1b[v\x1b[o\r[!] Interrupted.")
    -287                    self.close_smb_session()
    -288                    self.init_smb_session()
    -289                        
    -290        return None
    +            
    242    def get_file(self, path=None, keepRemotePath=False):
    +243        """
    +244        Retrieves a file from the specified path on the SMB share.
    +245
    +246        This method attempts to retrieve a file from the given path within the currently connected SMB share.
    +247        If the path points to a directory, it skips the retrieval. It handles file retrieval by creating a local
    +248        file object and writing the contents of the remote file to it using the SMB client's getFile method.
    +249
    +250        Parameters:
    +251            path (str): The path of the file to retrieve. If None, uses the current smb_path.
    +252
    +253        Returns:
    +254            None
    +255        """
    +256
    +257        # Parse path
    +258        path = path.replace('/', ntpath.sep)
    +259        if ntpath.sep in path:
    +260            tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep + ntpath.dirname(path))
    +261        else:
    +262            tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep)
    +263        # Parse filename
    +264        filename = ntpath.basename(path)
    +265
    +266        # Search for the file
    +267        matches = self.smbClient.listPath(
    +268            shareName=self.smb_share, 
    +269            path=tmp_search_path + ntpath.sep + '*'
    +270        )   
    +271
    +272        # Filter the entries
    +273        matching_entries = []
    +274        for entry in matches:
    +275            if entry.is_directory():
    +276                # Skip directories
    +277                continue
    +278            if entry.get_longname() == filename:
    +279                matching_entries.append(entry)
    +280            elif '*' in filename:
    +281                regexp = filename.replace('.', '\\.').replace('*', '.*')
    +282                if re.match(regexp, entry.get_longname()):
    +283                    matching_entries.append(entry)
    +284        
    +285        matching_entries = sorted(list(set(matching_entries)), key=lambda x: x.get_longname())
    +286
    +287        for entry in matching_entries:
    +288            if entry.is_directory():
    +289                if self.config.debug:
    +290                    print("[debug] [>] Skipping '%s' because it is a directory." % (tmp_search_path + ntpath.sep + entry.get_longname()))
    +291            else:
    +292                try:
    +293                    if ntpath.sep in path:
    +294                        outputfile = ntpath.dirname(path) + ntpath.sep + entry.get_longname()
    +295                    else:
    +296                        outputfile = entry.get_longname()
    +297                    f = LocalFileIO(
    +298                        mode="wb", 
    +299                        path=outputfile,
    +300                        expected_size=entry.get_filesize(), 
    +301                        debug=self.config.debug,
    +302                        keepRemotePath=keepRemotePath
    +303                    )
    +304                    self.smbClient.getFile(
    +305                        shareName=self.smb_share, 
    +306                        pathName=tmp_search_path + ntpath.sep + entry.get_longname(), 
    +307                        callback=f.write
    +308                    )
    +309                    f.close()
    +310                except (BrokenPipeError, KeyboardInterrupt) as e:
    +311                    f.close()
    +312                    print("\x1b[v\x1b[o\r[!] Interrupted.")
    +313                    self.close_smb_session()
    +314                    self.init_smb_session()
    +315                        
    +316        return None
     
    @@ -2903,79 +3246,79 @@

    -
    292    def get_file_recursively(self, path=None):
    -293        """
    -294        Recursively retrieves files from a specified path on the SMB share.
    -295
    -296        This method navigates through all directories starting from the given path,
    -297        and downloads all files found. It handles directories recursively, ensuring
    -298        that all nested files are retrieved. The method skips over directory entries
    -299        and handles errors gracefully, attempting to continue the operation where possible.
    -300
    -301        Parameters:
    -302            path (str): The initial directory path from which to start the recursive file retrieval.
    -303                        If None, it starts from the root of the configured SMB share.
    -304        """
    -305        
    -306        def recurse_action(base_dir="", path=[]):
    -307            if len(base_dir) == 0:
    -308                remote_smb_path = ntpath.sep.join(path)
    -309            else:
    -310                remote_smb_path = base_dir + ntpath.sep + ntpath.sep.join(path)
    -311            remote_smb_path = ntpath.normpath(remote_smb_path)
    -312
    -313            entries = self.smbClient.listPath(
    -314                shareName=self.smb_share, 
    -315                path=remote_smb_path + '\\*'
    -316            )
    -317            if len(entries) != 0:
    -318                files = [entry for entry in entries if not entry.is_directory()]
    -319                directories = [entry for entry in entries if entry.is_directory() and entry.get_longname() not in [".", ".."]]
    -320
    -321                # Files
    -322                if len(files) != 0:
    -323                    print("[>] Retrieving files of '%s'" % remote_smb_path)
    -324                for entry_file in files:
    -325                    if not entry_file.is_directory():
    -326                        f = LocalFileIO(
    -327                            mode="wb",
    -328                            path=remote_smb_path + ntpath.sep + entry_file.get_longname(), 
    -329                            expected_size=entry_file.get_filesize(),
    -330                            keepRemotePath=True,
    -331                            debug=self.config.debug
    -332                        )
    -333                        try:
    -334                            self.smbClient.getFile(
    -335                                shareName=self.smb_share, 
    -336                                pathName=remote_smb_path + ntpath.sep + entry_file.get_longname(), 
    -337                                callback=f.write
    -338                            )
    -339                            f.close()
    -340                        except BrokenPipeError as err:
    -341                            f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err))
    -342                            f.close(remove=True)
    -343                            break
    -344                        except Exception as err:
    -345                            f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err))
    -346                            f.close(remove=True)
    -347                
    -348                # Directories
    -349                for entry_directory in directories:
    -350                    if entry_directory.is_directory():
    -351                        recurse_action(
    -352                            base_dir=self.smb_cwd, 
    -353                            path=path+[entry_directory.get_longname()]
    -354                        )                   
    -355        # Entrypoint
    -356        try:
    -357            recurse_action(
    -358                base_dir=self.smb_cwd, 
    -359                path=[path]
    -360            )
    -361        except (BrokenPipeError, KeyboardInterrupt) as e:
    -362            print("\x1b[v\x1b[o\r[!] Interrupted.")
    -363            self.close_smb_session()
    -364            self.init_smb_session()
    +            
    318    def get_file_recursively(self, path=None):
    +319        """
    +320        Recursively retrieves files from a specified path on the SMB share.
    +321
    +322        This method navigates through all directories starting from the given path,
    +323        and downloads all files found. It handles directories recursively, ensuring
    +324        that all nested files are retrieved. The method skips over directory entries
    +325        and handles errors gracefully, attempting to continue the operation where possible.
    +326
    +327        Parameters:
    +328            path (str): The initial directory path from which to start the recursive file retrieval.
    +329                        If None, it starts from the root of the configured SMB share.
    +330        """
    +331        
    +332        def recurse_action(base_dir="", path=[]):
    +333            if len(base_dir) == 0:
    +334                remote_smb_path = ntpath.sep.join(path)
    +335            else:
    +336                remote_smb_path = base_dir + ntpath.sep + ntpath.sep.join(path)
    +337            remote_smb_path = ntpath.normpath(remote_smb_path)
    +338
    +339            entries = self.smbClient.listPath(
    +340                shareName=self.smb_share, 
    +341                path=remote_smb_path + '\\*'
    +342            )
    +343            if len(entries) != 0:
    +344                files = [entry for entry in entries if not entry.is_directory()]
    +345                directories = [entry for entry in entries if entry.is_directory() and entry.get_longname() not in [".", ".."]]
    +346
    +347                # Files
    +348                if len(files) != 0:
    +349                    print("[>] Retrieving files of '%s'" % remote_smb_path)
    +350                for entry_file in files:
    +351                    if not entry_file.is_directory():
    +352                        f = LocalFileIO(
    +353                            mode="wb",
    +354                            path=remote_smb_path + ntpath.sep + entry_file.get_longname(), 
    +355                            expected_size=entry_file.get_filesize(),
    +356                            keepRemotePath=True,
    +357                            debug=self.config.debug
    +358                        )
    +359                        try:
    +360                            self.smbClient.getFile(
    +361                                shareName=self.smb_share, 
    +362                                pathName=remote_smb_path + ntpath.sep + entry_file.get_longname(), 
    +363                                callback=f.write
    +364                            )
    +365                            f.close()
    +366                        except BrokenPipeError as err:
    +367                            f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err))
    +368                            f.close(remove=True)
    +369                            break
    +370                        except Exception as err:
    +371                            f.set_error(message="[bold red]Failed downloading '%s': %s" % (f.path, err))
    +372                            f.close(remove=True)
    +373                
    +374                # Directories
    +375                for entry_directory in directories:
    +376                    if entry_directory.is_directory():
    +377                        recurse_action(
    +378                            base_dir=self.smb_cwd, 
    +379                            path=path+[entry_directory.get_longname()]
    +380                        )                   
    +381        # Entrypoint
    +382        try:
    +383            recurse_action(
    +384                base_dir=self.smb_cwd, 
    +385                path=[path]
    +386            )
    +387        except (BrokenPipeError, KeyboardInterrupt) as e:
    +388            print("\x1b[v\x1b[o\r[!] Interrupted.")
    +389            self.close_smb_session()
    +390            self.init_smb_session()
     
    @@ -3004,29 +3347,29 @@

    -
    366    def get_entry(self, path=None):
    -367        """
    -368        Retrieves information about a specific entry located at the provided path on the SMB share.
    -369
    -370        This method checks if the specified path exists on the SMB share. If the path exists, it retrieves the details of the entry at that path, including the directory name and file name. If the entry is found, it returns the entry object; otherwise, it returns None.
    -371
    -372        Args:
    -373            path (str): The path of the entry to retrieve information about.
    -374
    -375        Returns:
    -376            Entry: An object representing the entry at the specified path, or None if the entry is not found.
    -377        """
    -378
    -379        if self.path_exists(path=path):
    -380            matches = self.smbClient.listPath(shareName=self.smb_share, path=path)
    -381
    -382            if len(matches) == 1:
    -383                return matches[0]
    -384            else:
    -385                return None
    -386            
    -387        else:
    -388            return None 
    +            
    392    def get_entry(self, path=None):
    +393        """
    +394        Retrieves information about a specific entry located at the provided path on the SMB share.
    +395
    +396        This method checks if the specified path exists on the SMB share. If the path exists, it retrieves the details of the entry at that path, including the directory name and file name. If the entry is found, it returns the entry object; otherwise, it returns None.
    +397
    +398        Args:
    +399            path (str): The path of the entry to retrieve information about.
    +400
    +401        Returns:
    +402            Entry: An object representing the entry at the specified path, or None if the entry is not found.
    +403        """
    +404
    +405        if self.path_exists(path=path):
    +406            matches = self.smbClient.listPath(shareName=self.smb_share, path=path)
    +407
    +408            if len(matches) == 1:
    +409                return matches[0]
    +410            else:
    +411                return None
    +412            
    +413        else:
    +414            return None 
     
    @@ -3054,80 +3397,80 @@

    -
    390    def info(self, share=True, server=True):
    -391        """
    -392        Displays information about the server and optionally the shares.
    -393
    -394        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.
    -395
    -396        Parameters:
    -397            share (bool): If True, display information about the current share.
    -398            server (bool): If True, display information about the server.
    -399
    -400        Returns:
    -401            None
    -402        """
    -403
    -404        if server:
    -405            if self.config.no_colors:
    -406                print("[+] Server:")
    -407                print("  ├─NetBIOS:")
    -408                print("  │ ├─ NetBIOS Hostname ──────── : %s" % (self.smbClient.getServerName()))
    -409                print("  │ └─ NetBIOS Domain ────────── : %s" % (self.smbClient.getServerDomain()))
    -410                print("  ├─DNS:")
    -411                print("  │ ├─ DNS Hostname ──────────── : %s" % (self.smbClient.getServerDNSHostName()))
    -412                print("  │ └─ DNS Domain ────────────── : %s" % (self.smbClient.getServerDNSDomainName()))
    -413                print("  ├─OS:")
    -414                print("  │ ├─ OS Name ───────────────── : %s" % (self.smbClient.getServerOS()))
    -415                print("  │ └─ OS Version ────────────── : %s.%s.%s" % (self.smbClient.getServerOSMajor(), self.smbClient.getServerOSMinor(), self.smbClient.getServerOSBuild()))
    -416                print("  ├─Server:")
    -417                print("  │ ├─ Signing Required ──────── : %s" % (self.smbClient.isSigningRequired()))
    -418                print("  │ ├─ Login Required ────────── : %s" % (self.smbClient.isLoginRequired()))
    -419                print("  │ ├─ Supports NTLMv2 ───────── : %s" % (self.smbClient.doesSupportNTLMv2()))
    -420                MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"]
    -421                print("  │ ├─ Max size of read chunk ── : %d bytes (%s)" % (MaxReadSize, b_filesize(MaxReadSize)))
    -422                MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"]
    -423                print("  │ └─ Max size of write chunk ─ : %d bytes (%s)" % (MaxWriteSize, b_filesize(MaxWriteSize)))
    -424                print("  └─")
    -425            else:
    -426                print("[+] Server:")
    -427                print("  ├─NetBIOS:")
    -428                print("  │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerName()))
    -429                print("  │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDomain()))
    -430                print("  ├─DNS:")
    -431                print("  │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSHostName()))
    -432                print("  │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSDomainName()))
    -433                print("  ├─OS:")
    -434                print("  │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerOS()))
    -435                print("  │ └─ \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()))
    -436                print("  ├─Server:")
    -437                print("  │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isSigningRequired()))
    -438                print("  │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isLoginRequired()))
    -439                print("  │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.doesSupportNTLMv2()))
    -440                MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"]
    -441                print("  │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxReadSize, b_filesize(MaxReadSize)))
    -442                MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"]
    -443                print("  │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxWriteSize, b_filesize(MaxWriteSize)))
    -444                print("  └─")
    -445
    -446        if share and self.smb_share is not None:
    -447            share_name = self.available_shares.get(self.smb_share.lower(), "")["name"]
    -448            share_comment = self.available_shares.get(self.smb_share.lower(), "")["comment"]
    -449            share_type = self.available_shares.get(self.smb_share.lower(), "")["type"]
    -450            share_type =', '.join([s.replace("STYPE_","") for s in share_type])
    -451            share_rawtype = self.available_shares.get(self.smb_share.lower(), "")["rawtype"]
    -452            if self.config.no_colors:
    -453                print("\n[+] Share:")
    -454                print("  ├─ Name ──────────── : %s" % (share_name))
    -455                print("  ├─ Description ───── : %s" % (share_comment))
    -456                print("  ├─ Type ──────────── : %s" % (share_type))
    -457                print("  └─ Raw type value ── : %s" % (share_rawtype))
    -458            else:
    -459                print("\n[+] Share:")
    -460                print("  ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_name))
    -461                print("  ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_comment))
    -462                print("  ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_type))
    -463                print("  └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m" % (share_rawtype))
    +            
    416    def info(self, share=True, server=True):
    +417        """
    +418        Displays information about the server and optionally the shares.
    +419
    +420        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.
    +421
    +422        Parameters:
    +423            share (bool): If True, display information about the current share.
    +424            server (bool): If True, display information about the server.
    +425
    +426        Returns:
    +427            None
    +428        """
    +429
    +430        if server:
    +431            if self.config.no_colors:
    +432                print("[+] Server:")
    +433                print("  ├─NetBIOS:")
    +434                print("  │ ├─ NetBIOS Hostname ──────── : %s" % (self.smbClient.getServerName()))
    +435                print("  │ └─ NetBIOS Domain ────────── : %s" % (self.smbClient.getServerDomain()))
    +436                print("  ├─DNS:")
    +437                print("  │ ├─ DNS Hostname ──────────── : %s" % (self.smbClient.getServerDNSHostName()))
    +438                print("  │ └─ DNS Domain ────────────── : %s" % (self.smbClient.getServerDNSDomainName()))
    +439                print("  ├─OS:")
    +440                print("  │ ├─ OS Name ───────────────── : %s" % (self.smbClient.getServerOS()))
    +441                print("  │ └─ OS Version ────────────── : %s.%s.%s" % (self.smbClient.getServerOSMajor(), self.smbClient.getServerOSMinor(), self.smbClient.getServerOSBuild()))
    +442                print("  ├─Server:")
    +443                print("  │ ├─ Signing Required ──────── : %s" % (self.smbClient.isSigningRequired()))
    +444                print("  │ ├─ Login Required ────────── : %s" % (self.smbClient.isLoginRequired()))
    +445                print("  │ ├─ Supports NTLMv2 ───────── : %s" % (self.smbClient.doesSupportNTLMv2()))
    +446                MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"]
    +447                print("  │ ├─ Max size of read chunk ── : %d bytes (%s)" % (MaxReadSize, b_filesize(MaxReadSize)))
    +448                MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"]
    +449                print("  │ └─ Max size of write chunk ─ : %d bytes (%s)" % (MaxWriteSize, b_filesize(MaxWriteSize)))
    +450                print("  └─")
    +451            else:
    +452                print("[+] Server:")
    +453                print("  ├─NetBIOS:")
    +454                print("  │ ├─ \x1b[94mNetBIOS Hostname\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerName()))
    +455                print("  │ └─ \x1b[94mNetBIOS Domain\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDomain()))
    +456                print("  ├─DNS:")
    +457                print("  │ ├─ \x1b[94mDNS Hostname\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSHostName()))
    +458                print("  │ └─ \x1b[94mDNS Domain\x1b[0m \x1b[90m──────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerDNSDomainName()))
    +459                print("  ├─OS:")
    +460                print("  │ ├─ \x1b[94mOS Name\x1b[0m \x1b[90m─────────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.getServerOS()))
    +461                print("  │ └─ \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()))
    +462                print("  ├─Server:")
    +463                print("  │ ├─ \x1b[94mSigning Required\x1b[0m \x1b[90m────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isSigningRequired()))
    +464                print("  │ ├─ \x1b[94mLogin Required\x1b[0m \x1b[90m──────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.isLoginRequired()))
    +465                print("  │ ├─ \x1b[94mSupports NTLMv2\x1b[0m \x1b[90m─────────\x1b[0m : \x1b[93m%s\x1b[0m" % (self.smbClient.doesSupportNTLMv2()))
    +466                MaxReadSize = self.smbClient.getIOCapabilities()["MaxReadSize"]
    +467                print("  │ ├─ \x1b[94mMax size of read chunk\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxReadSize, b_filesize(MaxReadSize)))
    +468                MaxWriteSize = self.smbClient.getIOCapabilities()["MaxWriteSize"]
    +469                print("  │ └─ \x1b[94mMax size of write chunk\x1b[0m \x1b[90m─\x1b[0m : \x1b[93m%d bytes (%s)\x1b[0m" % (MaxWriteSize, b_filesize(MaxWriteSize)))
    +470                print("  └─")
    +471
    +472        if share and self.smb_share is not None:
    +473            share_name = self.available_shares.get(self.smb_share.lower(), "")["name"]
    +474            share_comment = self.available_shares.get(self.smb_share.lower(), "")["comment"]
    +475            share_type = self.available_shares.get(self.smb_share.lower(), "")["type"]
    +476            share_type =', '.join([s.replace("STYPE_","") for s in share_type])
    +477            share_rawtype = self.available_shares.get(self.smb_share.lower(), "")["rawtype"]
    +478            if self.config.no_colors:
    +479                print("\n[+] Share:")
    +480                print("  ├─ Name ──────────── : %s" % (share_name))
    +481                print("  ├─ Description ───── : %s" % (share_comment))
    +482                print("  ├─ Type ──────────── : %s" % (share_type))
    +483                print("  └─ Raw type value ── : %s" % (share_rawtype))
    +484            else:
    +485                print("\n[+] Share:")
    +486                print("  ├─ \x1b[94mName\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_name))
    +487                print("  ├─ \x1b[94mDescription\x1b[0m \x1b[90m─────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_comment))
    +488                print("  ├─ \x1b[94mType\x1b[0m \x1b[90m────────────\x1b[0m : \x1b[93m%s\x1b[0m" % (share_type))
    +489                print("  └─ \x1b[94mRaw type value\x1b[0m \x1b[90m──\x1b[0m : \x1b[93m%s\x1b[0m" % (share_rawtype))
     
    @@ -3156,37 +3499,37 @@

    -
    465    def list_contents(self, path=None):
    -466        """
    -467        Lists the contents of a specified directory on the SMB share.
    -468
    -469        This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path`
    -470        is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with
    -471        the long names of the files and directories as keys and their respective SMB entry objects as values.
    -472
    -473        Args:
    -474            shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.
    -475            path (str, optional): The directory path to list contents from. Defaults to the current path if None.
    -476
    -477        Returns:
    -478            dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
    -479        """
    -480        
    -481        dest_path = [self.smb_cwd.rstrip(ntpath.sep),]
    -482        if path is not None and len(path) > 0:
    -483            dest_path.append(path.rstrip(ntpath.sep))
    -484        dest_path.append('*')
    -485        path = ntpath.sep.join(dest_path)
    -486
    -487        contents = {}
    -488        entries = self.smbClient.listPath(
    -489            shareName=self.smb_share, 
    -490            path=path
    -491        )
    -492        for entry in entries:
    -493            contents[entry.get_longname()] = entry
    +            
    491    def list_contents(self, path=None):
    +492        """
    +493        Lists the contents of a specified directory on the SMB share.
     494
    -495        return contents
    +495        This method retrieves the contents of a directory specified by `shareName` and `path`. If `shareName` or `path`
    +496        is not provided, it defaults to the instance's current SMB share or path. The method returns a dictionary with
    +497        the long names of the files and directories as keys and their respective SMB entry objects as values.
    +498
    +499        Args:
    +500            shareName (str, optional): The name of the SMB share. Defaults to the current SMB share if None.
    +501            path (str, optional): The directory path to list contents from. Defaults to the current path if None.
    +502
    +503        Returns:
    +504            dict: A dictionary with file and directory names as keys and their SMB entry objects as values.
    +505        """
    +506        
    +507        dest_path = [self.smb_cwd.rstrip(ntpath.sep),]
    +508        if path is not None and len(path) > 0:
    +509            dest_path.append(path.rstrip(ntpath.sep))
    +510        dest_path.append('*')
    +511        path = ntpath.sep.join(dest_path)
    +512
    +513        contents = {}
    +514        entries = self.smbClient.listPath(
    +515            shareName=self.smb_share, 
    +516            path=path
    +517        )
    +518        for entry in entries:
    +519            contents[entry.get_longname()] = entry
    +520
    +521        return contents
     
    @@ -3217,41 +3560,41 @@

    -
    497    def list_shares(self):
    -498        """
    -499        Lists all the shares available on the connected SMB server.
    -500
    -501        This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary
    -502        with key-value pairs where the key is the share name and the value is a dictionary containing details about the share
    -503        such as its name, type, raw type, and any comments associated with the share.
    -504
    -505        Returns:
    -506            dict: A dictionary containing information about each share available on the server.
    -507        """
    -508
    -509        self.available_shares = {}
    -510
    -511        if self.connected:
    -512            if self.smbClient is not None:
    -513                resp = self.smbClient.listShares()
    -514
    -515                for share in resp:
    -516                    # SHARE_INFO_1 structure (lmshare.h)
    -517                    # https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1
    -518                    sharename = share["shi1_netname"][:-1]
    -519                    sharecomment = share["shi1_remark"][:-1]
    -520                    sharetype = share["shi1_type"]
    -521
    -522                    self.available_shares[sharename.lower()] = {
    -523                        "name": sharename, 
    -524                        "type": STYPE_MASK(sharetype), 
    -525                        "rawtype": sharetype, 
    -526                        "comment": sharecomment
    -527                    }
    -528            else:
    -529                print("[!] Error: SMBSession.smbClient is None.")
    +            
    523    def list_shares(self):
    +524        """
    +525        Lists all the shares available on the connected SMB server.
    +526
    +527        This method queries the SMB server to retrieve a list of all available shares. It populates the `shares` dictionary
    +528        with key-value pairs where the key is the share name and the value is a dictionary containing details about the share
    +529        such as its name, type, raw type, and any comments associated with the share.
     530
    -531        return self.available_shares
    +531        Returns:
    +532            dict: A dictionary containing information about each share available on the server.
    +533        """
    +534
    +535        self.available_shares = {}
    +536
    +537        if self.connected:
    +538            if self.smbClient is not None:
    +539                resp = self.smbClient.listShares()
    +540
    +541                for share in resp:
    +542                    # SHARE_INFO_1 structure (lmshare.h)
    +543                    # https://learn.microsoft.com/en-us/windows/win32/api/lmshare/ns-lmshare-share_info_1
    +544                    sharename = share["shi1_netname"][:-1]
    +545                    sharecomment = share["shi1_remark"][:-1]
    +546                    sharetype = share["shi1_type"]
    +547
    +548                    self.available_shares[sharename.lower()] = {
    +549                        "name": sharename, 
    +550                        "type": STYPE_MASK(sharetype), 
    +551                        "rawtype": sharetype, 
    +552                        "comment": sharecomment
    +553                    }
    +554            else:
    +555                print("[!] Error: SMBSession.smbClient is None.")
    +556
    +557        return self.available_shares
     
    @@ -3278,49 +3621,49 @@

    -
    533    def mkdir(self, path=None):
    -534        """
    -535        Creates a directory at the specified path on the SMB share.
    -536
    -537        This method takes a path and attempts to create the directory structure on the SMB share. If the path includes
    -538        nested directories, it will create each directory in the sequence. If a directory already exists, it will skip
    -539        the creation for that directory without raising an error.
    -540
    -541        Args:
    -542            path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
    -543
    -544        Note:
    -545            The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
    -546        """
    -547
    -548        if path is not None:
    -549            # Prepare path
    -550            path = path.replace('/',ntpath.sep)
    -551            if ntpath.sep in path:
    -552                path = path.strip(ntpath.sep).split(ntpath.sep)
    -553            else:
    -554                path = [path]
    -555
    -556            # Create each dir in the path
    -557            for depth in range(1, len(path)+1):
    -558                tmp_path = ntpath.sep.join(path[:depth])
    -559                try:
    -560                    self.smbClient.createDirectory(
    -561                        shareName=self.smb_share, 
    -562                        pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + tmp_path + ntpath.sep)
    -563                    )
    -564                except impacket.smbconnection.SessionError as err:
    -565                    if err.getErrorCode() == 0xc0000035:
    -566                        # STATUS_OBJECT_NAME_COLLISION
    -567                        # Remote directory already created, this is normal
    -568                        # Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19
    -569                        pass
    -570                    else:
    -571                        print("[!] Failed to create directory '%s': %s" % (tmp_path, err))
    -572                        if self.config.debug:
    -573                            traceback.print_exc()
    -574        else:
    -575            pass
    +            
    559    def mkdir(self, path=None):
    +560        """
    +561        Creates a directory at the specified path on the SMB share.
    +562
    +563        This method takes a path and attempts to create the directory structure on the SMB share. If the path includes
    +564        nested directories, it will create each directory in the sequence. If a directory already exists, it will skip
    +565        the creation for that directory without raising an error.
    +566
    +567        Args:
    +568            path (str, optional): The full path of the directory to create on the SMB share. Defaults to None.
    +569
    +570        Note:
    +571            The path should use forward slashes ('/') which will be converted to backslashes (ntpath.sep) for SMB compatibility.
    +572        """
    +573
    +574        if path is not None:
    +575            # Prepare path
    +576            path = path.replace('/',ntpath.sep)
    +577            if ntpath.sep in path:
    +578                path = path.strip(ntpath.sep).split(ntpath.sep)
    +579            else:
    +580                path = [path]
    +581
    +582            # Create each dir in the path
    +583            for depth in range(1, len(path)+1):
    +584                tmp_path = ntpath.sep.join(path[:depth])
    +585                try:
    +586                    self.smbClient.createDirectory(
    +587                        shareName=self.smb_share, 
    +588                        pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + tmp_path + ntpath.sep)
    +589                    )
    +590                except impacket.smbconnection.SessionError as err:
    +591                    if err.getErrorCode() == 0xc0000035:
    +592                        # STATUS_OBJECT_NAME_COLLISION
    +593                        # Remote directory already created, this is normal
    +594                        # Src: https://github.com/fortra/impacket/blob/269ce69872f0e8f2188a80addb0c39fedfa6dcb8/impacket/nt_errors.py#L268C9-L268C19
    +595                        pass
    +596                    else:
    +597                        print("[!] Failed to create directory '%s': %s" % (tmp_path, err))
    +598                        if self.config.debug:
    +599                            traceback.print_exc()
    +600        else:
    +601            pass
     
    @@ -3350,35 +3693,72 @@

    -
    577    def mount(self, local_mount_point, remote_path):
    -578
    -579        if not os.path.exists(local_mount_point):
    -580            pass
    -581
    -582        if sys.platform.startswith('win'):
    -583            remote_path = remote_path.replace('/',ntpath.sep)
    -584            command = f"net use {local_mount_point} \\\\{self.address}\\{self.smb_share}\\{remote_path}"
    -585        
    -586        elif sys.platform.startswith('linux'):
    -587            remote_path = remote_path.replace(ntpath.sep,'/')
    -588            command = f"mount -t cifs //{self.address}/{self.smb_share}/{remote_path} {local_mount_point} -o username={self.username},password={self.password}"
    -589        
    -590        elif sys.platform.startswith('darwin'):
    -591            remote_path = remote_path.replace(ntpath.sep,'/')
    -592            command = f"mount_smbfs //{self.username}:{self.password}@{self.address}/{self.smb_share}/{remote_path} {local_mount_point}"
    -593        
    -594        else:
    -595            command = None
    -596            print("[!] Unsupported platform for mounting SMB share.")
    -597        
    -598        if command is not None:
    -599            if self.config.debug:
    -600                print("[debug] Executing: %s" % command)
    -601            os.system(command)
    +            
    603    def mount(self, local_mount_point, remote_path):
    +604        """
    +605        Generates the command to mount an SMB share on different platforms.
    +606
    +607        This method takes the local mount point and the remote path of the SMB share and generates the appropriate mount command based on the platform.
    +608        It constructs the mount command using the provided parameters and executes it using the os.system() function.
    +609
    +610        Args:
    +611            local_mount_point (str): The local directory where the SMB share will be mounted.
    +612            remote_path (str): The remote path on the SMB share to be mounted.
    +613
    +614        Note:
    +615            - For Windows platform, the command uses 'net use' to mount the share.
    +616            - For Linux platform, the command uses 'mount' to mount the share.
    +617            - For macOS platform, the command uses 'mount_smbfs' to mount the share.
    +618            - If the platform is not supported, an error message is displayed.
    +619
    +620        Returns:
    +621            None
    +622        """
    +623
    +624        if not os.path.exists(local_mount_point):
    +625            pass
    +626
    +627        if sys.platform.startswith('win'):
    +628            remote_path = remote_path.replace('/',ntpath.sep)
    +629            command = f"net use {local_mount_point} \\\\{self.address}\\{self.smb_share}\\{remote_path}"
    +630        
    +631        elif sys.platform.startswith('linux'):
    +632            remote_path = remote_path.replace(ntpath.sep,'/')
    +633            command = f"mount -t cifs //{self.address}/{self.smb_share}/{remote_path} {local_mount_point} -o username={self.username},password={self.password}"
    +634        
    +635        elif sys.platform.startswith('darwin'):
    +636            remote_path = remote_path.replace(ntpath.sep,'/')
    +637            command = f"mount_smbfs //{self.username}:{self.password}@{self.address}/{self.smb_share}/{remote_path} {local_mount_point}"
    +638        
    +639        else:
    +640            command = None
    +641            print("[!] Unsupported platform for mounting SMB share.")
    +642        
    +643        if command is not None:
    +644            if self.config.debug:
    +645                print("[debug] Executing: %s" % command)
    +646            os.system(command)
     
    - +

    Generates the command to mount an SMB share on different platforms.

    + +

    This method takes the local mount point and the remote path of the SMB share and generates the appropriate mount command based on the platform. +It constructs the mount command using the provided parameters and executes it using the os.system() function.

    + +

    Args: + local_mount_point (str): The local directory where the SMB share will be mounted. + remote_path (str): The remote path on the SMB share to be mounted.

    + +

    Note: + - For Windows platform, the command uses 'net use' to mount the share. + - For Linux platform, the command uses 'mount' to mount the share. + - For macOS platform, the command uses 'mount_smbfs' to mount the share. + - If the platform is not supported, an error message is displayed.

    + +

    Returns: + None

    +
    +
    @@ -3392,32 +3772,32 @@

    -
    603    def path_exists(self, path=None):
    -604        """
    -605        Checks if the specified path exists on the SMB share.
    -606
    -607        This method determines if a given path exists on the SMB share by attempting to list the contents of the path.
    -608        If the path listing is successful and returns one or more entries, the path is considered to exist.
    -609
    -610        Args:
    -611            path (str, optional): The path to check on the SMB share. Defaults to None.
    -612
    -613        Returns:
    -614            bool: True if the path exists, False otherwise or if an error occurs.
    -615        """
    -616
    -617        if path is not None:
    -618            path = path.replace('*','')
    -619            try:
    -620                contents = self.smbClient.listPath(
    -621                    shareName=self.smb_share,
    -622                    path=ntpath.normpath(self.smb_cwd + ntpath.sep + path + ntpath.sep)
    -623                )
    -624                return (len(contents) != 0)
    -625            except Exception as e:
    -626                return False
    -627        else:
    -628            return False
    +            
    648    def path_exists(self, path=None):
    +649        """
    +650        Checks if the specified path exists on the SMB share.
    +651
    +652        This method determines if a given path exists on the SMB share by attempting to list the contents of the path.
    +653        If the path listing is successful and returns one or more entries, the path is considered to exist.
    +654
    +655        Args:
    +656            path (str, optional): The path to check on the SMB share. Defaults to None.
    +657
    +658        Returns:
    +659            bool: True if the path exists, False otherwise or if an error occurs.
    +660        """
    +661
    +662        if path is not None:
    +663            path = path.replace('*','')
    +664            try:
    +665                contents = self.smbClient.listPath(
    +666                    shareName=self.smb_share,
    +667                    path=ntpath.normpath(self.smb_cwd + ntpath.sep + path + ntpath.sep)
    +668                )
    +669                return (len(contents) != 0)
    +670            except Exception as e:
    +671                return False
    +672        else:
    +673            return False
     
    @@ -3446,49 +3826,49 @@

    -
    630    def path_isdir(self, pathFromRoot=None):
    -631        """
    -632        Checks if the specified path is a directory on the SMB share.
    -633
    -634        This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the
    -635        contents of the path and filtering for entries that match the basename of the path and are marked as directories.
    -636
    -637        Args:
    -638            path (str, optional): The path to check on the SMB share. Defaults to None.
    -639
    -640        Returns:
    -641            bool: True if the path is a directory, False otherwise or if an error occurs.
    -642        """
    -643
    -644        if pathFromRoot is not None:
    -645            # Replace slashes if any
    -646            path = pathFromRoot.replace('/', ntpath.sep)
    -647            
    -648            # Strip wildcards to avoid injections
    -649            path = path.replace('*','')
    -650
    -651            # Normalize path and strip leading backslash
    -652            path = ntpath.normpath(path + ntpath.sep).lstrip(ntpath.sep)
    -653
    -654            if path.strip() in ['', '.', '..']:
    -655                # By defininition they exist on the filesystem
    -656                return True
    -657            else:
    -658                try:
    -659                    contents = self.smbClient.listPath(
    -660                        shareName=self.smb_share,
    -661                        path=path+'*'
    -662                    )
    -663                    # Filter on directories
    -664                    contents = [
    -665                        c for c in contents
    -666                        if c.get_longname() == ntpath.basename(path) and c.is_directory()
    -667                    ]
    -668                    return (len(contents) != 0)
    -669                except Exception as e:
    -670                    return False
    -671        else:
    -672            return False
    +            
    675    def path_isdir(self, pathFromRoot=None):
    +676        """
    +677        Checks if the specified path is a directory on the SMB share.
    +678
    +679        This method determines if a given path corresponds to a directory on the SMB share. It does this by listing the
    +680        contents of the path and filtering for entries that match the basename of the path and are marked as directories.
    +681
    +682        Args:
    +683            path (str, optional): The path to check on the SMB share. Defaults to None.
    +684
    +685        Returns:
    +686            bool: True if the path is a directory, False otherwise or if an error occurs.
    +687        """
    +688
    +689        if pathFromRoot is not None:
    +690            # Replace slashes if any
    +691            path = pathFromRoot.replace('/', ntpath.sep)
    +692            
    +693            # Strip wildcards to avoid injections
    +694            path = path.replace('*','')
    +695
    +696            # Normalize path and strip leading backslash
    +697            path = ntpath.normpath(path + ntpath.sep).lstrip(ntpath.sep)
    +698
    +699            if path.strip() in ['', '.', '..']:
    +700                # By defininition they exist on the filesystem
    +701                return True
    +702            else:
    +703                try:
    +704                    contents = self.smbClient.listPath(
    +705                        shareName=self.smb_share,
    +706                        path=path+'*'
    +707                    )
    +708                    # Filter on directories
    +709                    contents = [
    +710                        c for c in contents
    +711                        if c.get_longname() == ntpath.basename(path) and c.is_directory()
    +712                    ]
    +713                    return (len(contents) != 0)
    +714                except Exception as e:
    +715                    return False
    +716        else:
    +717            return False
     
    @@ -3517,39 +3897,39 @@

    -
    674    def path_isfile(self, path=None):
    -675        """
    -676        Checks if the specified path is a file on the SMB share.
    -677
    -678        This method determines if a given path corresponds to a file on the SMB share. It does this by listing the
    -679        contents of the path and filtering for entries that match the basename of the path and are not marked as directories.
    -680
    -681        Args:
    -682            path (str, optional): The path to check on the SMB share. Defaults to None.
    -683
    -684        Returns:
    -685            bool: True if the path is a file, False otherwise or if an error occurs.
    -686        """
    -687
    -688        if path is not None:
    -689            path = path.replace('*','')
    -690            search_dir = ntpath.normpath(self.smb_cwd + ntpath.sep + path)
    -691            search_dir = ntpath.dirname(search_dir) + ntpath.sep + '*'
    -692            try:
    -693                contents = self.smbClient.listPath(
    -694                    shareName=self.smb_share,
    -695                    path=search_dir
    -696                )
    -697                # Filter on files
    -698                contents = [
    -699                    c for c in contents
    -700                    if c.get_longname() == ntpath.basename(path) and not c.is_directory()
    -701                ]
    -702                return (len(contents) != 0)
    -703            except Exception as e:
    -704                return False
    -705        else:
    -706            return False
    +            
    719    def path_isfile(self, path=None):
    +720        """
    +721        Checks if the specified path is a file on the SMB share.
    +722
    +723        This method determines if a given path corresponds to a file on the SMB share. It does this by listing the
    +724        contents of the path and filtering for entries that match the basename of the path and are not marked as directories.
    +725
    +726        Args:
    +727            path (str, optional): The path to check on the SMB share. Defaults to None.
    +728
    +729        Returns:
    +730            bool: True if the path is a file, False otherwise or if an error occurs.
    +731        """
    +732
    +733        if path is not None:
    +734            path = path.replace('*','')
    +735            search_dir = ntpath.normpath(self.smb_cwd + ntpath.sep + path)
    +736            search_dir = ntpath.dirname(search_dir) + ntpath.sep + '*'
    +737            try:
    +738                contents = self.smbClient.listPath(
    +739                    shareName=self.smb_share,
    +740                    path=search_dir
    +741                )
    +742                # Filter on files
    +743                contents = [
    +744                    c for c in contents
    +745                    if c.get_longname() == ntpath.basename(path) and not c.is_directory()
    +746                ]
    +747                return (len(contents) != 0)
    +748            except Exception as e:
    +749                return False
    +750        else:
    +751            return False
     
    @@ -3578,22 +3958,22 @@

    -
    708    def ping_smb_session(self):
    -709        """
    -710        Tests the connectivity to the SMB server by sending an echo command.
    -711
    -712        This method attempts to send an echo command to the SMB server to check if the session is still active.
    -713        It updates the `connected` attribute of the class based on the success or failure of the echo command.
    -714
    -715        Returns:
    -716            bool: True if the echo command succeeds (indicating the session is active), False otherwise.
    -717        """
    -718
    -719        try:
    -720            self.smbClient.getSMBServer().echo()
    -721        except Exception as e:
    -722            self.connected = False
    -723        return self.connected
    +            
    753    def ping_smb_session(self):
    +754        """
    +755        Tests the connectivity to the SMB server by sending an echo command.
    +756
    +757        This method attempts to send an echo command to the SMB server to check if the session is still active.
    +758        It updates the `connected` attribute of the class based on the success or failure of the echo command.
    +759
    +760        Returns:
    +761            bool: True if the echo command succeeds (indicating the session is active), False otherwise.
    +762        """
    +763
    +764        try:
    +765            self.smbClient.getSMBServer().echo()
    +766        except Exception as e:
    +767            self.connected = False
    +768        return self.connected
     
    @@ -3619,45 +3999,72 @@

    -
    725    def put_file(self, localpath=None):
    -726        """
    -727        Uploads a single file to the SMB share.
    -728
    -729        This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.
    -730        It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.
    -731        General exceptions are caught and logged, with a traceback provided if debugging is enabled.
    -732
    -733        Args:
    -734            localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
    -735        """
    -736
    -737        if os.path.exists(localpath):
    -738            if os.path.isfile(localpath):
    -739                try:
    -740                    localfile = os.path.basename(localpath)
    -741                    f = LocalFileIO(
    -742                        mode="rb", 
    -743                        path=localpath, 
    -744                        debug=self.config.debug
    -745                    )
    -746                    self.smbClient.putFile(
    -747                        shareName=self.smb_share, 
    -748                        pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + localfile + ntpath.sep), 
    -749                        callback=f.read
    -750                    )
    -751                    f.close()
    -752                except (BrokenPipeError, KeyboardInterrupt) as err:
    -753                    print("[!] Interrupted.")
    -754                    self.close_smb_session()
    -755                    self.init_smb_session()
    -756                except Exception as err:
    -757                    print("[!] Failed to upload '%s': %s" % (localfile, err))
    -758                    if self.config.debug:
    -759                        traceback.print_exc()
    -760            else:
    -761                print("[!] The specified localpath is a directory. Use 'put -r <directory>' instead.")
    -762        else:
    -763            print("[!] The specified localpath does not exist.")
    +            
    770    def put_file(self, localpath=None):
    +771        """
    +772        Uploads a single file to the SMB share.
    +773
    +774        This method takes a local file path, opens the file, and uploads it to the SMB share at the specified path.
    +775        It handles exceptions such as broken pipe errors or keyboard interrupts by closing and reinitializing the SMB session.
    +776        General exceptions are caught and logged, with a traceback provided if debugging is enabled.
    +777
    +778        Args:
    +779            localpath (str, optional): The local file path of the file to be uploaded. Defaults to None.
    +780        """
    +781
    +782        # Parse path
    +783        localpath = localpath.replace('/', os.path.sep)
    +784        if os.path.sep in localpath:
    +785            tmp_search_path = os.path.normpath(os.getcwd() + os.path.sep + os.path.dirname(localpath))
    +786        else:
    +787            tmp_search_path = os.path.normpath(os.getcwd() + os.path.sep)
    +788        # Parse filename
    +789        filename = os.path.basename(localpath)
    +790
    +791        # Search for the file
    +792        matches = os.listdir(tmp_search_path)
    +793        # Filter the entries
    +794        matching_entries = []
    +795        for entry in matches:
    +796            if entry == filename:
    +797                matching_entries.append(entry)
    +798            elif '*' in filename:
    +799                regexp = filename.replace('.', '\\.').replace('*', '.*')
    +800                if re.match(regexp, entry):
    +801                    matching_entries.append(entry)
    +802
    +803        matching_entries = sorted(list(set(matching_entries)))
    +804
    +805        # Loop and upload
    +806        for localpath in matching_entries:
    +807            if os.path.exists(localpath):
    +808                if os.path.isfile(localpath):
    +809                    try:
    +810                        localfile = os.path.basename(localpath)
    +811                        f = LocalFileIO(
    +812                            mode="rb", 
    +813                            path=localpath, 
    +814                            debug=self.config.debug
    +815                        )
    +816                        self.smbClient.putFile(
    +817                            shareName=self.smb_share, 
    +818                            pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + localfile + ntpath.sep), 
    +819                            callback=f.read
    +820                        )
    +821                        f.close()
    +822                    except (BrokenPipeError, KeyboardInterrupt) as err:
    +823                        print("[!] Interrupted.")
    +824                        self.close_smb_session()
    +825                        self.init_smb_session()
    +826                    except Exception as err:
    +827                        print("[!] Failed to upload '%s': %s" % (localfile, err))
    +828                        if self.config.debug:
    +829                            traceback.print_exc()
    +830                else:
    +831                    # [!] The specified localpath is a directory. Use 'put -r <directory>' instead.
    +832                    pass
    +833            else:
    +834                # [!] The specified localpath does not exist.
    +835                pass
     
    @@ -3684,62 +4091,62 @@

    -
    765    def put_file_recursively(self, localpath=None):
    -766        """
    -767        Recursively uploads files from a specified local directory to the SMB share.
    -768
    -769        This method walks through the given local directory and all its subdirectories, uploading each file to the
    -770        corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,
    -771        it iterates over all files and directories within the local path, creating necessary directories on the SMB share
    -772        and uploading files. If the local path is not a directory, it prints an error message.
    -773
    -774        Args:
    -775            localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
    -776        """
    -777
    -778        if os.path.exists(localpath):
    -779            if os.path.isfile(localpath):
    -780                # Iterate over all files and directories within the local path
    -781                local_files = {}
    -782                for root, dirs, files in os.walk(localpath):
    -783                    if len(files) != 0:
    -784                        local_files[root] = files
    -785
    -786                # Iterate over the found files
    -787                for local_dir_path in sorted(local_files.keys()):
    -788                    print("[>] Putting files of '%s'" % local_dir_path)
    -789
    -790                    # Create remote directory
    -791                    remote_dir_path = local_dir_path.replace(os.path.sep, ntpath.sep)
    -792                    self.mkdir(
    -793                        path=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep)
    -794                    )
    -795
    -796                    for local_file_path in local_files[local_dir_path]:
    -797                        try:
    -798                            f = LocalFileIO(
    -799                                mode="rb", 
    -800                                path=local_dir_path + os.path.sep + local_file_path, 
    -801                                debug=self.config.debug
    -802                            )
    -803                            self.smbClient.putFile(
    -804                                shareName=self.smb_share, 
    -805                                pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep + local_file_path), 
    -806                                callback=f.read
    -807                            )
    -808                            f.close()
    -809
    -810                        except BrokenPipeError as err:
    -811                            f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err))
    -812                            f.close(remove=True)
    -813                            break
    -814                        except Exception as err:
    -815                            f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err))
    -816                            f.close(remove=True)
    -817                else:
    -818                    print("[!] The specified localpath is a file. Use 'put <file>' instead.")
    -819        else:
    -820            print("[!] The specified localpath does not exist.")
    +            
    837    def put_file_recursively(self, localpath=None):
    +838        """
    +839        Recursively uploads files from a specified local directory to the SMB share.
    +840
    +841        This method walks through the given local directory and all its subdirectories, uploading each file to the
    +842        corresponding directory structure on the SMB share. It first checks if the local path is a directory. If it is,
    +843        it iterates over all files and directories within the local path, creating necessary directories on the SMB share
    +844        and uploading files. If the local path is not a directory, it prints an error message.
    +845
    +846        Args:
    +847            localpath (str, optional): The local directory path from which files will be uploaded. Defaults to None.
    +848        """
    +849
    +850        if os.path.exists(localpath):
    +851            if os.path.isfile(localpath):
    +852                # Iterate over all files and directories within the local path
    +853                local_files = {}
    +854                for root, dirs, files in os.walk(localpath):
    +855                    if len(files) != 0:
    +856                        local_files[root] = files
    +857
    +858                # Iterate over the found files
    +859                for local_dir_path in sorted(local_files.keys()):
    +860                    print("[>] Putting files of '%s'" % local_dir_path)
    +861
    +862                    # Create remote directory
    +863                    remote_dir_path = local_dir_path.replace(os.path.sep, ntpath.sep)
    +864                    self.mkdir(
    +865                        path=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep)
    +866                    )
    +867
    +868                    for local_file_path in local_files[local_dir_path]:
    +869                        try:
    +870                            f = LocalFileIO(
    +871                                mode="rb", 
    +872                                path=local_dir_path + os.path.sep + local_file_path, 
    +873                                debug=self.config.debug
    +874                            )
    +875                            self.smbClient.putFile(
    +876                                shareName=self.smb_share, 
    +877                                pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + remote_dir_path + ntpath.sep + local_file_path), 
    +878                                callback=f.read
    +879                            )
    +880                            f.close()
    +881
    +882                        except BrokenPipeError as err:
    +883                            f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err))
    +884                            f.close(remove=True)
    +885                            break
    +886                        except Exception as err:
    +887                            f.set_error(message="[bold red]Failed uploading '%s': %s" % (f.path, err))
    +888                            f.close(remove=True)
    +889                else:
    +890                    print("[!] The specified localpath is a file. Use 'put <file>' instead.")
    +891        else:
    +892            print("[!] The specified localpath does not exist.")
     
    @@ -3767,26 +4174,26 @@

    -
    822    def rmdir(self, path=None):
    -823        """
    -824        Removes a directory from the SMB share at the specified path.
    -825
    -826        This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,
    -827        it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
    -828        the stack trace of the exception.
    -829
    -830        Args:
    -831            path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
    -832        """
    -833        try:
    -834            self.smbClient.deleteDirectory(
    -835                shareName=self.smb_share, 
    -836                pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + path), 
    -837            )
    -838        except Exception as err:
    -839            print("[!] Failed to remove directory '%s': %s" % (path, err))
    -840            if self.config.debug:
    -841                traceback.print_exc()
    +            
    894    def rmdir(self, path=None):
    +895        """
    +896        Removes a directory from the SMB share at the specified path.
    +897
    +898        This method attempts to delete a directory located at the given path on the SMB share. If the operation fails,
    +899        it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
    +900        the stack trace of the exception.
    +901
    +902        Args:
    +903            path (str, optional): The path of the directory to be removed on the SMB share. Defaults to None.
    +904        """
    +905        try:
    +906            self.smbClient.deleteDirectory(
    +907                shareName=self.smb_share, 
    +908                pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + path), 
    +909            )
    +910        except Exception as err:
    +911            print("[!] Failed to remove directory '%s': %s" % (path, err))
    +912            if self.config.debug:
    +913                traceback.print_exc()
     
    @@ -3813,26 +4220,58 @@

    -
    843    def rm(self, path=None):
    -844        """
    -845        Removes a file from the SMB share at the specified path.
    -846
    -847        This method attempts to delete a file located at the given path on the SMB share. If the operation fails,
    -848        it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
    -849        the stack trace of the exception.
    -850
    -851        Args:
    -852            path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
    -853        """
    -854        try:
    -855            self.smbClient.deleteFile(
    -856                shareName=self.smb_share, 
    -857                pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + path), 
    -858            )
    -859        except Exception as err:
    -860            print("[!] Failed to remove file '%s': %s" % (path, err))
    -861            if self.config.debug:
    -862                traceback.print_exc()
    +            
    915    def rm(self, path=None):
    +916        """
    +917        Removes a file from the SMB share at the specified path.
    +918
    +919        This method attempts to delete a file located at the given path on the SMB share. If the operation fails,
    +920        it prints an error message indicating the failure and the reason. If debugging is enabled, it also prints
    +921        the stack trace of the exception.
    +922
    +923        Args:
    +924            path (str, optional): The path of the file to be removed on the SMB share. Defaults to None.
    +925        """
    +926
    +927        # Parse path
    +928        path = path.replace('/', ntpath.sep)
    +929        if ntpath.sep in path:
    +930            tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep + ntpath.dirname(path))
    +931        else:
    +932            tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep)
    +933        # Parse filename
    +934        filename = ntpath.basename(path)
    +935
    +936        # Search for the file
    +937        matches = self.smbClient.listPath(
    +938            shareName=self.smb_share, 
    +939            path=tmp_search_path + ntpath.sep + '*'
    +940        )   
    +941
    +942        # Filter the entries
    +943        matching_entries = []
    +944        for entry in matches:
    +945            if entry.is_directory():
    +946                # Skip directories
    +947                continue
    +948            if entry.get_longname() == filename:
    +949                matching_entries.append(entry)
    +950            elif '*' in filename:
    +951                regexp = filename.replace('.', '\\.').replace('*', '.*')
    +952                if re.match(regexp, entry.get_longname()):
    +953                    matching_entries.append(entry)
    +954        
    +955        matching_entries = sorted(list(set(matching_entries)), key=lambda x: x.get_longname())
    +956
    +957        for entry in matching_entries:
    +958            try:
    +959                self.smbClient.deleteFile(
    +960                    shareName=self.smb_share, 
    +961                    pathName=ntpath.normpath(tmp_search_path + ntpath.sep + entry.get_longname()), 
    +962                )
    +963            except Exception as err:
    +964                print("[!] Failed to remove file '%s': %s" % (path, err))
    +965                if self.config.debug:
    +966                    traceback.print_exc()
     
    @@ -3859,135 +4298,135 @@

    -
    864    def tree(self, path=None):
    -865        """
    -866        Recursively lists the directory structure of the SMB share starting from the specified path.
    -867
    -868        This function prints a visual representation of the directory tree of the remote SMB share. It uses
    -869        recursion to navigate through directories and lists all files and subdirectories in each directory.
    -870        The output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
    -871
    -872        Args:
    -873            path (str, optional): The starting path on the SMB share from which to begin listing the tree.
    -874                                  Defaults to the root of the current share.
    -875        """
    -876        
    -877        def recurse_action(base_dir="", path=[], prompt=[]):
    -878            bars = ["│   ", "├── ", "└── "]
    -879
    -880            remote_smb_path = ntpath.normpath(base_dir + ntpath.sep + ntpath.sep.join(path))
    -881
    -882            entries = []
    -883            try:
    -884                entries = self.smbClient.listPath(
    -885                    shareName=self.smb_share, 
    -886                    path=remote_smb_path+'\\*'
    -887                )
    -888            except impacket.smbconnection.SessionError as err:
    -889                code, const, text = err.getErrorCode(), err.getErrorString()[0], err.getErrorString()[1]
    -890                errmsg = "Error 0x%08x (%s): %s" % (code, const, text)
    -891                if self.config.no_colors:
    -892                    print("%s%s" % (''.join(prompt+[bars[2]]), errmsg))
    -893                else:
    -894                    print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), errmsg))
    -895                return 
    -896
    -897            entries = [e for e in entries if e.get_longname() not in [".", ".."]]
    -898            entries = sorted(entries, key=lambda x:x.get_longname())
    -899
    -900            # 
    -901            if len(entries) > 1:
    -902                index = 0
    -903                for entry in entries:
    -904                    index += 1
    -905                    # This is the first entry 
    -906                    if index == 0:
    -907                        if entry.is_directory():
    -908                            if self.config.no_colors:
    -909                                print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    -910                            else:
    -911                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    -912                            recurse_action(
    -913                                base_dir=base_dir, 
    -914                                path=path+[entry.get_longname()],
    -915                                prompt=prompt+["│   "]
    -916                            )
    -917                        else:
    -918                            if self.config.no_colors:
    -919                                print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    -920                            else:
    -921                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    -922
    -923                    # This is the last entry
    -924                    elif index == len(entries):
    -925                        if entry.is_directory():
    -926                            if self.config.no_colors:
    -927                                print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    -928                            else:
    -929                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    -930                            recurse_action(
    -931                                base_dir=base_dir, 
    -932                                path=path+[entry.get_longname()],
    -933                                prompt=prompt+["    "]
    -934                            )
    -935                        else:
    -936                            if self.config.no_colors:
    -937                                print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    -938                            else:
    -939                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    -940                        
    -941                    # These are entries in the middle
    -942                    else:
    -943                        if entry.is_directory():
    -944                            if self.config.no_colors:
    -945                                print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    -946                            else:
    -947                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    -948                            recurse_action(
    -949                                base_dir=base_dir, 
    -950                                path=path+[entry.get_longname()],
    -951                                prompt=prompt+["│   "]
    -952                            )
    -953                        else:
    -954                            if self.config.no_colors:
    -955                                print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    -956                            else:
    -957                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    -958
    -959            # 
    -960            elif len(entries) == 1:
    -961                entry = entries[0]
    -962                if entry.is_directory():
    -963                    if self.config.no_colors:
    -964                        print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    -965                    else:
    -966                        print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    -967                    recurse_action(
    -968                        base_dir=base_dir, 
    -969                        path=path+[entry.get_longname()],
    -970                        prompt=prompt+["    "]
    -971                    )
    -972                else:
    -973                    if self.config.no_colors:
    -974                        print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    -975                    else:
    -976                        print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    -977
    -978        # Entrypoint
    -979        try:
    -980            if self.config.no_colors:
    -981                print("%s\\" % path)
    -982            else:
    -983                print("\x1b[1;96m%s\x1b[0m\\" % path)
    -984            recurse_action(
    -985                base_dir=self.smb_cwd, 
    -986                path=[path],
    -987                prompt=[""]
    -988            )
    -989        except (BrokenPipeError, KeyboardInterrupt) as e:
    -990            print("[!] Interrupted.")
    -991            self.close_smb_session()
    -992            self.init_smb_session()
    +            
     968    def tree(self, path=None):
    + 969        """
    + 970        Recursively lists the directory structure of the SMB share starting from the specified path.
    + 971
    + 972        This function prints a visual representation of the directory tree of the remote SMB share. It uses
    + 973        recursion to navigate through directories and lists all files and subdirectories in each directory.
    + 974        The output is color-coded and formatted to enhance readability, with directories highlighted in cyan.
    + 975
    + 976        Args:
    + 977            path (str, optional): The starting path on the SMB share from which to begin listing the tree.
    + 978                                  Defaults to the root of the current share.
    + 979        """
    + 980        
    + 981        def recurse_action(base_dir="", path=[], prompt=[]):
    + 982            bars = ["│   ", "├── ", "└── "]
    + 983
    + 984            remote_smb_path = ntpath.normpath(base_dir + ntpath.sep + ntpath.sep.join(path))
    + 985
    + 986            entries = []
    + 987            try:
    + 988                entries = self.smbClient.listPath(
    + 989                    shareName=self.smb_share, 
    + 990                    path=remote_smb_path+'\\*'
    + 991                )
    + 992            except impacket.smbconnection.SessionError as err:
    + 993                code, const, text = err.getErrorCode(), err.getErrorString()[0], err.getErrorString()[1]
    + 994                errmsg = "Error 0x%08x (%s): %s" % (code, const, text)
    + 995                if self.config.no_colors:
    + 996                    print("%s%s" % (''.join(prompt+[bars[2]]), errmsg))
    + 997                else:
    + 998                    print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), errmsg))
    + 999                return 
    +1000
    +1001            entries = [e for e in entries if e.get_longname() not in [".", ".."]]
    +1002            entries = sorted(entries, key=lambda x:x.get_longname())
    +1003
    +1004            # 
    +1005            if len(entries) > 1:
    +1006                index = 0
    +1007                for entry in entries:
    +1008                    index += 1
    +1009                    # This is the first entry 
    +1010                    if index == 0:
    +1011                        if entry.is_directory():
    +1012                            if self.config.no_colors:
    +1013                                print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1014                            else:
    +1015                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1016                            recurse_action(
    +1017                                base_dir=base_dir, 
    +1018                                path=path+[entry.get_longname()],
    +1019                                prompt=prompt+["│   "]
    +1020                            )
    +1021                        else:
    +1022                            if self.config.no_colors:
    +1023                                print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1024                            else:
    +1025                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1026
    +1027                    # This is the last entry
    +1028                    elif index == len(entries):
    +1029                        if entry.is_directory():
    +1030                            if self.config.no_colors:
    +1031                                print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1032                            else:
    +1033                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1034                            recurse_action(
    +1035                                base_dir=base_dir, 
    +1036                                path=path+[entry.get_longname()],
    +1037                                prompt=prompt+["    "]
    +1038                            )
    +1039                        else:
    +1040                            if self.config.no_colors:
    +1041                                print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1042                            else:
    +1043                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1044                        
    +1045                    # These are entries in the middle
    +1046                    else:
    +1047                        if entry.is_directory():
    +1048                            if self.config.no_colors:
    +1049                                print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1050                            else:
    +1051                                print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1052                            recurse_action(
    +1053                                base_dir=base_dir, 
    +1054                                path=path+[entry.get_longname()],
    +1055                                prompt=prompt+["│   "]
    +1056                            )
    +1057                        else:
    +1058                            if self.config.no_colors:
    +1059                                print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1060                            else:
    +1061                                print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))
    +1062
    +1063            # 
    +1064            elif len(entries) == 1:
    +1065                entry = entries[0]
    +1066                if entry.is_directory():
    +1067                    if self.config.no_colors:
    +1068                        print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1069                    else:
    +1070                        print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1071                    recurse_action(
    +1072                        base_dir=base_dir, 
    +1073                        path=path+[entry.get_longname()],
    +1074                        prompt=prompt+["    "]
    +1075                    )
    +1076                else:
    +1077                    if self.config.no_colors:
    +1078                        print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1079                    else:
    +1080                        print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))
    +1081
    +1082        # Entrypoint
    +1083        try:
    +1084            if self.config.no_colors:
    +1085                print("%s\\" % path)
    +1086            else:
    +1087                print("\x1b[1;96m%s\x1b[0m\\" % path)
    +1088            recurse_action(
    +1089                base_dir=self.smb_cwd, 
    +1090                path=[path],
    +1091                prompt=[""]
    +1092            )
    +1093        except (BrokenPipeError, KeyboardInterrupt) as e:
    +1094            print("[!] Interrupted.")
    +1095            self.close_smb_session()
    +1096            self.init_smb_session()
     
    @@ -4015,28 +4454,113 @@

    -
     994    def umount(self, local_mount_point):
    - 995        if os.path.exists(local_mount_point):
    - 996            if sys.platform.startswith('win'):
    - 997                command = f"net use {local_mount_point} /delete"
    - 998
    - 999            elif sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
    -1000                command = f"umount {local_mount_point}"
    -1001
    -1002            else:
    -1003                command = None
    -1004                print("[!] Unsupported platform for unmounting SMB share.")
    -1005        
    -1006            if command is not None:
    -1007                if self.config.debug:
    -1008                    print("[debug] Executing: %s" % command)
    -1009                os.system(command)
    -1010        else:
    -1011            print("[!] Cannot unmount a non existing path.")        
    +            
    1098    def umount(self, local_mount_point):
    +1099        """
    +1100        Unmounts the specified local mount point of the remote share.
    +1101
    +1102        This method unmounts the specified local mount point of the remote share based on the platform.
    +1103        It supports Windows, Linux, and macOS platforms for unmounting.
    +1104
    +1105        Parameters:
    +1106            local_mount_point (str): The local mount point to unmount.
    +1107
    +1108        Raises:
    +1109            None
    +1110        """
    +1111
    +1112        if os.path.exists(local_mount_point):
    +1113            if sys.platform.startswith('win'):
    +1114                command = f"net use {local_mount_point} /delete"
    +1115
    +1116            elif sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
    +1117                command = f"umount {local_mount_point}"
    +1118
    +1119            else:
    +1120                command = None
    +1121                print("[!] Unsupported platform for unmounting SMB share.")
    +1122        
    +1123            if command is not None:
    +1124                if self.config.debug:
    +1125                    print("[debug] Executing: %s" % command)
    +1126                os.system(command)
    +1127        else:
    +1128            print("[!] Cannot unmount a non existing path.")        
     
    - +

    Unmounts the specified local mount point of the remote share.

    + +

    This method unmounts the specified local mount point of the remote share based on the platform. +It supports Windows, Linux, and macOS platforms for unmounting.

    + +

    Parameters: + local_mount_point (str): The local mount point to unmount.

    + +

    Raises: + None

    +
    + + +
    +
    + +
    + + def + test_rights(self, sharename): + + + +
    + +
    1132    def test_rights(self, sharename): 
    +1133        """
    +1134        Tests the read and write access rights of the current SMB session.
    +1135
    +1136        This method checks the read and write access rights of the current SMB session by attempting to list paths and create/delete temporary directories.
    +1137        
    +1138        Returns:
    +1139            dict: A dictionary containing the read and write access rights status.
    +1140                - "readable" (bool): Indicates if the session has read access rights.
    +1141                - "writable" (bool): Indicates if the session has write access rights.
    +1142        """
    +1143
    +1144        # Restore the current share
    +1145        current_share = self.smb_share
    +1146        self.set_share(shareName=sharename)
    +1147
    +1148        access_rights = {"readable": False, "writable": False}
    +1149        try:
    +1150            self.smbClient.listPath(self.smb_share, '*', password=None)
    +1151            access_rights["readable"] = True
    +1152        except impacket.smbconnection.SessionError as e:
    +1153            access_rights["readable"] = False
    +1154
    +1155        try:
    +1156            temp_dir = ntpath.normpath("\\" + ''.join([random.choice("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ0123456759") for k in range(16)]))
    +1157            self.smbClient.createDirectory(self.smb_share, temp_dir)
    +1158            self.smbClient.deleteDirectory(self.smb_share, temp_dir)
    +1159            access_rights["writable"] = True
    +1160        except impacket.smbconnection.SessionError as e:
    +1161            access_rights["writable"] = False
    +1162
    +1163        # Restore the current share
    +1164        self.set_share(shareName=current_share)
    +1165
    +1166        return access_rights
    +
    + + +

    Tests the read and write access rights of the current SMB session.

    + +

    This method checks the read and write access rights of the current SMB session by attempting to list paths and create/delete temporary directories.

    + +

    Returns: + dict: A dictionary containing the read and write access rights status. + - "readable" (bool): Indicates if the session has read access rights. + - "writable" (bool): Indicates if the session has write access rights.

    +
    +
    @@ -4050,29 +4574,32 @@

    -
    1015    def set_share(self, shareName):
    -1016        """
    -1017        Sets the current SMB share to the specified share name.
    -1018
    -1019        This method updates the SMB session to use the specified share name. It checks if the share name is valid
    -1020        and updates the smb_share attribute of the SMBSession instance.
    -1021
    -1022        Parameters:
    -1023            shareName (str): The name of the share to set as the current SMB share.
    -1024
    -1025        Raises:
    -1026            ValueError: If the shareName is None or an empty string.
    -1027        """
    -1028
    -1029        if shareName is not None:
    -1030            self.list_shares()
    -1031            if shareName.lower() in self.available_shares.keys():
    -1032                # Doing this in order to keep the case of the share adevertised by the remote machine
    -1033                self.smb_share = self.available_shares[shareName.lower()]["name"]
    -1034                # Connects the tree
    -1035                self.smb_tree_id = self.smbClient.connectTree(self.smb_share)
    -1036            else:
    -1037                print("[!] Could not set share '%s', it does not exist remotely." % shareName)
    +            
    1170    def set_share(self, shareName):
    +1171        """
    +1172        Sets the current SMB share to the specified share name.
    +1173
    +1174        This method updates the SMB session to use the specified share name. It checks if the share name is valid
    +1175        and updates the smb_share attribute of the SMBSession instance.
    +1176
    +1177        Parameters:
    +1178            shareName (str): The name of the share to set as the current SMB share.
    +1179
    +1180        Raises:
    +1181            ValueError: If the shareName is None or an empty string.
    +1182        """
    +1183
    +1184        if shareName is not None:
    +1185            self.list_shares()
    +1186            if shareName.lower() in self.available_shares.keys():
    +1187                # Doing this in order to keep the case of the share adevertised by the remote machine
    +1188                self.smb_share = self.available_shares[shareName.lower()]["name"]
    +1189                self.smb_cwd = ""
    +1190                # Connects the tree
    +1191                self.smb_tree_id = self.smbClient.connectTree(self.smb_share)
    +1192            else:
    +1193                print("[!] Could not set share '%s', it does not exist remotely." % shareName)
    +1194        else:
    +1195            self.smb_share = None
     
    @@ -4101,48 +4628,48 @@

    -
    1039    def set_cwd(self, path=None):
    -1040        """
    -1041        Sets the current working directory on the SMB share to the specified path.
    -1042
    -1043        This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.
    -1044        If the specified path is not a directory, the cwd remains unchanged.
    -1045
    -1046        Parameters:
    -1047            path (str): The path to set as the current working directory.
    -1048
    -1049        Raises:
    -1050            ValueError: If the specified path is not a directory.
    -1051        """
    -1052
    -1053        if path is not None:
    -1054            # Set path separators to ntpath sep 
    -1055            if '/' in path:
    -1056                path = path.replace('/', ntpath.sep)
    -1057
    -1058            if path.startswith(ntpath.sep):
    -1059                # Absolute path
    -1060                path = path + ntpath.sep
    -1061            else:
    -1062                # Relative path to the CWD
    -1063                if len(self.smb_cwd) == 0:
    -1064                    path = path + ntpath.sep
    -1065                else:
    -1066                    path = self.smb_cwd + ntpath.sep + path
    -1067            
    -1068            # Path normalization
    -1069            path = ntpath.normpath(path)
    -1070            path = re.sub(r'\\+', r'\\', path)
    -1071
    -1072            if path in ["", ".", ".."]:
    -1073                self.smb_cwd = ""
    -1074            else:
    -1075                if self.path_isdir(pathFromRoot=path.strip(ntpath.sep)):
    -1076                    # Path exists on the remote 
    -1077                    self.smb_cwd = ntpath.normpath(path)
    -1078                else:
    -1079                    # Path does not exists or is not a directory on the remote 
    -1080                    print("[!] Remote directory '%s' does not exist." % path)
    +            
    1197    def set_cwd(self, path=None):
    +1198        """
    +1199        Sets the current working directory on the SMB share to the specified path.
    +1200
    +1201        This method updates the current working directory (cwd) of the SMB session to the given path if it is a valid directory.
    +1202        If the specified path is not a directory, the cwd remains unchanged.
    +1203
    +1204        Parameters:
    +1205            path (str): The path to set as the current working directory.
    +1206
    +1207        Raises:
    +1208            ValueError: If the specified path is not a directory.
    +1209        """
    +1210
    +1211        if path is not None:
    +1212            # Set path separators to ntpath sep 
    +1213            if '/' in path:
    +1214                path = path.replace('/', ntpath.sep)
    +1215
    +1216            if path.startswith(ntpath.sep):
    +1217                # Absolute path
    +1218                path = path + ntpath.sep
    +1219            else:
    +1220                # Relative path to the CWD
    +1221                if len(self.smb_cwd) == 0:
    +1222                    path = path + ntpath.sep
    +1223                else:
    +1224                    path = self.smb_cwd + ntpath.sep + path
    +1225            
    +1226            # Path normalization
    +1227            path = ntpath.normpath(path)
    +1228            path = re.sub(r'\\+', r'\\', path)
    +1229
    +1230            if path in ["", ".", ".."]:
    +1231                self.smb_cwd = ""
    +1232            else:
    +1233                if self.path_isdir(pathFromRoot=path.strip(ntpath.sep)):
    +1234                    # Path exists on the remote 
    +1235                    self.smb_cwd = ntpath.normpath(path)
    +1236                else:
    +1237                    # Path does not exists or is not a directory on the remote 
    +1238                    print("[!] Remote directory '%s' does not exist." % path)
     
    diff --git a/smbclientng/core/InteractiveShell.py b/smbclientng/core/InteractiveShell.py index 9a0e275..c691b2a 100644 --- a/smbclientng/core/InteractiveShell.py +++ b/smbclientng/core/InteractiveShell.py @@ -723,7 +723,9 @@ def command_rm(self, arguments, command): # SMB share needed : Yes path = ' '.join(arguments) - if self.smbSession.path_exists(path): + if '*' in path: + self.smbSession.rm(path=path) + elif self.smbSession.path_exists(path): if self.smbSession.path_isfile(path): try: self.smbSession.rm(path=path) diff --git a/smbclientng/core/SMBSession.py b/smbclientng/core/SMBSession.py index a95680b..9378d70 100644 --- a/smbclientng/core/SMBSession.py +++ b/smbclientng/core/SMBSession.py @@ -271,6 +271,9 @@ def get_file(self, path=None, keepRemotePath=False): # Filter the entries matching_entries = [] for entry in matches: + if entry.is_directory(): + # Skip directories + continue if entry.get_longname() == filename: matching_entries.append(entry) elif '*' in filename: @@ -278,7 +281,7 @@ def get_file(self, path=None, keepRemotePath=False): if re.match(regexp, entry.get_longname()): matching_entries.append(entry) - matching_entries = sorted(list(set(matching_entries))) + matching_entries = sorted(list(set(matching_entries)), key=lambda x: x.get_longname()) for entry in matching_entries: if entry.is_directory(): @@ -919,15 +922,47 @@ def rm(self, path=None): Args: path (str, optional): The path of the file to be removed on the SMB share. Defaults to None. """ - try: - self.smbClient.deleteFile( - shareName=self.smb_share, - pathName=ntpath.normpath(self.smb_cwd + ntpath.sep + path), - ) - except Exception as err: - print("[!] Failed to remove file '%s': %s" % (path, err)) - if self.config.debug: - traceback.print_exc() + + # Parse path + path = path.replace('/', ntpath.sep) + if ntpath.sep in path: + tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep + ntpath.dirname(path)) + else: + tmp_search_path = ntpath.normpath(self.smb_cwd + ntpath.sep) + # Parse filename + filename = ntpath.basename(path) + + # Search for the file + matches = self.smbClient.listPath( + shareName=self.smb_share, + path=tmp_search_path + ntpath.sep + '*' + ) + + # Filter the entries + matching_entries = [] + for entry in matches: + if entry.is_directory(): + # Skip directories + continue + if entry.get_longname() == filename: + matching_entries.append(entry) + elif '*' in filename: + regexp = filename.replace('.', '\\.').replace('*', '.*') + if re.match(regexp, entry.get_longname()): + matching_entries.append(entry) + + matching_entries = sorted(list(set(matching_entries)), key=lambda x: x.get_longname()) + + for entry in matching_entries: + try: + self.smbClient.deleteFile( + shareName=self.smb_share, + pathName=ntpath.normpath(tmp_search_path + ntpath.sep + entry.get_longname()), + ) + except Exception as err: + print("[!] Failed to remove file '%s': %s" % (path, err)) + if self.config.debug: + traceback.print_exc() def tree(self, path=None): """