Skip to content

Commit 58e0f2f

Browse files
authored
Merge pull request Pennyw0rth#970 from Pennyw0rth/neff-fix-#967
2 parents 07c6bf6 + eb42f7b commit 58e0f2f

12 files changed

Lines changed: 45 additions & 140 deletions

File tree

nxc/connection.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ def __init__(self, args, db, target):
135135
self.db = db
136136
self.logger = nxc_logger
137137
self.conn = None
138+
self.output_file_template = None
139+
self.output_filename = None
138140

139141
# Authentication info
140142
self.password = ""
@@ -159,11 +161,6 @@ def __init__(self, args, db, target):
159161
self.local_ip = None
160162
self.dns_server = self.args.dns_server
161163

162-
# Construct the output file template using os.path.join for OS compatibility
163-
base_log_dir = os.path.join(os.path.expanduser(NXC_PATH), "logs")
164-
filename_pattern = f"{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")
165-
self.output_file_template = os.path.join(base_log_dir, "{output_folder}", filename_pattern)
166-
167164
# DNS resolution
168165
dns_result = self.resolver(target)
169166
if dns_result:
@@ -243,6 +240,14 @@ def proto_flow(self):
243240
else:
244241
self.logger.debug("Created connection object")
245242
self.enum_host_info()
243+
244+
# Construct the output file template using os.path.join for OS compatibility
245+
base_log_dir = os.path.join(NXC_PATH, "logs")
246+
filename_pattern = f"{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")
247+
self.output_file_template = os.path.join(base_log_dir, "{output_folder}", filename_pattern)
248+
# Default output filename for logs
249+
self.output_filename = os.path.join(base_log_dir, filename_pattern)
250+
246251
self.print_host_info()
247252
if self.login() or (self.username == "" and self.password == ""):
248253
if hasattr(self.args, "module") and self.args.module:

nxc/helpers/pfx.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,8 @@ def pfx_auth(self):
488488
return None
489489

490490
username = self.args.username[0]
491-
timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H%M%S").replace(":", "-")
492-
log_ccache = os.path.normpath(os.path.expanduser(f"{NXC_PATH}/logs/{self.hostname}_{self.host}_{timestamp}-{username}.ccache"))
491+
basename = f"{self.hostname}_{self.host}_{datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S')}-{username}.ccache"
492+
log_ccache = os.path.normpath(os.path.expanduser(f"{NXC_PATH}/logs/{basename}"))
493493

494494
# Request a TGT with the cert data
495495
req = ini.build_asreq(self.domain, username)

nxc/modules/backup_operator.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import contextlib
2-
import os
3-
import datetime
2+
from time import sleep
43

54
from impacket.examples.secretsdump import SAMHashes, LSASecrets, LocalOperations
65
from impacket.smbconnection import SessionError
76
from impacket.dcerpc.v5 import transport, rrp
87
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE
98
from nxc.helpers.misc import CATEGORY
10-
from nxc.paths import NXC_PATH
119

1210

1311
class NXCModule:
@@ -62,7 +60,7 @@ def on_login(self, context, connection):
6260
dce.disconnect()
6361

6462
# copy remote file to local
65-
log_path = os.path.expanduser(f"{NXC_PATH}/logs/{connection.hostname}_{connection.host}_{datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S')}.".replace(":", "-"))
63+
log_path = f"{connection.output_filename}."
6664
for hive in ["SAM", "SECURITY", "SYSTEM"]:
6765
connection.get_file_single(hive, log_path + hive)
6866

@@ -100,6 +98,7 @@ def parse_sam(secret):
10098

10199
context.log.display(f"Cleaning dump with user {self.domain_admin} and hash {self.domain_admin_hash} on domain {connection.domain}")
102100
connection.execute("del C:\\Windows\\sysvol\\sysvol\\SECURITY && del C:\\Windows\\sysvol\\sysvol\\SAM && del C:\\Windows\\sysvol\\sysvol\\SYSTEM")
101+
sleep(0.2)
103102
for hive in ["SAM", "SECURITY", "SYSTEM"]:
104103
try:
105104
out = connection.conn.listPath("SYSVOL", hive)

