smbclientng.core.utils
1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# File name : utils.py 4# Author : Podalirius (@podalirius_) 5# Date created : 23 may 2024 6 7 8import datetime 9import fnmatch 10import ntpath 11import os 12import re 13import socket 14import stat 15 16 17def parse_lm_nt_hashes(lm_nt_hashes_string): 18 """ 19 Parse the input string containing LM and NT hash values and return them separately. 20 21 This function takes a string containing LM and NT hash values, typically separated by a colon (:). 22 It returns the LM and NT hash values as separate strings. If only one hash value is provided, it is 23 assumed to be the NT hash and the LM hash is set to its default value. If no valid hash values are 24 found, both return values are empty strings. 25 26 Args: 27 lm_nt_hashes_string (str): A string containing LM and NT hash values separated by a colon. 28 29 Returns: 30 tuple: A tuple containing two strings (lm_hash_value, nt_hash_value). 31 - lm_hash_value: The LM hash value or its default if not provided. 32 - nt_hash_value: The NT hash value or its default if not provided. 33 34 Extracted from p0dalirius/sectools library 35 Src: https://github.com/p0dalirius/sectools/blob/7bb3f5cb7815ad4d4845713c8739e2e2b0ea4e75/sectools/windows/crypto.py#L11-L24 36 """ 37 38 lm_hash_value, nt_hash_value = "", "" 39 if lm_nt_hashes_string is not None: 40 matched = re.match("([0-9a-f]{32})?(:)?([0-9a-f]{32})?", lm_nt_hashes_string.strip().lower()) 41 m_lm_hash, m_sep, m_nt_hash = matched.groups() 42 if m_lm_hash is None and m_sep is None and m_nt_hash is None: 43 lm_hash_value, nt_hash_value = "", "" 44 elif m_lm_hash is None and m_nt_hash is not None: 45 lm_hash_value = "aad3b435b51404eeaad3b435b51404ee" 46 nt_hash_value = m_nt_hash 47 elif m_lm_hash is not None and m_nt_hash is None: 48 lm_hash_value = m_lm_hash 49 nt_hash_value = "31d6cfe0d16ae931b73c59d7e0c089c0" 50 return lm_hash_value, nt_hash_value 51 52 53def b_filesize(l): 54 """ 55 Convert a file size from bytes to a more readable format using the largest appropriate unit. 56 57 This function takes an integer representing a file size in bytes and converts it to a human-readable 58 string using the largest appropriate unit from bytes (B) to petabytes (PB). The result is rounded to 59 two decimal places. 60 61 Args: 62 l (int): The file size in bytes. 63 64 Returns: 65 str: A string representing the file size in a more readable format, including the appropriate unit. 66 """ 67 68 units = ['B','kB','MB','GB','TB','PB'] 69 for k in range(len(units)): 70 if l < (1024**(k+1)): 71 break 72 return "%4.2f %s" % (round(l/(1024**(k)),2), units[k]) 73 74 75def unix_permissions(entryname): 76 """ 77 Generate a string representing the Unix-style permissions for a given file or directory. 78 79 This function uses the os.lstat() method to retrieve the status of the specified file or directory, 80 then constructs a string that represents the Unix-style permissions based on the mode of the file. 81 82 Args: 83 entryname (str): The path to the file or directory for which permissions are being determined. 84 85 Returns: 86 str: A string of length 10 representing the Unix-style permissions (e.g., '-rwxr-xr--'). 87 The first character is either 'd' (directory), '-' (not a directory), followed by 88 three groups of 'r', 'w', 'x' (read, write, execute permissions) for owner, group, 89 and others respectively. 90 """ 91 92 mode = os.lstat(entryname).st_mode 93 permissions = [] 94 95 permissions.append('d' if stat.S_ISDIR(mode) else '-') 96 97 permissions.append('r' if mode & stat.S_IRUSR else '-') 98 permissions.append('w' if mode & stat.S_IWUSR else '-') 99 permissions.append('x' if mode & stat.S_IXUSR else '-') 100 101 permissions.append('r' if mode & stat.S_IRGRP else '-') 102 permissions.append('w' if mode & stat.S_IWGRP else '-') 103 permissions.append('x' if mode & stat.S_IXGRP else '-') 104 105 permissions.append('r' if mode & stat.S_IROTH else '-') 106 permissions.append('w' if mode & stat.S_IWOTH else '-') 107 permissions.append('x' if mode & stat.S_IXOTH else '-') 108 109 return ''.join(permissions) 110 111 112def STYPE_MASK(stype_value): 113 """ 114 Extracts the share type flags from a given share type value. 115 116 This function uses bitwise operations to determine which share type flags are set in the provided `stype_value`. 117 It checks against known share type flags and returns a list of the flags that are set. 118 119 Parameters: 120 stype_value (int): The share type value to analyze, typically obtained from SMB share properties. 121 122 Returns: 123 list: A list of strings, where each string represents a share type flag that is set in the input value. 124 """ 125 126 known_flags = { 127 ## One of the following values may be specified. You can isolate these values by using the STYPE_MASK value. 128 # Disk drive. 129 "STYPE_DISKTREE": 0x0, 130 131 # Print queue. 132 "STYPE_PRINTQ": 0x1, 133 134 # Communication device. 135 "STYPE_DEVICE": 0x2, 136 137 # Interprocess communication (IPC). 138 "STYPE_IPC": 0x3, 139 140 ## In addition, one or both of the following values may be specified. 141 # Special share reserved for interprocess communication (IPC$) or remote administration of the server (ADMIN$). 142 # Can also refer to administrative shares such as C$, D$, E$, and so forth. For more information, see Network Share Functions. 143 "STYPE_SPECIAL": 0x80000000, 144 145 # A temporary share. 146 "STYPE_TEMPORARY": 0x40000000 147 } 148 flags = [] 149 if (stype_value & 0b11) == known_flags["STYPE_DISKTREE"]: 150 flags.append("STYPE_DISKTREE") 151 elif (stype_value & 0b11) == known_flags["STYPE_PRINTQ"]: 152 flags.append("STYPE_PRINTQ") 153 elif (stype_value & 0b11) == known_flags["STYPE_DEVICE"]: 154 flags.append("STYPE_DEVICE") 155 elif (stype_value & 0b11) == known_flags["STYPE_IPC"]: 156 flags.append("STYPE_IPC") 157 if (stype_value & known_flags["STYPE_SPECIAL"]) == known_flags["STYPE_SPECIAL"]: 158 flags.append("STYPE_SPECIAL") 159 if (stype_value & known_flags["STYPE_TEMPORARY"]) == known_flags["STYPE_TEMPORARY"]: 160 flags.append("STYPE_TEMPORARY") 161 return flags 162 163 164def windows_ls_entry(entry, config, pathToPrint=None): 165 """ 166 This function generates a metadata string based on the attributes of the provided entry object. 167 168 Parameters: 169 entry (object): An object representing a file or directory entry. 170 171 Returns: 172 str: A string representing the metadata of the entry, including attributes like directory, archive, compressed, hidden, normal, readonly, system, and temporary. 173 """ 174 175 if pathToPrint is not None: 176 pathToPrint = pathToPrint + ntpath.sep + entry.get_longname() 177 else: 178 pathToPrint = entry.get_longname() 179 180 meta_string = "" 181 meta_string += ("d" if entry.is_directory() else "-") 182 meta_string += ("a" if entry.is_archive() else "-") 183 meta_string += ("c" if entry.is_compressed() else "-") 184 meta_string += ("h" if entry.is_hidden() else "-") 185 meta_string += ("n" if entry.is_normal() else "-") 186 meta_string += ("r" if entry.is_readonly() else "-") 187 meta_string += ("s" if entry.is_system() else "-") 188 meta_string += ("t" if entry.is_temporary() else "-") 189 190 size_str = b_filesize(entry.get_filesize()) 191 192 date_str = datetime.datetime.fromtimestamp(entry.get_atime_epoch()).strftime("%Y-%m-%d %H:%M") 193 194 if entry.is_directory(): 195 if config.no_colors: 196 print("%s %10s %s %s\\" % (meta_string, size_str, date_str, pathToPrint)) 197 else: 198 print("%s %10s %s \x1b[1;96m%s\x1b[0m\\" % (meta_string, size_str, date_str, pathToPrint)) 199 else: 200 if config.no_colors: 201 print("%s %10s %s %s" % (meta_string, size_str, date_str, pathToPrint)) 202 else: 203 print("%s %10s %s \x1b[1m%s\x1b[0m" % (meta_string, size_str, date_str, pathToPrint)) 204 205 206def local_tree(path, config): 207 """ 208 This function recursively lists the contents of a directory in a tree-like format. 209 210 Parameters: 211 path (str): The path to the directory to list. 212 config (object): Configuration settings which may affect the output, such as whether to use colors. 213 214 Returns: 215 None: This function does not return anything but prints the directory tree to the console. 216 """ 217 218 def recurse_action(base_dir="", path=[], prompt=[]): 219 bars = ["│ ", "├── ", "└── "] 220 221 local_path = os.path.normpath(base_dir + os.path.sep + os.path.sep.join(path) + os.path.sep) 222 223 entries = [] 224 try: 225 entries = os.listdir(local_path) 226 except Exception as err: 227 if config.no_colors: 228 print("%s%s" % (''.join(prompt+[bars[2]]), err)) 229 else: 230 print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), err)) 231 return 232 233 entries = sorted(entries) 234 235 # 236 if len(entries) > 1: 237 index = 0 238 for entry in entries: 239 index += 1 240 # This is the first entry 241 if index == 0: 242 if os.path.isdir(local_path + os.path.sep + entry): 243 if config.no_colors: 244 print("%s%s%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 245 else: 246 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 247 recurse_action( 248 base_dir=base_dir, 249 path=path+[entry], 250 prompt=prompt+["│ "] 251 ) 252 else: 253 if config.no_colors: 254 print("%s%s" % (''.join(prompt+[bars[1]]), entry)) 255 else: 256 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry)) 257 258 # This is the last entry 259 elif index == len(entries): 260 if os.path.isdir(local_path + os.path.sep + entry): 261 if config.no_colors: 262 print("%s%s%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 263 else: 264 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 265 recurse_action( 266 base_dir=base_dir, 267 path=path+[entry], 268 prompt=prompt+[" "] 269 ) 270 else: 271 if config.no_colors: 272 print("%s%s" % (''.join(prompt+[bars[2]]), entry)) 273 else: 274 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry)) 275 276 # These are entries in the middle 277 else: 278 if os.path.isdir(local_path + os.path.sep + entry): 279 if config.no_colors: 280 print("%s%s%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 281 else: 282 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 283 recurse_action( 284 base_dir=base_dir, 285 path=path+[entry], 286 prompt=prompt+["│ "] 287 ) 288 else: 289 if config.no_colors: 290 print("%s%s" % (''.join(prompt+[bars[1]]), entry)) 291 else: 292 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry)) 293 294 # 295 elif len(entries) == 1: 296 entry = entries[0] 297 if os.path.isdir(local_path + os.path.sep + entry): 298 if config.no_colors: 299 print("%s%s%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 300 else: 301 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 302 recurse_action( 303 base_dir=base_dir, 304 path=path+[entry], 305 prompt=prompt+[" "] 306 ) 307 else: 308 if config.no_colors: 309 print("%s%s" % (''.join(prompt+[bars[2]]), entry)) 310 else: 311 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry)) 312 313 # Entrypoint 314 try: 315 if config.no_colors: 316 print("%s%s" % (path, os.path.sep)) 317 else: 318 print("\x1b[1;96m%s\x1b[0m%s" % (path, os.path.sep)) 319 recurse_action( 320 base_dir=os.getcwd(), 321 path=[path], 322 prompt=[""] 323 ) 324 except (BrokenPipeError, KeyboardInterrupt) as e: 325 print("[!] Interrupted.") 326 327 328def resolve_local_files(arguments): 329 """ 330 Resolves local file paths based on the provided arguments. 331 332 This function takes a list of arguments, which can include wildcard patterns, and resolves them to actual file paths. 333 If an argument contains a wildcard ('*'), it attempts to match files in the specified directory against the pattern. 334 If the argument does not contain a wildcard, it is added to the list of resolved files as is. 335 336 Args: 337 arguments (list): A list of file path arguments, which may include wildcard patterns. 338 339 Returns: 340 list: A list of resolved file paths that match the provided arguments. 341 """ 342 343 resolved_files = [] 344 for arg in arguments: 345 if '*' in arg: 346 try: 347 path = os.path.dirname(arg) or '.' 348 pattern = os.path.basename(arg) 349 for entry in os.listdir(path): 350 if fnmatch.fnmatch(entry, pattern): 351 resolved_files.append(os.path.join(path, entry)) 352 except FileNotFoundError as err: 353 pass 354 else: 355 resolved_files.append(arg) 356 resolved_files = sorted(list(set(resolved_files))) 357 return resolved_files 358 359 360def resolve_remote_files(smbSession, arguments): 361 """ 362 Resolves remote file paths based on the provided arguments using an SMB session. 363 364 This function takes a list of arguments, which can include wildcard patterns, and resolves them to actual remote file paths. 365 If an argument contains a wildcard ('*'), it attempts to match files in the specified remote directory against the pattern. 366 If the argument does not contain a wildcard, it is added to the list of resolved files as is. 367 368 Args: 369 smbsession (SMBSession): The SMB session through which to access the files. 370 arguments (list): A list of file path arguments, which may include wildcard patterns. 371 372 Returns: 373 list: A list of resolved remote file paths that match the provided arguments. 374 """ 375 376 resolved_files = [] 377 for arg in arguments: 378 if '*' in arg: 379 if arg == '*': 380 path = smbSession.smb_cwd 381 elif arg.startswith(ntpath.sep): 382 path = ntpath.dirname(arg) 383 else: 384 path = ntpath.normpath(smbSession.smb_cwd + ntpath.sep + ntpath.dirname(arg)) 385 386 try: 387 contents = smbSession.smbClient.listPath( 388 shareName=smbSession.smb_share, 389 path=path + ntpath.sep + '*' 390 ) 391 contents = [e for e in contents if e.get_longname() not in ['.', '..']] 392 393 for entry in contents: 394 if fnmatch.fnmatch(entry.get_longname(), ntpath.basename(arg)): 395 resolved_files.append(ntpath.join(path, entry.get_longname())) 396 397 except Exception as err: 398 pass 399 else: 400 resolved_files.append(arg) 401 resolved_files = sorted(list(set(resolved_files))) 402 return resolved_files 403 404 405def is_port_open(target, port) -> bool: 406 """ 407 Check if a specific port on a target host is open. 408 409 This function attempts to establish a TCP connection to the specified port on the target host. 410 If the connection is successful, it indicates that the port is open. If the connection fails, 411 it indicates that the port is closed or the host is unreachable. 412 413 Args: 414 target (str): The hostname or IP address of the target host. 415 port (int): The port number to check. 416 417 Returns: 418 bool: True if the port is open, False otherwise. 419 """ 420 421 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 422 s.settimeout(0.1) 423 # Non-existant domains cause a lot of errors, added error handling 424 try: 425 return s.connect_ex((target, port)) == 0 426 except Exception as e: 427 return False
18def parse_lm_nt_hashes(lm_nt_hashes_string): 19 """ 20 Parse the input string containing LM and NT hash values and return them separately. 21 22 This function takes a string containing LM and NT hash values, typically separated by a colon (:). 23 It returns the LM and NT hash values as separate strings. If only one hash value is provided, it is 24 assumed to be the NT hash and the LM hash is set to its default value. If no valid hash values are 25 found, both return values are empty strings. 26 27 Args: 28 lm_nt_hashes_string (str): A string containing LM and NT hash values separated by a colon. 29 30 Returns: 31 tuple: A tuple containing two strings (lm_hash_value, nt_hash_value). 32 - lm_hash_value: The LM hash value or its default if not provided. 33 - nt_hash_value: The NT hash value or its default if not provided. 34 35 Extracted from p0dalirius/sectools library 36 Src: https://github.com/p0dalirius/sectools/blob/7bb3f5cb7815ad4d4845713c8739e2e2b0ea4e75/sectools/windows/crypto.py#L11-L24 37 """ 38 39 lm_hash_value, nt_hash_value = "", "" 40 if lm_nt_hashes_string is not None: 41 matched = re.match("([0-9a-f]{32})?(:)?([0-9a-f]{32})?", lm_nt_hashes_string.strip().lower()) 42 m_lm_hash, m_sep, m_nt_hash = matched.groups() 43 if m_lm_hash is None and m_sep is None and m_nt_hash is None: 44 lm_hash_value, nt_hash_value = "", "" 45 elif m_lm_hash is None and m_nt_hash is not None: 46 lm_hash_value = "aad3b435b51404eeaad3b435b51404ee" 47 nt_hash_value = m_nt_hash 48 elif m_lm_hash is not None and m_nt_hash is None: 49 lm_hash_value = m_lm_hash 50 nt_hash_value = "31d6cfe0d16ae931b73c59d7e0c089c0" 51 return lm_hash_value, nt_hash_value
Parse the input string containing LM and NT hash values and return them separately.
This function takes a string containing LM and NT hash values, typically separated by a colon (:). It returns the LM and NT hash values as separate strings. If only one hash value is provided, it is assumed to be the NT hash and the LM hash is set to its default value. If no valid hash values are found, both return values are empty strings.
Args: lm_nt_hashes_string (str): A string containing LM and NT hash values separated by a colon.
Returns: tuple: A tuple containing two strings (lm_hash_value, nt_hash_value). - lm_hash_value: The LM hash value or its default if not provided. - nt_hash_value: The NT hash value or its default if not provided.
Extracted from p0dalirius/sectools library Src: https://github.com/p0dalirius/sectools/blob/7bb3f5cb7815ad4d4845713c8739e2e2b0ea4e75/sectools/windows/crypto.py#L11-L24
54def b_filesize(l): 55 """ 56 Convert a file size from bytes to a more readable format using the largest appropriate unit. 57 58 This function takes an integer representing a file size in bytes and converts it to a human-readable 59 string using the largest appropriate unit from bytes (B) to petabytes (PB). The result is rounded to 60 two decimal places. 61 62 Args: 63 l (int): The file size in bytes. 64 65 Returns: 66 str: A string representing the file size in a more readable format, including the appropriate unit. 67 """ 68 69 units = ['B','kB','MB','GB','TB','PB'] 70 for k in range(len(units)): 71 if l < (1024**(k+1)): 72 break 73 return "%4.2f %s" % (round(l/(1024**(k)),2), units[k])
Convert a file size from bytes to a more readable format using the largest appropriate unit.
This function takes an integer representing a file size in bytes and converts it to a human-readable string using the largest appropriate unit from bytes (B) to petabytes (PB). The result is rounded to two decimal places.
Args: l (int): The file size in bytes.
Returns: str: A string representing the file size in a more readable format, including the appropriate unit.
76def unix_permissions(entryname): 77 """ 78 Generate a string representing the Unix-style permissions for a given file or directory. 79 80 This function uses the os.lstat() method to retrieve the status of the specified file or directory, 81 then constructs a string that represents the Unix-style permissions based on the mode of the file. 82 83 Args: 84 entryname (str): The path to the file or directory for which permissions are being determined. 85 86 Returns: 87 str: A string of length 10 representing the Unix-style permissions (e.g., '-rwxr-xr--'). 88 The first character is either 'd' (directory), '-' (not a directory), followed by 89 three groups of 'r', 'w', 'x' (read, write, execute permissions) for owner, group, 90 and others respectively. 91 """ 92 93 mode = os.lstat(entryname).st_mode 94 permissions = [] 95 96 permissions.append('d' if stat.S_ISDIR(mode) else '-') 97 98 permissions.append('r' if mode & stat.S_IRUSR else '-') 99 permissions.append('w' if mode & stat.S_IWUSR else '-') 100 permissions.append('x' if mode & stat.S_IXUSR else '-') 101 102 permissions.append('r' if mode & stat.S_IRGRP else '-') 103 permissions.append('w' if mode & stat.S_IWGRP else '-') 104 permissions.append('x' if mode & stat.S_IXGRP else '-') 105 106 permissions.append('r' if mode & stat.S_IROTH else '-') 107 permissions.append('w' if mode & stat.S_IWOTH else '-') 108 permissions.append('x' if mode & stat.S_IXOTH else '-') 109 110 return ''.join(permissions)
Generate a string representing the Unix-style permissions for a given file or directory.
This function uses the os.lstat() method to retrieve the status of the specified file or directory, then constructs a string that represents the Unix-style permissions based on the mode of the file.
Args: entryname (str): The path to the file or directory for which permissions are being determined.
Returns: str: A string of length 10 representing the Unix-style permissions (e.g., '-rwxr-xr--'). The first character is either 'd' (directory), '-' (not a directory), followed by three groups of 'r', 'w', 'x' (read, write, execute permissions) for owner, group, and others respectively.
113def STYPE_MASK(stype_value): 114 """ 115 Extracts the share type flags from a given share type value. 116 117 This function uses bitwise operations to determine which share type flags are set in the provided `stype_value`. 118 It checks against known share type flags and returns a list of the flags that are set. 119 120 Parameters: 121 stype_value (int): The share type value to analyze, typically obtained from SMB share properties. 122 123 Returns: 124 list: A list of strings, where each string represents a share type flag that is set in the input value. 125 """ 126 127 known_flags = { 128 ## One of the following values may be specified. You can isolate these values by using the STYPE_MASK value. 129 # Disk drive. 130 "STYPE_DISKTREE": 0x0, 131 132 # Print queue. 133 "STYPE_PRINTQ": 0x1, 134 135 # Communication device. 136 "STYPE_DEVICE": 0x2, 137 138 # Interprocess communication (IPC). 139 "STYPE_IPC": 0x3, 140 141 ## In addition, one or both of the following values may be specified. 142 # Special share reserved for interprocess communication (IPC$) or remote administration of the server (ADMIN$). 143 # Can also refer to administrative shares such as C$, D$, E$, and so forth. For more information, see Network Share Functions. 144 "STYPE_SPECIAL": 0x80000000, 145 146 # A temporary share. 147 "STYPE_TEMPORARY": 0x40000000 148 } 149 flags = [] 150 if (stype_value & 0b11) == known_flags["STYPE_DISKTREE"]: 151 flags.append("STYPE_DISKTREE") 152 elif (stype_value & 0b11) == known_flags["STYPE_PRINTQ"]: 153 flags.append("STYPE_PRINTQ") 154 elif (stype_value & 0b11) == known_flags["STYPE_DEVICE"]: 155 flags.append("STYPE_DEVICE") 156 elif (stype_value & 0b11) == known_flags["STYPE_IPC"]: 157 flags.append("STYPE_IPC") 158 if (stype_value & known_flags["STYPE_SPECIAL"]) == known_flags["STYPE_SPECIAL"]: 159 flags.append("STYPE_SPECIAL") 160 if (stype_value & known_flags["STYPE_TEMPORARY"]) == known_flags["STYPE_TEMPORARY"]: 161 flags.append("STYPE_TEMPORARY") 162 return flags
Extracts the share type flags from a given share type value.
This function uses bitwise operations to determine which share type flags are set in the provided stype_value.
It checks against known share type flags and returns a list of the flags that are set.
Parameters: stype_value (int): The share type value to analyze, typically obtained from SMB share properties.
Returns: list: A list of strings, where each string represents a share type flag that is set in the input value.
165def windows_ls_entry(entry, config, pathToPrint=None): 166 """ 167 This function generates a metadata string based on the attributes of the provided entry object. 168 169 Parameters: 170 entry (object): An object representing a file or directory entry. 171 172 Returns: 173 str: A string representing the metadata of the entry, including attributes like directory, archive, compressed, hidden, normal, readonly, system, and temporary. 174 """ 175 176 if pathToPrint is not None: 177 pathToPrint = pathToPrint + ntpath.sep + entry.get_longname() 178 else: 179 pathToPrint = entry.get_longname() 180 181 meta_string = "" 182 meta_string += ("d" if entry.is_directory() else "-") 183 meta_string += ("a" if entry.is_archive() else "-") 184 meta_string += ("c" if entry.is_compressed() else "-") 185 meta_string += ("h" if entry.is_hidden() else "-") 186 meta_string += ("n" if entry.is_normal() else "-") 187 meta_string += ("r" if entry.is_readonly() else "-") 188 meta_string += ("s" if entry.is_system() else "-") 189 meta_string += ("t" if entry.is_temporary() else "-") 190 191 size_str = b_filesize(entry.get_filesize()) 192 193 date_str = datetime.datetime.fromtimestamp(entry.get_atime_epoch()).strftime("%Y-%m-%d %H:%M") 194 195 if entry.is_directory(): 196 if config.no_colors: 197 print("%s %10s %s %s\\" % (meta_string, size_str, date_str, pathToPrint)) 198 else: 199 print("%s %10s %s \x1b[1;96m%s\x1b[0m\\" % (meta_string, size_str, date_str, pathToPrint)) 200 else: 201 if config.no_colors: 202 print("%s %10s %s %s" % (meta_string, size_str, date_str, pathToPrint)) 203 else: 204 print("%s %10s %s \x1b[1m%s\x1b[0m" % (meta_string, size_str, date_str, pathToPrint))
This function generates a metadata string based on the attributes of the provided entry object.
Parameters: entry (object): An object representing a file or directory entry.
Returns: str: A string representing the metadata of the entry, including attributes like directory, archive, compressed, hidden, normal, readonly, system, and temporary.
207def local_tree(path, config): 208 """ 209 This function recursively lists the contents of a directory in a tree-like format. 210 211 Parameters: 212 path (str): The path to the directory to list. 213 config (object): Configuration settings which may affect the output, such as whether to use colors. 214 215 Returns: 216 None: This function does not return anything but prints the directory tree to the console. 217 """ 218 219 def recurse_action(base_dir="", path=[], prompt=[]): 220 bars = ["│ ", "├── ", "└── "] 221 222 local_path = os.path.normpath(base_dir + os.path.sep + os.path.sep.join(path) + os.path.sep) 223 224 entries = [] 225 try: 226 entries = os.listdir(local_path) 227 except Exception as err: 228 if config.no_colors: 229 print("%s%s" % (''.join(prompt+[bars[2]]), err)) 230 else: 231 print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), err)) 232 return 233 234 entries = sorted(entries) 235 236 # 237 if len(entries) > 1: 238 index = 0 239 for entry in entries: 240 index += 1 241 # This is the first entry 242 if index == 0: 243 if os.path.isdir(local_path + os.path.sep + entry): 244 if config.no_colors: 245 print("%s%s%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 246 else: 247 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 248 recurse_action( 249 base_dir=base_dir, 250 path=path+[entry], 251 prompt=prompt+["│ "] 252 ) 253 else: 254 if config.no_colors: 255 print("%s%s" % (''.join(prompt+[bars[1]]), entry)) 256 else: 257 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry)) 258 259 # This is the last entry 260 elif index == len(entries): 261 if os.path.isdir(local_path + os.path.sep + entry): 262 if config.no_colors: 263 print("%s%s%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 264 else: 265 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 266 recurse_action( 267 base_dir=base_dir, 268 path=path+[entry], 269 prompt=prompt+[" "] 270 ) 271 else: 272 if config.no_colors: 273 print("%s%s" % (''.join(prompt+[bars[2]]), entry)) 274 else: 275 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry)) 276 277 # These are entries in the middle 278 else: 279 if os.path.isdir(local_path + os.path.sep + entry): 280 if config.no_colors: 281 print("%s%s%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 282 else: 283 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 284 recurse_action( 285 base_dir=base_dir, 286 path=path+[entry], 287 prompt=prompt+["│ "] 288 ) 289 else: 290 if config.no_colors: 291 print("%s%s" % (''.join(prompt+[bars[1]]), entry)) 292 else: 293 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry)) 294 295 # 296 elif len(entries) == 1: 297 entry = entries[0] 298 if os.path.isdir(local_path + os.path.sep + entry): 299 if config.no_colors: 300 print("%s%s%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 301 else: 302 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 303 recurse_action( 304 base_dir=base_dir, 305 path=path+[entry], 306 prompt=prompt+[" "] 307 ) 308 else: 309 if config.no_colors: 310 print("%s%s" % (''.join(prompt+[bars[2]]), entry)) 311 else: 312 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry)) 313 314 # Entrypoint 315 try: 316 if config.no_colors: 317 print("%s%s" % (path, os.path.sep)) 318 else: 319 print("\x1b[1;96m%s\x1b[0m%s" % (path, os.path.sep)) 320 recurse_action( 321 base_dir=os.getcwd(), 322 path=[path], 323 prompt=[""] 324 ) 325 except (BrokenPipeError, KeyboardInterrupt) as e: 326 print("[!] Interrupted.")
This function recursively lists the contents of a directory in a tree-like format.
Parameters: path (str): The path to the directory to list. config (object): Configuration settings which may affect the output, such as whether to use colors.
Returns: None: This function does not return anything but prints the directory tree to the console.
329def resolve_local_files(arguments): 330 """ 331 Resolves local file paths based on the provided arguments. 332 333 This function takes a list of arguments, which can include wildcard patterns, and resolves them to actual file paths. 334 If an argument contains a wildcard ('*'), it attempts to match files in the specified directory against the pattern. 335 If the argument does not contain a wildcard, it is added to the list of resolved files as is. 336 337 Args: 338 arguments (list): A list of file path arguments, which may include wildcard patterns. 339 340 Returns: 341 list: A list of resolved file paths that match the provided arguments. 342 """ 343 344 resolved_files = [] 345 for arg in arguments: 346 if '*' in arg: 347 try: 348 path = os.path.dirname(arg) or '.' 349 pattern = os.path.basename(arg) 350 for entry in os.listdir(path): 351 if fnmatch.fnmatch(entry, pattern): 352 resolved_files.append(os.path.join(path, entry)) 353 except FileNotFoundError as err: 354 pass 355 else: 356 resolved_files.append(arg) 357 resolved_files = sorted(list(set(resolved_files))) 358 return resolved_files
Resolves local file paths based on the provided arguments.
This function takes a list of arguments, which can include wildcard patterns, and resolves them to actual file paths. If an argument contains a wildcard ('*'), it attempts to match files in the specified directory against the pattern. If the argument does not contain a wildcard, it is added to the list of resolved files as is.
Args: arguments (list): A list of file path arguments, which may include wildcard patterns.
Returns: list: A list of resolved file paths that match the provided arguments.
361def resolve_remote_files(smbSession, arguments): 362 """ 363 Resolves remote file paths based on the provided arguments using an SMB session. 364 365 This function takes a list of arguments, which can include wildcard patterns, and resolves them to actual remote file paths. 366 If an argument contains a wildcard ('*'), it attempts to match files in the specified remote directory against the pattern. 367 If the argument does not contain a wildcard, it is added to the list of resolved files as is. 368 369 Args: 370 smbsession (SMBSession): The SMB session through which to access the files. 371 arguments (list): A list of file path arguments, which may include wildcard patterns. 372 373 Returns: 374 list: A list of resolved remote file paths that match the provided arguments. 375 """ 376 377 resolved_files = [] 378 for arg in arguments: 379 if '*' in arg: 380 if arg == '*': 381 path = smbSession.smb_cwd 382 elif arg.startswith(ntpath.sep): 383 path = ntpath.dirname(arg) 384 else: 385 path = ntpath.normpath(smbSession.smb_cwd + ntpath.sep + ntpath.dirname(arg)) 386 387 try: 388 contents = smbSession.smbClient.listPath( 389 shareName=smbSession.smb_share, 390 path=path + ntpath.sep + '*' 391 ) 392 contents = [e for e in contents if e.get_longname() not in ['.', '..']] 393 394 for entry in contents: 395 if fnmatch.fnmatch(entry.get_longname(), ntpath.basename(arg)): 396 resolved_files.append(ntpath.join(path, entry.get_longname())) 397 398 except Exception as err: 399 pass 400 else: 401 resolved_files.append(arg) 402 resolved_files = sorted(list(set(resolved_files))) 403 return resolved_files
Resolves remote file paths based on the provided arguments using an SMB session.
This function takes a list of arguments, which can include wildcard patterns, and resolves them to actual remote file paths. If an argument contains a wildcard ('*'), it attempts to match files in the specified remote directory against the pattern. If the argument does not contain a wildcard, it is added to the list of resolved files as is.
Args: smbsession (SMBSession): The SMB session through which to access the files. arguments (list): A list of file path arguments, which may include wildcard patterns.
Returns: list: A list of resolved remote file paths that match the provided arguments.
406def is_port_open(target, port) -> bool: 407 """ 408 Check if a specific port on a target host is open. 409 410 This function attempts to establish a TCP connection to the specified port on the target host. 411 If the connection is successful, it indicates that the port is open. If the connection fails, 412 it indicates that the port is closed or the host is unreachable. 413 414 Args: 415 target (str): The hostname or IP address of the target host. 416 port (int): The port number to check. 417 418 Returns: 419 bool: True if the port is open, False otherwise. 420 """ 421 422 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 423 s.settimeout(0.1) 424 # Non-existant domains cause a lot of errors, added error handling 425 try: 426 return s.connect_ex((target, port)) == 0 427 except Exception as e: 428 return False
Check if a specific port on a target host is open.
This function attempts to establish a TCP connection to the specified port on the target host. If the connection is successful, it indicates that the port is open. If the connection fails, it indicates that the port is closed or the host is unreachable.
Args: target (str): The hostname or IP address of the target host. port (int): The port number to check.
Returns: bool: True if the port is open, False otherwise.