Skip to content

Commit 65e2b3f

Browse files
authored
Merge pull request Pennyw0rth#449 from Dfte/SMB]-Powershell-history-module-rework
[SMB] Powershell history module rework
2 parents c9ce989 + 9e3ea17 commit 65e2b3f

1 file changed

Lines changed: 47 additions & 56 deletions

File tree

nxc/modules/powershell_history.py

Lines changed: 47 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,64 @@
1-
import traceback
21
from os import makedirs
32
from os.path import join, abspath
43
from nxc.paths import NXC_PATH
4+
from io import BytesIO
55

66

77
class NXCModule:
8-
"""Module by @357384n"""
8+
# Module by @357384n
9+
# Modified by @Defte_ 12/10/2024 to remove unecessary powershell execute command
910

1011
name = "powershell_history"
1112
description = "Extracts PowerShell history for all users and looks for sensitive commands."
1213
supported_protocols = ["smb"]
1314
opsec_safe = True
1415
multiple_hosts = True
16+
false_positive = [".", "..", "desktop.ini", "Public", "Default", "Default User", "All Users", ".NET v4.5", ".NET v4.5 Classic"]
17+
sensitive_keywords = [
18+
"password", "passw", "secret", "credential", "key",
19+
"get-credential", "convertto-securestring", "set-localuser",
20+
"new-localuser", "set-adaccountpassword", "new-object system.net.webclient",
21+
"invoke-webrequest", "invoke-restmethod"
22+
]
1523

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}")
24+
def options(self, _, module_options):
1925
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
3626

3727
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}")
28+
for directory in connection.conn.listPath("C$", "Users\\*"):
29+
if directory.get_longname() not in self.false_positive and directory.is_directory():
6430
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())
31+
powershell_history_dir = f"Users\\{directory.get_longname()}\\AppData\\Roaming\\Microsoft\\Windows\\PowerShell\\PSReadLine\\"
32+
for file in connection.conn.listPath("C$", f"{powershell_history_dir}\\*"):
33+
if file.get_longname() not in self.false_positive:
34+
file_path = f"{powershell_history_dir}{file.get_longname()}"
35+
36+
buf = BytesIO()
37+
connection.conn.getFile("C$", file_path, buf.write)
38+
buf.seek(0)
39+
file_content = buf.read().decode("utf-8", errors="ignore").lower()
40+
keywords = []
41+
for keyword in self.sensitive_keywords:
42+
if keyword in file_content:
43+
keywords.append(keyword.upper())
44+
45+
if keyword:
46+
context.log.highlight(f"C:\\{file_path} [ {' '.join(keywords)} ]")
47+
else:
48+
context.log.highlight(f"C:\\{file_path}")
49+
50+
for line in file_content.splitlines():
51+
context.log.highlight(f"\t{line}")
52+
if self.export:
53+
filename = f"{connection.host}_{directory.get_longname()}_powershell_history.txt"
54+
export_path = join(NXC_PATH, "modules", "powershell_history")
55+
path = abspath(join(export_path, filename))
56+
makedirs(export_path, exist_ok=True)
57+
try:
58+
with open(path, "w+") as file:
59+
file.write(file_content)
60+
context.log.highlight(f"PowerShell history written to: {path}")
61+
except Exception as e:
62+
context.log.fail(f"Failed to write history to {filename}: {e}")
63+
except Exception:
64+
pass

0 commit comments

Comments
 (0)