nxc/modules/ntds-dump-raw.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,10 @@ def read_from_disk(self, offset, size):
115115
# scary base64 powershell code :)
116116
# This to read the PhysicalDrive0 file
117117
get_data_script = f"""powershell.exe -c "$base64Cmd = '{self.ps_script_b64}';$decodedCmd = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($base64Cmd)) + '; read_disk {offset} {fixed_size}'; Invoke-Expression $decodedCmd" """
118-
if self.connection.__class__.__name__ == "wmi": # noqa: SIM108
118+
if self.connection.__class__.__name__ == "wmi":
119119
data_output = self.connection.execute_psh(get_data_script, True)
120+
elif self.connection.__class__.__name__ == "smb":
121+
data_output = self.execute(get_data_script, True, ["smbexec"])
120122
else:
121123
data_output = self.execute(get_data_script, True)
122124
self.logger.debug(f"{offset=},{size=},{fixed_size=}")
@@ -174,8 +176,11 @@ def main(self):
174176
if self.number_of_file_to_extract != 0:
175177
self.logger.fail("Unable to find all needed files, trying to work with what we have")
176178

177-
self.logger.success("Heads up, hashes on the way...")
178-
self.dump_hashes()
179+
if "SYSTEM" in self.extracted_files_location_local and self.extracted_files_location_local["SYSTEM"] != "":
180+
self.logger.success("Heads up, hashes on the way...")
181+
self.dump_hashes()
182+
else:
183+
self.logger.fail("SYSTEM file not found, unable to proceed with hash extraction")
179184

180185
def dump_hashes(self):
181186
"""Dumping NTDS and SAM hashes locally from the extracted files"""

nxc/modules/putty.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,13 @@ def get_private_key_paths(self, all_users):
154154
return sessions
155155

156156
def extract_session(self, sessions):
157-
proxycreds_file = f"{NXC_PATH}/modules/PuTTY/putty_proxycreds_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")
157+
proxycreds_file = f"{NXC_PATH}/modules/PuTTY/putty_proxycreds_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}"
158158
for session in sessions:
159159
if session["private_key_path"]:
160160
makedirs(f"{NXC_PATH}/modules/PuTTY", exist_ok=True)
161161
share = session["private_key_path"].split(":")[0] + "$"
162162
file_path = session["private_key_path"].split(":")[1]
163-
download_path = f"{NXC_PATH}/modules/PuTTY/putty_{session['user']}_{session['session_name']}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.sec".replace(":", "-")
163+
download_path = f"{NXC_PATH}/modules/PuTTY/putty_{session['user']}_{session['session_name']}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.sec"
164164

165165
buf = BytesIO()
166166
with open(download_path, "wb") as file:

nxc/protocols/ldap.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
from nxc.protocols.ldap.kerberos import KerberosAttacks
4747
from nxc.parsers.ldap_results import parse_result_attributes
4848
from nxc.helpers.ntlm_parser import parse_challenge
49-
from nxc.paths import CONFIG_PATH, NXC_PATH
49+
from nxc.paths import CONFIG_PATH
5050

5151
ldap_error_status = {
5252
"1": "STATUS_NOT_SUPPORTED",
@@ -149,7 +149,6 @@ def __init__(self, args, db, host):
149149
self.targetDomain = ""
150150
self.remote_ops = None
151151
self.bootkey = None
152-
self.output_filename = None
153152
self.smbv1 = None
154153
self.signing = False
155154
self.signing_required = None
@@ -333,9 +332,6 @@ def enum_host_info(self):
333332
self.kdcHost = result["host"] if result else None
334333
self.logger.info(f"Resolved domain: {self.domain} with dns, kdcHost: {self.kdcHost}")
335334

336-
filename = f"{self.hostname}_{self.host}".replace(":", "-")
337-
self.output_filename = os.path.expanduser(os.path.join(NXC_PATH, "logs", filename))
338-
339335
try:
340336
self.db.add_host(
341337
self.host,
@@ -1681,11 +1677,9 @@ def bloodhound(self):
16811677
self.logger.debug(f"BloodHound collection failed: {e.__class__.__name__} - {e}", exc_info=True)
16821678
return
16831679

1684-
self.output_filename += f"_{timestamp}"
1685-
1686-
self.logger.highlight(f"Compressing output into {self.output_filename}bloodhound.zip")
1680+
self.logger.highlight(f"Compressing output into {self.output_filename}_bloodhound.zip")
16871681
list_of_files = os.listdir(os.getcwd())
1688-
with ZipFile(self.output_filename + "bloodhound.zip", "w") as z:
1682+
with ZipFile(f"{self.output_filename}_bloodhound.zip", "w") as z:
16891683
for each_file in list_of_files:
16901684
if each_file.startswith(self.output_filename.split("/")[-1]) and each_file.endswith("json"):
16911685
z.write(each_file)

nxc/protocols/rdp.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ def __init__(self, args, db, host):
5454
self.iosettings.video_bpp_max = 32
5555
# PIL produces incorrect picture for some reason?! TODO: check bug
5656
self.iosettings.video_out_format = VIDEO_FORMAT.PNG #
57-
self.output_filename = None
5857
self.domain = None
5958
self.server_os = None
6059
self.url = None
@@ -140,7 +139,6 @@ def create_conn_obj(self):
140139
self.hostname = info_domain["computername"]
141140
self.server_os = info_domain["os_guess"] + " Build " + str(info_domain["os_build"])
142141
self.logger.extra["hostname"] = self.hostname
143-
self.output_filename = os.path.expanduser(f"{NXC_PATH}/logs/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-"))
144142
break
145143

146144
if self.args.domain:

nxc/protocols/smb.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,6 @@ def __init__(self, args, db, host):
117117
self.nthash = ""
118118
self.remote_ops = None
119119
self.bootkey = None
120-
self.output_file_template = None
121-
self.output_filename = None
122120
self.smbv1 = None # Check if SMBv1 is supported
123121
self.smbv3 = None # Check if SMBv3 is supported
124122
self.is_timed_out = False

nxc/protocols/winrm.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import logging
66
import xml.etree.ElementTree as ET
77

8-
from datetime import datetime
98
from pypsrp.wsman import NAMESPACES
109
from pypsrp.client import Client
1110
from pypsrp.powershell import PSDataStreams
@@ -19,7 +18,6 @@
1918
from nxc.helpers.misc import gen_random_string
2019
from nxc.helpers.ntlm_parser import parse_challenge
2120
from nxc.logger import NXCAdapter
22-
from nxc.paths import NXC_PATH
2321

2422
urllib3.disable_warnings()
2523

@@ -29,7 +27,6 @@ def __init__(self, args, db, host):
2927
self.domain = ""
3028
self.targedDomain = ""
3129
self.server_os = None
32-
self.output_filename = None
3330
self.endpoint = None
3431
self.lmhash = ""
3532
self.nthash = ""
@@ -75,8 +72,6 @@ def enum_host_info(self):
7572
if self.args.local_auth:
7673
self.domain = self.hostname
7774

78-
self.output_filename = os.path.expanduser(f"{NXC_PATH}/logs/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-"))
79-
8075
def print_host_info(self):
8176
self.logger.extra["protocol"] = "WINRM-SSL" if self.ssl else "WINRM"
8277
self.logger.extra["port"] = self.port

nxc/protocols/wmi.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import os
2-
32
from io import StringIO
4-
from datetime import datetime
53

64
from nxc.helpers.ntlm_parser import parse_challenge
75
from nxc.config import process_secret
86
from nxc.connection import connection, dcom_FirewallChecker, requires_admin
97
from nxc.logger import NXCAdapter
108
from nxc.protocols.wmi import wmiexec, wmiexec_event
11-
from nxc.paths import NXC_PATH
129

1310
from impacket import ntlm
1411
from impacket.uuid import uuidtup_to_bin
@@ -141,8 +138,6 @@ def enum_host_info(self):
141138
self.kdcHost = result["host"] if result else None
142139
self.logger.info(f"Resolved domain: {self.domain} with dns, kdcHost: {self.kdcHost}")
143140

144-
self.output_filename = os.path.expanduser(f"{NXC_PATH}/logs/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-"))
145-
146141
def print_host_info(self):
147142
self.logger.extra["protocol"] = "RPC"
148143
self.logger.extra["port"] = "135"

0 commit comments

Comments
 (0)