From d814e2cc2c1ff90094ed74060bc28b0ee0b7a668 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:31 +0100 Subject: [PATCH 01/39] Use NXC_PATH in netexec.py --- nxc/netexec.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nxc/netexec.py b/nxc/netexec.py index 5fd273a3..0db79579 100755 --- a/nxc/netexec.py +++ b/nxc/netexec.py @@ -127,8 +127,9 @@ def main(): # The following is a quick hack for the powershell obfuscation functionality, I know this is yucky if hasattr(args, "clear_obfscripts") and args.clear_obfscripts: - shutil.rmtree(os.path.expanduser("~/.nxc/obfuscated_scripts/")) - os.mkdir(os.path.expanduser("~/.nxc/obfuscated_scripts/")) + obfuscated_dir = os.path.join(NXC_PATH, "obfuscated_scripts") + shutil.rmtree(obfuscated_dir) + os.mkdir(obfuscated_dir) nxc_logger.success("Cleared cached obfuscated PowerShell scripts") if hasattr(args, "obfs") and args.obfs: From 7d08340d29226b54d3f1637296bb550d2ac14451 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 02/39] Use NXC_PATH in logger.py --- nxc/helpers/logger.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nxc/helpers/logger.py b/nxc/helpers/logger.py index 22db76f3..1f1d9744 100755 --- a/nxc/helpers/logger.py +++ b/nxc/helpers/logger.py @@ -1,9 +1,11 @@ import os from termcolor import colored +from nxc.paths import NXC_PATH + def write_log(data, log_name): - logs_dir = os.path.join(os.path.expanduser("~/.nxc"), "logs") + logs_dir = os.path.join(NXC_PATH, "logs") with open(os.path.join(logs_dir, log_name), "w") as log_output: log_output.write(data) From bc12c964927c0e5ce2117bacc542ec8b69a08577 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 03/39] Use NXC_PATH in protocolloader.py --- nxc/loaders/protocolloader.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nxc/loaders/protocolloader.py b/nxc/loaders/protocolloader.py index 37407953..40b0f9c0 100755 --- a/nxc/loaders/protocolloader.py +++ b/nxc/loaders/protocolloader.py @@ -3,13 +3,13 @@ from importlib.machinery import SourceFileLoader from os import listdir from os.path import join as path_join from os.path import dirname, exists, expanduser + +from nxc.paths import NXC_PATH + import nxc class ProtocolLoader: - def __init__(self): - self.nxc_path = expanduser("~/.nxc") - def load_protocol(self, protocol_path): loader = SourceFileLoader("protocol", protocol_path) protocol = ModuleType(loader.name) @@ -20,7 +20,7 @@ class ProtocolLoader: protocols = {} protocol_paths = [ path_join(dirname(nxc.__file__), "protocols"), - path_join(self.nxc_path, "protocols"), + path_join(NXC_PATH, "protocols"), ] for path in protocol_paths: From 314c3675efa2562d6d8ca1dfb6f7a9c2d6dc4398 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 04/39] Use NXC_PATH in get-network.py --- nxc/modules/get-network.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nxc/modules/get-network.py b/nxc/modules/get-network.py index 732acd2c..fda0b58e 100644 --- a/nxc/modules/get-network.py +++ b/nxc/modules/get-network.py @@ -2,7 +2,6 @@ # Credit to https://github.com/dirkjanm/adidnsdump @_dirkjan # module by @mpgn_x64 import re -from os.path import expanduser import codecs import socket from datetime import datetime @@ -14,6 +13,9 @@ from impacket.ldap import ldap from impacket.structure import Structure from impacket.ldap import ldapasn1 as ldapasn1_impacket from ldap3 import LEVEL +from os.path import expanduser + +from nxc.paths import NXC_PATH def get_dns_zones(connection, root, debug=False): @@ -181,7 +183,7 @@ class NXCModule: ) context.log.highlight(f"Found {len(outdata)} records") - path = expanduser(f"~/.nxc/logs/{connection.domain}_network_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.log") + path = expanduser(f"{NXC_PATH}/logs/{connection.domain}_network_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.log") with codecs.open(path, "w", "utf-8") as outfile: for row in outdata: if self.showhosts: From fb7ca1dac04f4b8f7a4069554bb471c722fdc0a2 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 05/39] Use TMP_PATH in keepass_trigger.py --- nxc/modules/keepass_trigger.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nxc/modules/keepass_trigger.py b/nxc/modules/keepass_trigger.py index d9d56d4c..b58bc9ab 100644 --- a/nxc/modules/keepass_trigger.py +++ b/nxc/modules/keepass_trigger.py @@ -7,6 +7,8 @@ from io import BytesIO, StringIO from xml.etree import ElementTree from nxc.helpers.powershell import get_ps_script +from nxc.paths import TMP_PATH + class NXCModule: """ @@ -39,7 +41,7 @@ class NXCModule: self.share = "C$" self.remote_temp_script_path = "C:\\Windows\\Temp\\temp.ps1" self.keepass_binary_path = "C:\\Program Files\\KeePass Password Safe 2\\KeePass.exe" - self.local_export_path = "/tmp" + self.local_export_path = TMP_PATH self.trigger_name = "export_database" self.poll_frequency_seconds = 5 self.dummy_service_name = "OneDrive Sync KeePass" From d6e8cad8179e13396eceabf7b70ce82e964988ff Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 06/39] Use NXC_PATH in ldap.py --- nxc/protocols/ldap.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nxc/protocols/ldap.py b/nxc/protocols/ldap.py index 18d1861f..aa7daa24 100644 --- a/nxc/protocols/ldap.py +++ b/nxc/protocols/ldap.py @@ -43,6 +43,8 @@ from nxc.protocols.ldap.kerberos import KerberosAttacks from nxc.parsers.ldap_results import parse_result_attributes from nxc.helpers.ntlm_parser import parse_challenge +from nxc.paths import NXC_PATH + ldap_error_status = { "1": "STATUS_NOT_SUPPORTED", "533": "STATUS_ACCOUNT_DISABLED", @@ -256,7 +258,7 @@ class ldap(connection): self.kdcHost = result["host"] if result else None self.logger.info(f"Resolved domain: {self.domain} with dns, kdcHost: {self.kdcHost}") - self.output_filename = os.path.expanduser(f"~/.nxc/logs/{self.hostname}_{self.host}".replace(":", "-")) + self.output_filename = os.path.expanduser(f"{NXC_PATH}/logs/{self.hostname}_{self.host}".replace(":", "-")) try: self.db.add_host( From f295dcf5f51b7fd54eedf8b0a527e3049ec51889 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 07/39] Use NXC_PATH in rdp.py --- nxc/protocols/rdp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nxc/protocols/rdp.py b/nxc/protocols/rdp.py index d9656694..48378ba9 100644 --- a/nxc/protocols/rdp.py +++ b/nxc/protocols/rdp.py @@ -141,7 +141,7 @@ class rdp(connection): self.hostname = info_domain["computername"] self.server_os = info_domain["os_guess"] + " Build " + str(info_domain["os_build"]) self.logger.extra["hostname"] = self.hostname - self.output_filename = os.path.expanduser(f"~/.nxc/logs/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")) + self.output_filename = os.path.expanduser(f"{NXC_PATH}/logs/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")) break if self.args.domain: @@ -368,7 +368,7 @@ class rdp(connection): await asyncio.sleep(5) if self.conn is not None and self.conn.desktop_buffer_has_data is True: buffer = self.conn.get_desktop_buffer(VIDEO_FORMAT.PIL) - filename = os.path.expanduser(f"~/.nxc/screenshots/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.png") + filename = os.path.expanduser(f"{NXC_PATH}/screenshots/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.png") buffer.save(filename, "png") self.logger.highlight(f"Screenshot saved {filename}") From 4174dd9313f84cc60cbeb783883eed84521a6ab7 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 08/39] Use NXC_PATH in vnc.py --- nxc/protocols/vnc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nxc/protocols/vnc.py b/nxc/protocols/vnc.py index fb6e4d29..568fa9ea 100644 --- a/nxc/protocols/vnc.py +++ b/nxc/protocols/vnc.py @@ -13,6 +13,7 @@ from aardwolf.commons.queuedata.constants import VIDEO_FORMAT from asyauth.common.credentials import UniCredential from asyauth.common.constants import asyauthSecret, asyauthProtocol +from nxc.paths import NXC_PATH class vnc(connection): def __init__(self, args, db, host): @@ -112,7 +113,7 @@ class vnc(connection): await asyncio.sleep(int(self.args.screentime)) if self.conn is not None and self.conn.desktop_buffer_has_data is True: buffer = self.conn.get_desktop_buffer(VIDEO_FORMAT.PIL) - filename = os.path.expanduser(f"~/.nxc/screenshots/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.png") + filename = os.path.expanduser(f"{NXC_PATH}/screenshots/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.png") buffer.save(filename, "png") self.logger.highlight(f"Screenshot saved {filename}") From 038fe52e8c82d02e73aadffc7c46f5e4eedd9645 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 09/39] Use NXC_PATH in winrm.py --- nxc/protocols/winrm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nxc/protocols/winrm.py b/nxc/protocols/winrm.py index ea3dee3a..64491365 100644 --- a/nxc/protocols/winrm.py +++ b/nxc/protocols/winrm.py @@ -19,6 +19,7 @@ from nxc.helpers.misc import gen_random_string from nxc.helpers.ntlm_parser import parse_challenge from nxc.logger import NXCAdapter +from nxc.paths import NXC_PATH urllib3.disable_warnings() @@ -65,7 +66,7 @@ class winrm(connection): if self.args.local_auth: self.domain = self.hostname - self.output_filename = os.path.expanduser(f"~/.nxc/logs/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")) + self.output_filename = os.path.expanduser(f"{NXC_PATH}/logs/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")) def print_host_info(self): self.logger.extra["protocol"] = "WINRM-SSL" if self.ssl else "WINRM" From 0e370152b8c1c090dae5b2432afd3d4ed6841468 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 10/39] Use NXC_PATH in wmi.py --- nxc/protocols/wmi.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nxc/protocols/wmi.py b/nxc/protocols/wmi.py index caf9fd8c..15aaa127 100644 --- a/nxc/protocols/wmi.py +++ b/nxc/protocols/wmi.py @@ -9,6 +9,8 @@ from nxc.connection import connection, dcom_FirewallChecker, requires_admin from nxc.logger import NXCAdapter from nxc.protocols.wmi import wmiexec, wmiexec_event +from nxc.paths import NXC_PATH + from impacket import ntlm from impacket.uuid import uuidtup_to_bin from impacket.krb5.ccache import CCache @@ -140,7 +142,7 @@ class wmi(connection): self.kdcHost = result["host"] if result else None self.logger.info(f"Resolved domain: {self.domain} with dns, kdcHost: {self.kdcHost}") - self.output_filename = os.path.expanduser(f"~/.nxc/logs/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")) + self.output_filename = os.path.expanduser(f"{NXC_PATH}/logs/{self.hostname}_{self.host}_{datetime.now().strftime('%Y-%m-%d_%H%M%S')}".replace(":", "-")) def print_host_info(self): self.logger.extra["protocol"] = "RPC" From b8d5ede6f5d0c965d1750d6e27ca460b0667e1ca Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 11/39] Use TMP_PATH in atexec.py --- nxc/protocols/smb/atexec.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nxc/protocols/smb/atexec.py b/nxc/protocols/smb/atexec.py index 105983d4..087f5fda 100755 --- a/nxc/protocols/smb/atexec.py +++ b/nxc/protocols/smb/atexec.py @@ -6,6 +6,8 @@ from nxc.helpers.misc import gen_random_string from time import sleep from datetime import datetime, timedelta +from nxc.paths import TMP_PATH + class TSCH_EXEC: def __init__(self, target, share_name, username, password, domain, doKerberos=False, aesKey=None, remoteHost=None, kdcHost=None, hashes=None, logger=None, tries=None, share=None): @@ -167,7 +169,7 @@ class TSCH_EXEC: if fileless: while True: try: - with open(os.path.join("/tmp", "nxc_hosted", self.__output_filename)) as output: + with open(os.path.join(TMP_PATH, self.__output_filename)) as output: self.output_callback(output.read()) break except OSError: From a3920da30213ce2b1b7775e691ed1dbca98a2096 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 12/39] Use TMP_PATH in mmcexec.py --- nxc/protocols/smb/mmcexec.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nxc/protocols/smb/mmcexec.py b/nxc/protocols/smb/mmcexec.py index 538ddf38..3fe56768 100644 --- a/nxc/protocols/smb/mmcexec.py +++ b/nxc/protocols/smb/mmcexec.py @@ -30,6 +30,8 @@ from time import sleep from nxc.connection import dcom_FirewallChecker from nxc.helpers.misc import gen_random_string +from nxc.paths import TMP_PATH + from impacket.dcerpc.v5.dcom.oaut import ( IID_IDispatch, string_to_bin, @@ -238,7 +240,7 @@ class MMCEXEC: while True: try: - with open(path_join("/tmp", "nxc_hosted", self.__output)) as output: + with open(path_join(TMP_PATH, self.__output)) as output: self.output_callback(output.read()) break except OSError: From 2e50996ae51308a1fc1408e99b2aa2986a118c12 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 13/39] Use TMP_PATH in wmiexec.py --- nxc/protocols/smb/wmiexec.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nxc/protocols/smb/wmiexec.py b/nxc/protocols/smb/wmiexec.py index 6c762eee..f3ec6134 100755 --- a/nxc/protocols/smb/wmiexec.py +++ b/nxc/protocols/smb/wmiexec.py @@ -7,6 +7,7 @@ from impacket.dcerpc.v5.dcomrt import DCOMConnection from impacket.dcerpc.v5.dcom import wmi from impacket.dcerpc.v5.dtypes import NULL +from nxc.paths import TMP_PATH class WMIEXEC: def __init__(self, target, share_name, username, password, domain, smbconnection, doKerberos=False, aesKey=None, kdcHost=None, remoteHost=None, hashes=None, share=None, logger=None, timeout=None, tries=None): @@ -129,7 +130,7 @@ class WMIEXEC: def get_output_fileless(self): while True: try: - with open(os.path.join("/tmp", "nxc_hosted", self.__output)) as output: + with open(os.path.join(TMP_PATH, self.__output)) as output: self.output_callback(output.read()) break except OSError: From f16616eeb674a9d234505edbad1d7beb24c9f122 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 14/39] Use CONFIG_PATH in database.py --- nxc/protocols/ssh/database.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nxc/protocols/ssh/database.py b/nxc/protocols/ssh/database.py index 7cf25475..7398ec0e 100644 --- a/nxc/protocols/ssh/database.py +++ b/nxc/protocols/ssh/database.py @@ -1,5 +1,4 @@ import configparser -import os import sys from sqlalchemy import Table, select, func, delete @@ -11,11 +10,11 @@ from sqlalchemy.exc import ( from nxc.database import BaseDB, format_host_query from nxc.logger import nxc_logger -from nxc.paths import NXC_PATH +from nxc.paths import CONFIG_PATH # we can't import config.py due to a circular dependency, so we have to create redundant code unfortunately nxc_config = configparser.ConfigParser() -nxc_config.read(os.path.join(NXC_PATH, "nxc.conf")) +nxc_config.read(CONFIG_PATH) nxc_workspace = nxc_config.get("nxc", "workspace", fallback="default") From dc00beab39b10eeb20d0d80bf929f6a8cd059c7d Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 15/39] Use NXC_PATH in enum_dns.py --- nxc/modules/enum_dns.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nxc/modules/enum_dns.py b/nxc/modules/enum_dns.py index fe88cd29..e55eabb2 100644 --- a/nxc/modules/enum_dns.py +++ b/nxc/modules/enum_dns.py @@ -1,6 +1,7 @@ from datetime import datetime from nxc.helpers.logger import write_log +from nxc.paths import NXC_PATH class NXCModule: """ @@ -64,4 +65,4 @@ class NXCModule: log_name = f"DNS-Enum-{connection.host}-{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.log" write_log(data, log_name) - context.log.display(f"Saved raw output to ~/.nxc/logs/{log_name}") + context.log.display(f"Saved raw output to {NXC_PATH}/logs/{log_name}") From 4c515414e238cf0cca5759835d2ba5106af983ce Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 16/39] Use NXC_PATH in get_netconnections.py --- nxc/modules/get_netconnections.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nxc/modules/get_netconnections.py b/nxc/modules/get_netconnections.py index 22f716ee..30eb2713 100755 --- a/nxc/modules/get_netconnections.py +++ b/nxc/modules/get_netconnections.py @@ -2,6 +2,7 @@ from datetime import datetime from nxc.helpers.logger import write_log import json +from nxc.paths import NXC_PATH class NXCModule: """ @@ -31,4 +32,4 @@ class NXCModule: log_name = f"network-connections-{connection.host}-{datetime.now().strftime('%Y-%m-%d_%H%M%S')}.log" write_log(json.dumps(data), log_name) - context.log.display(f"Saved raw output to ~/.nxc/logs/{log_name}") + context.log.display(f"Saved raw output to {NXC_PATH}/logs/{log_name}") From 5f25e25d2656e5bc2ed07e413362c788afada378 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 17/39] Use NXC_PATH in spider_plus.py --- nxc/modules/spider_plus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nxc/modules/spider_plus.py b/nxc/modules/spider_plus.py index 9ccc148d..a047ab3d 100755 --- a/nxc/modules/spider_plus.py +++ b/nxc/modules/spider_plus.py @@ -485,7 +485,7 @@ class NXCModule: EXCLUDE_EXTS Case-insensitive extension filter to exclude (Default: ico,lnk) EXCLUDE_FILTER Case-insensitive filter to exclude folders/files (Default: print$,ipc$) MAX_FILE_SIZE Max file size to download (Default: 51200) - OUTPUT_FOLDER Path of the local folder to save files (Default: ~/.nxc/nxc_spider_plus) + OUTPUT_FOLDER Path of the local folder to save files (Default: NXC_PATH/nxc_spider_plus) """ self.download_flag = False if any("DOWNLOAD" in key for key in module_options): From 95c11aa43489fc23b0c1f14e7148ec5528584f75 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 18/39] Use NXC_PATH,CONFIG_PATH in context.py --- nxc/context.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nxc/context.py b/nxc/context.py index c8004f44..1eaffef7 100755 --- a/nxc/context.py +++ b/nxc/context.py @@ -1,6 +1,8 @@ import configparser import os +from nxc.paths import NXC_PATH, CONFIG_PATH + class Context: def __init__(self, db, logger, args): @@ -8,10 +10,10 @@ class Context: setattr(self, key, value) self.db = db - self.log_folder_path = os.path.join(os.path.expanduser("~/.nxc"), "logs") + self.log_folder_path = os.path.join(os.path.expanduser(NXC_PATH), "logs") self.localip = None self.conf = configparser.ConfigParser() - self.conf.read(os.path.expanduser("~/.nxc/nxc.conf")) + self.conf.read(CONFIG_PATH) self.log = logger From ca7408fd4d20964222337fa4d09d02de57072e77 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 19/39] Use TMP_PATH in smb.py --- nxc/servers/smb.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nxc/servers/smb.py b/nxc/servers/smb.py index 99b8cc58..53a9c445 100755 --- a/nxc/servers/smb.py +++ b/nxc/servers/smb.py @@ -4,13 +4,15 @@ from sys import exit from impacket import smbserver from nxc.logger import nxc_logger +from nxc.paths import TMP_PATH + class NXCSMBServer(threading.Thread): def __init__( self, logger, share_name, - share_path="/tmp/nxc_hosted", + share_path=TMP_PATH, listen_address="0.0.0.0", listen_port=445, verbose=False, From 41a934592790b260d061a7df5d5a86228783bd76 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 20/39] Use CONFIG_PATH in config.py --- nxc/config.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nxc/config.py b/nxc/config.py index 07f2e55b..af6eedb0 100644 --- a/nxc/config.py +++ b/nxc/config.py @@ -1,7 +1,7 @@ import os from os.path import join as path_join import configparser -from nxc.paths import NXC_PATH, DATA_PATH +from nxc.paths import NXC_PATH, DATA_PATH, CONFIG_PATH from nxc.first_run import first_run_setup from nxc.logger import nxc_logger from ast import literal_eval @@ -10,11 +10,11 @@ nxc_default_config = configparser.ConfigParser() nxc_default_config.read(path_join(DATA_PATH, "nxc.conf")) nxc_config = configparser.ConfigParser() -nxc_config.read(os.path.join(NXC_PATH, "nxc.conf")) +nxc_config.read(CONFIG_PATH) if "nxc" not in nxc_config.sections(): first_run_setup() - nxc_config.read(os.path.join(NXC_PATH, "nxc.conf")) + nxc_config.read(CONFIG_PATH) # Check if there are any missing options in the config file for section in nxc_default_config.sections(): @@ -23,7 +23,7 @@ for section in nxc_default_config.sections(): nxc_logger.display(f"Adding missing option '{option}' in config section '{section}' to nxc.conf") nxc_config.set(section, option, nxc_default_config.get(section, option)) - with open(path_join(NXC_PATH, "nxc.conf"), "w") as config_file: + with open(CONFIG_PATH, "w") as config_file: nxc_config.write(config_file) # THESE OPTIONS HAVE TO EXIST IN THE DEFAULT CONFIG FILE From 5fc5922bf2d51f68364dab614750d2589ed4001b Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:17:32 +0100 Subject: [PATCH 21/39] Use WORKSPACE_DIR in netexec.py --- nxc/netexec.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nxc/netexec.py b/nxc/netexec.py index 0db79579..a7b6b32c 100755 --- a/nxc/netexec.py +++ b/nxc/netexec.py @@ -17,6 +17,7 @@ from nxc.database import create_db_engine from concurrent.futures import ThreadPoolExecutor, as_completed import asyncio from nxc.helpers import powershell +from nxc.paths import WORKSPACE_DIR import shutil import os from os.path import exists @@ -147,7 +148,7 @@ def main(): protocol_db_object = p_loader.load_protocol(protocol_db_path).database nxc_logger.debug(f"Protocol DB Object: {protocol_db_object}") - db_path = path_join(NXC_PATH, "workspaces", nxc_workspace, f"{args.protocol}.db") + db_path = path_join(WORKSPACE_DIR, nxc_workspace, f"{args.protocol}.db") nxc_logger.debug(f"DB Path: {db_path}") db_engine = create_db_engine(db_path) From d40a1c84d2ae139e755550ad0a1ff1a452611770 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:27:06 +0100 Subject: [PATCH 22/39] Fix unecessary expand_user in context.py --- nxc/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nxc/context.py b/nxc/context.py index 1eaffef7..7daea34f 100755 --- a/nxc/context.py +++ b/nxc/context.py @@ -10,7 +10,7 @@ class Context: setattr(self, key, value) self.db = db - self.log_folder_path = os.path.join(os.path.expanduser(NXC_PATH), "logs") + self.log_folder_path = os.path.join(NXC_PATH, "logs") self.localip = None self.conf = configparser.ConfigParser() From bf202a23f1e7c0736855d9632b5d3f7a30851143 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:31:14 +0100 Subject: [PATCH 23/39] Merge the two import statements together --- nxc/netexec.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nxc/netexec.py b/nxc/netexec.py index a7b6b32c..02304d3e 100755 --- a/nxc/netexec.py +++ b/nxc/netexec.py @@ -9,7 +9,7 @@ from nxc.cli import gen_cli_args from nxc.loaders.protocolloader import ProtocolLoader from nxc.loaders.moduleloader import ModuleLoader from nxc.first_run import first_run_setup -from nxc.paths import NXC_PATH +from nxc.paths import NXC_PATH, WORKSPACE_DIR from nxc.console import nxc_console from nxc.logger import nxc_logger from nxc.config import nxc_config, nxc_workspace, config_log, ignore_opsec @@ -17,7 +17,6 @@ from nxc.database import create_db_engine from concurrent.futures import ThreadPoolExecutor, as_completed import asyncio from nxc.helpers import powershell -from nxc.paths import WORKSPACE_DIR import shutil import os from os.path import exists From 88997c33a881e7623e191be5092534ddb16512cf Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 14:37:35 +0100 Subject: [PATCH 24/39] Fix ruff findings --- nxc/config.py | 3 +-- nxc/loaders/protocolloader.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/nxc/config.py b/nxc/config.py index af6eedb0..5a87b75b 100644 --- a/nxc/config.py +++ b/nxc/config.py @@ -1,7 +1,6 @@ -import os from os.path import join as path_join import configparser -from nxc.paths import NXC_PATH, DATA_PATH, CONFIG_PATH +from nxc.paths import DATA_PATH, CONFIG_PATH from nxc.first_run import first_run_setup from nxc.logger import nxc_logger from ast import literal_eval diff --git a/nxc/loaders/protocolloader.py b/nxc/loaders/protocolloader.py index 40b0f9c0..d705f891 100755 --- a/nxc/loaders/protocolloader.py +++ b/nxc/loaders/protocolloader.py @@ -2,7 +2,7 @@ from types import ModuleType from importlib.machinery import SourceFileLoader from os import listdir from os.path import join as path_join -from os.path import dirname, exists, expanduser +from os.path import dirname, exists from nxc.paths import NXC_PATH From 64cce9572f88a9f75ecaf318045291b37f0f51dc Mon Sep 17 00:00:00 2001 From: D4ytox Date: Fri, 18 Apr 2025 15:55:30 +0100 Subject: [PATCH 25/39] Fix path imports to be grouped with other imports --- nxc/helpers/logger.py | 1 - nxc/loaders/protocolloader.py | 3 +-- nxc/modules/backup_operator.py | 1 - nxc/modules/enum_dns.py | 1 - nxc/modules/get-network.py | 1 - nxc/modules/get_netconnections.py | 3 +-- nxc/modules/keepass_trigger.py | 1 - nxc/protocols/ldap.py | 1 - nxc/protocols/rdp.py | 2 +- nxc/protocols/smb/atexec.py | 4 +--- nxc/protocols/smb/mmcexec.py | 1 - nxc/protocols/smb/wmiexec.py | 3 +-- nxc/protocols/vnc.py | 3 +-- nxc/protocols/winrm.py | 1 - nxc/protocols/wmi.py | 1 - nxc/servers/smb.py | 2 -- 16 files changed, 6 insertions(+), 23 deletions(-) diff --git a/nxc/helpers/logger.py b/nxc/helpers/logger.py index 1f1d9744..82442d7e 100755 --- a/nxc/helpers/logger.py +++ b/nxc/helpers/logger.py @@ -1,6 +1,5 @@ import os from termcolor import colored - from nxc.paths import NXC_PATH diff --git a/nxc/loaders/protocolloader.py b/nxc/loaders/protocolloader.py index d705f891..fe37f941 100755 --- a/nxc/loaders/protocolloader.py +++ b/nxc/loaders/protocolloader.py @@ -4,9 +4,8 @@ from os import listdir from os.path import join as path_join from os.path import dirname, exists -from nxc.paths import NXC_PATH - import nxc +from nxc.paths import NXC_PATH class ProtocolLoader: diff --git a/nxc/modules/backup_operator.py b/nxc/modules/backup_operator.py index 4b858312..03fba7f2 100644 --- a/nxc/modules/backup_operator.py +++ b/nxc/modules/backup_operator.py @@ -6,7 +6,6 @@ from impacket.examples.secretsdump import SAMHashes, LSASecrets, LocalOperations from impacket.smbconnection import SessionError from impacket.dcerpc.v5 import transport, rrp from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE - from nxc.paths import NXC_PATH class NXCModule: diff --git a/nxc/modules/enum_dns.py b/nxc/modules/enum_dns.py index e55eabb2..7b05b108 100644 --- a/nxc/modules/enum_dns.py +++ b/nxc/modules/enum_dns.py @@ -1,6 +1,5 @@ from datetime import datetime from nxc.helpers.logger import write_log - from nxc.paths import NXC_PATH class NXCModule: diff --git a/nxc/modules/get-network.py b/nxc/modules/get-network.py index fda0b58e..9f3ca393 100644 --- a/nxc/modules/get-network.py +++ b/nxc/modules/get-network.py @@ -14,7 +14,6 @@ from impacket.structure import Structure from impacket.ldap import ldapasn1 as ldapasn1_impacket from ldap3 import LEVEL from os.path import expanduser - from nxc.paths import NXC_PATH diff --git a/nxc/modules/get_netconnections.py b/nxc/modules/get_netconnections.py index 30eb2713..26ebd33c 100755 --- a/nxc/modules/get_netconnections.py +++ b/nxc/modules/get_netconnections.py @@ -1,8 +1,7 @@ from datetime import datetime from nxc.helpers.logger import write_log -import json - from nxc.paths import NXC_PATH +import json class NXCModule: """ diff --git a/nxc/modules/keepass_trigger.py b/nxc/modules/keepass_trigger.py index b58bc9ab..4ed2de25 100644 --- a/nxc/modules/keepass_trigger.py +++ b/nxc/modules/keepass_trigger.py @@ -6,7 +6,6 @@ from base64 import b64encode from io import BytesIO, StringIO from xml.etree import ElementTree from nxc.helpers.powershell import get_ps_script - from nxc.paths import TMP_PATH diff --git a/nxc/protocols/ldap.py b/nxc/protocols/ldap.py index aa7daa24..562f1819 100644 --- a/nxc/protocols/ldap.py +++ b/nxc/protocols/ldap.py @@ -42,7 +42,6 @@ from nxc.protocols.ldap.gmsa import MSDS_MANAGEDPASSWORD_BLOB from nxc.protocols.ldap.kerberos import KerberosAttacks from nxc.parsers.ldap_results import parse_result_attributes from nxc.helpers.ntlm_parser import parse_challenge - from nxc.paths import NXC_PATH ldap_error_status = { diff --git a/nxc/protocols/rdp.py b/nxc/protocols/rdp.py index 48378ba9..84e1ed2e 100644 --- a/nxc/protocols/rdp.py +++ b/nxc/protocols/rdp.py @@ -11,6 +11,7 @@ from nxc.helpers.bloodhound import add_user_bh from nxc.logger import NXCAdapter from nxc.config import host_info_colors from nxc.config import process_secret +from nxc.paths import NXC_PATH from aardwolf.connection import RDPConnection from aardwolf.commons.queuedata.constants import VIDEO_FORMAT @@ -22,7 +23,6 @@ from asyauth.common.credentials.kerberos import KerberosCredential from asyauth.common.constants import asyauthSecret from asysocks.unicomm.common.target import UniTarget, UniProto -from nxc.paths import NXC_PATH class rdp(connection): diff --git a/nxc/protocols/smb/atexec.py b/nxc/protocols/smb/atexec.py index 087f5fda..3ad2b4ae 100755 --- a/nxc/protocols/smb/atexec.py +++ b/nxc/protocols/smb/atexec.py @@ -3,12 +3,10 @@ from impacket.dcerpc.v5 import tsch, transport from impacket.dcerpc.v5.dtypes import NULL from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_LEVEL_PKT_PRIVACY from nxc.helpers.misc import gen_random_string +from nxc.paths import TMP_PATH from time import sleep from datetime import datetime, timedelta -from nxc.paths import TMP_PATH - - class TSCH_EXEC: def __init__(self, target, share_name, username, password, domain, doKerberos=False, aesKey=None, remoteHost=None, kdcHost=None, hashes=None, logger=None, tries=None, share=None): self.__target = target diff --git a/nxc/protocols/smb/mmcexec.py b/nxc/protocols/smb/mmcexec.py index 3fe56768..b964c8ff 100644 --- a/nxc/protocols/smb/mmcexec.py +++ b/nxc/protocols/smb/mmcexec.py @@ -29,7 +29,6 @@ from os.path import join as path_join from time import sleep from nxc.connection import dcom_FirewallChecker from nxc.helpers.misc import gen_random_string - from nxc.paths import TMP_PATH from impacket.dcerpc.v5.dcom.oaut import ( diff --git a/nxc/protocols/smb/wmiexec.py b/nxc/protocols/smb/wmiexec.py index f3ec6134..eb10e0d2 100755 --- a/nxc/protocols/smb/wmiexec.py +++ b/nxc/protocols/smb/wmiexec.py @@ -3,12 +3,11 @@ import os from time import sleep from nxc.connection import dcom_FirewallChecker from nxc.helpers.misc import gen_random_string +from nxc.paths import TMP_PATH from impacket.dcerpc.v5.dcomrt import DCOMConnection from impacket.dcerpc.v5.dcom import wmi from impacket.dcerpc.v5.dtypes import NULL -from nxc.paths import TMP_PATH - class WMIEXEC: def __init__(self, target, share_name, username, password, domain, smbconnection, doKerberos=False, aesKey=None, kdcHost=None, remoteHost=None, hashes=None, share=None, logger=None, timeout=None, tries=None): self.__target = target diff --git a/nxc/protocols/vnc.py b/nxc/protocols/vnc.py index 568fa9ea..460c749f 100644 --- a/nxc/protocols/vnc.py +++ b/nxc/protocols/vnc.py @@ -7,14 +7,13 @@ from aardwolf.commons.target import RDPTarget from nxc.connection import connection from nxc.helpers.logger import highlight from nxc.logger import NXCAdapter +from nxc.paths import NXC_PATH from aardwolf.vncconnection import VNCConnection from aardwolf.commons.iosettings import RDPIOSettings from aardwolf.commons.queuedata.constants import VIDEO_FORMAT from asyauth.common.credentials import UniCredential from asyauth.common.constants import asyauthSecret, asyauthProtocol -from nxc.paths import NXC_PATH - class vnc(connection): def __init__(self, args, db, host): self.iosettings = RDPIOSettings() diff --git a/nxc/protocols/winrm.py b/nxc/protocols/winrm.py index 64491365..0d376c67 100644 --- a/nxc/protocols/winrm.py +++ b/nxc/protocols/winrm.py @@ -18,7 +18,6 @@ from nxc.helpers.bloodhound import add_user_bh from nxc.helpers.misc import gen_random_string from nxc.helpers.ntlm_parser import parse_challenge from nxc.logger import NXCAdapter - from nxc.paths import NXC_PATH urllib3.disable_warnings() diff --git a/nxc/protocols/wmi.py b/nxc/protocols/wmi.py index 15aaa127..a8dd4255 100644 --- a/nxc/protocols/wmi.py +++ b/nxc/protocols/wmi.py @@ -8,7 +8,6 @@ from nxc.config import process_secret from nxc.connection import connection, dcom_FirewallChecker, requires_admin from nxc.logger import NXCAdapter from nxc.protocols.wmi import wmiexec, wmiexec_event - from nxc.paths import NXC_PATH from impacket import ntlm diff --git a/nxc/servers/smb.py b/nxc/servers/smb.py index 53a9c445..f35776d0 100755 --- a/nxc/servers/smb.py +++ b/nxc/servers/smb.py @@ -3,10 +3,8 @@ from threading import enumerate from sys import exit from impacket import smbserver from nxc.logger import nxc_logger - from nxc.paths import TMP_PATH - class NXCSMBServer(threading.Thread): def __init__( self, From ff1ce969f9485c4099027832169447e063521498 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Sun, 20 Apr 2025 14:49:25 +0100 Subject: [PATCH 26/39] Use XDG_CONFIG_HOME and XDG_DATA_HOME if set by user --- nxc/paths.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nxc/paths.py b/nxc/paths.py index 31e3479d..27258889 100644 --- a/nxc/paths.py +++ b/nxc/paths.py @@ -2,7 +2,7 @@ import os import sys import nxc -NXC_PATH = os.path.expanduser("~/.nxc") +NXC_PATH = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.nxc")) if os.name == "nt": TMP_PATH = os.getenv("LOCALAPPDATA") + "\\Temp\\nxc_hosted" elif hasattr(sys, "getandroidapilevel"): @@ -13,4 +13,4 @@ else: CERT_PATH = os.path.join(NXC_PATH, "nxc.pem") CONFIG_PATH = os.path.join(NXC_PATH, "nxc.conf") WORKSPACE_DIR = os.path.join(NXC_PATH, "workspaces") -DATA_PATH = os.path.join(os.path.dirname(nxc.__file__), "data") +DATA_PATH = os.getenv('XDG_DATA_HOME', os.path.join(os.path.dirname(nxc.__file__), "data")) From 0abadb062b8bf4db124604ba0ec8f419b20b2c3f Mon Sep 17 00:00:00 2001 From: D4ytox Date: Sun, 20 Apr 2025 15:03:12 +0100 Subject: [PATCH 27/39] Make XDG_CONFIG_HOME append nxc afterwards and XDG_DATA_HOME append nxc_data --- nxc/paths.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nxc/paths.py b/nxc/paths.py index 27258889..e0912dfd 100644 --- a/nxc/paths.py +++ b/nxc/paths.py @@ -2,7 +2,7 @@ import os import sys import nxc -NXC_PATH = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.nxc")) +NXC_PATH = os.path.join(os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/")), "nxc") if os.name == "nt": TMP_PATH = os.getenv("LOCALAPPDATA") + "\\Temp\\nxc_hosted" elif hasattr(sys, "getandroidapilevel"): @@ -13,4 +13,8 @@ else: CERT_PATH = os.path.join(NXC_PATH, "nxc.pem") CONFIG_PATH = os.path.join(NXC_PATH, "nxc.conf") WORKSPACE_DIR = os.path.join(NXC_PATH, "workspaces") -DATA_PATH = os.getenv('XDG_DATA_HOME', os.path.join(os.path.dirname(nxc.__file__), "data")) + +if 'XDG_DATA_HOME' in os.environ: + DATA_PATH = os.path.join(os.getenv('XDG_DATA_HOME'), "nxc_data") +else: + DATA_PATH = os.path.join(os.path.dirname(nxc.__file__), "data") From 8deb2f99245cd5892cd857e01716f65c4254fd48 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Sun, 20 Apr 2025 15:09:52 +0100 Subject: [PATCH 28/39] Use nxc as the folder name for XDG_DATA_HOME as well --- nxc/paths.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nxc/paths.py b/nxc/paths.py index e0912dfd..391ac6ae 100644 --- a/nxc/paths.py +++ b/nxc/paths.py @@ -2,7 +2,8 @@ import os import sys import nxc -NXC_PATH = os.path.join(os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/")), "nxc") +NXC_APP_NAME = "nxc" +NXC_PATH = os.path.join(os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/")), NXC_APP_NAME) if os.name == "nt": TMP_PATH = os.getenv("LOCALAPPDATA") + "\\Temp\\nxc_hosted" elif hasattr(sys, "getandroidapilevel"): @@ -15,6 +16,6 @@ CONFIG_PATH = os.path.join(NXC_PATH, "nxc.conf") WORKSPACE_DIR = os.path.join(NXC_PATH, "workspaces") if 'XDG_DATA_HOME' in os.environ: - DATA_PATH = os.path.join(os.getenv('XDG_DATA_HOME'), "nxc_data") + DATA_PATH = os.path.join(os.getenv('XDG_DATA_HOME'), NXC_APP_NAME) else: DATA_PATH = os.path.join(os.path.dirname(nxc.__file__), "data") From 46c16213f96c4a68b089f46ad4ab8b6a4dfc89de Mon Sep 17 00:00:00 2001 From: D4ytox Date: Sun, 20 Apr 2025 15:17:28 +0100 Subject: [PATCH 29/39] Remove the use of XDG_DATA_HOME --- nxc/paths.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/nxc/paths.py b/nxc/paths.py index 391ac6ae..37b30f6b 100644 --- a/nxc/paths.py +++ b/nxc/paths.py @@ -2,8 +2,7 @@ import os import sys import nxc -NXC_APP_NAME = "nxc" -NXC_PATH = os.path.join(os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/")), NXC_APP_NAME) +NXC_PATH = os.path.join(os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/")), "nxc") if os.name == "nt": TMP_PATH = os.getenv("LOCALAPPDATA") + "\\Temp\\nxc_hosted" elif hasattr(sys, "getandroidapilevel"): @@ -14,8 +13,4 @@ else: CERT_PATH = os.path.join(NXC_PATH, "nxc.pem") CONFIG_PATH = os.path.join(NXC_PATH, "nxc.conf") WORKSPACE_DIR = os.path.join(NXC_PATH, "workspaces") - -if 'XDG_DATA_HOME' in os.environ: - DATA_PATH = os.path.join(os.getenv('XDG_DATA_HOME'), NXC_APP_NAME) -else: - DATA_PATH = os.path.join(os.path.dirname(nxc.__file__), "data") +DATA_PATH = os.path.join(os.path.dirname(nxc.__file__), "data") From d51fc3f09592f88d77bfee21dca0b6f7f1760003 Mon Sep 17 00:00:00 2001 From: D4ytox Date: Sun, 20 Apr 2025 16:18:29 +0100 Subject: [PATCH 30/39] Fix . missing from classic path --- nxc/paths.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nxc/paths.py b/nxc/paths.py index 37b30f6b..1468289b 100644 --- a/nxc/paths.py +++ b/nxc/paths.py @@ -2,7 +2,11 @@ import os import sys import nxc -NXC_PATH = os.path.join(os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/")), "nxc") +if 'XDG_CONFIG_HOME' in os.environ: + NXC_PATH = os.path.join(os.getenv('XDG_CONFIG_HOME'), "nxc") +else: + NXC_PATH = os.path.expanduser("~/.nxc") + if os.name == "nt": TMP_PATH = os.getenv("LOCALAPPDATA") + "\\Temp\\nxc_hosted" elif hasattr(sys, "getandroidapilevel"): From 0b4d0bb21cfb7a4e229b3e85a063369be4944aa2 Mon Sep 17 00:00:00 2001 From: Alex <61382599+NeffIsBack@users.noreply.github.com> Date: Tue, 10 Jun 2025 12:46:37 +0200 Subject: [PATCH 31/39] Replace single quotes --- nxc/paths.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nxc/paths.py b/nxc/paths.py index 1468289b..adece2f8 100644 --- a/nxc/paths.py +++ b/nxc/paths.py @@ -2,8 +2,8 @@ import os import sys import nxc -if 'XDG_CONFIG_HOME' in os.environ: - NXC_PATH = os.path.join(os.getenv('XDG_CONFIG_HOME'), "nxc") +if "XDG_CONFIG_HOME" in os.environ: # noqa: SIM108 + NXC_PATH = os.path.join(os.getenv("XDG_CONFIG_HOME"), "nxc") else: NXC_PATH = os.path.expanduser("~/.nxc") From 7ea164af9798329a1778eb28eac482ec03add12f Mon Sep 17 00:00:00 2001 From: Alex <61382599+NeffIsBack@users.noreply.github.com> Date: Tue, 10 Jun 2025 12:47:02 +0200 Subject: [PATCH 32/39] Normpath for nxc folder --- nxc/paths.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nxc/paths.py b/nxc/paths.py index adece2f8..4f0d6dd6 100644 --- a/nxc/paths.py +++ b/nxc/paths.py @@ -5,7 +5,7 @@ import nxc if "XDG_CONFIG_HOME" in os.environ: # noqa: SIM108 NXC_PATH = os.path.join(os.getenv("XDG_CONFIG_HOME"), "nxc") else: - NXC_PATH = os.path.expanduser("~/.nxc") + NXC_PATH = os.path.normpath(os.path.expanduser("~/.nxc")) if os.name == "nt": TMP_PATH = os.getenv("LOCALAPPDATA") + "\\Temp\\nxc_hosted" From 07803cb58c949a9b70e135794d902f03925b1864 Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Tue, 10 Jun 2025 07:58:44 -0400 Subject: [PATCH 33/39] Use NXC_CONFIG instead of retrieving it with NXC_PATH/nxc.conf --- nxc/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nxc/config.py b/nxc/config.py index a8035078..6582deef 100644 --- a/nxc/config.py +++ b/nxc/config.py @@ -20,7 +20,7 @@ for section in nxc_default_config.sections(): if not nxc_config.has_section(section): nxc_logger.display(f"Adding missing section '{section}' to nxc.conf") nxc_config.add_section(section) - with open(path_join(NXC_PATH, "nxc.conf"), "w") as config_file: + with open(CONFIG_PATH, "w") as config_file: nxc_config.write(config_file) for option in nxc_default_config.options(section): if not nxc_config.has_option(section, option): From b9bee6bb0b0a711c849f033cc6c5c77b7df7a1a7 Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Tue, 10 Jun 2025 07:59:27 -0400 Subject: [PATCH 34/39] Use NXC_PATH instead of XDG env var and also initialize TMP folder when nxc folder exists --- nxc/first_run.py | 5 ++--- nxc/paths.py | 25 +++++++++---------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/nxc/first_run.py b/nxc/first_run.py index eee20802..d1fb6024 100755 --- a/nxc/first_run.py +++ b/nxc/first_run.py @@ -8,13 +8,12 @@ from nxc.logger import nxc_logger def first_run_setup(logger=nxc_logger): - if not exists(TMP_PATH): - mkdir(TMP_PATH) - if not exists(NXC_PATH): logger.display("First time use detected") logger.display("Creating home directory structure") mkdir(NXC_PATH) + if not exists(TMP_PATH): + mkdir(TMP_PATH) folders = ( "logs", diff --git a/nxc/paths.py b/nxc/paths.py index 4f0d6dd6..a9a148d1 100644 --- a/nxc/paths.py +++ b/nxc/paths.py @@ -1,20 +1,13 @@ -import os -import sys +from os.path import join, normpath, expanduser, dirname +from os import environ, getenv import nxc -if "XDG_CONFIG_HOME" in os.environ: # noqa: SIM108 - NXC_PATH = os.path.join(os.getenv("XDG_CONFIG_HOME"), "nxc") +if "NXC_PATH" in environ: # noqa: SIM108 + NXC_PATH = normpath(getenv("NXC_PATH")) else: - NXC_PATH = os.path.normpath(os.path.expanduser("~/.nxc")) - -if os.name == "nt": - TMP_PATH = os.getenv("LOCALAPPDATA") + "\\Temp\\nxc_hosted" -elif hasattr(sys, "getandroidapilevel"): - TMP_PATH = os.path.join("/data", "data", "com.termux", "files", "usr", "tmp", "nxc_hosted") -else: - TMP_PATH = os.path.join("/tmp", "nxc_hosted") + NXC_PATH = normpath(expanduser("~/.nxc")) -CERT_PATH = os.path.join(NXC_PATH, "nxc.pem") -CONFIG_PATH = os.path.join(NXC_PATH, "nxc.conf") -WORKSPACE_DIR = os.path.join(NXC_PATH, "workspaces") -DATA_PATH = os.path.join(os.path.dirname(nxc.__file__), "data") +TMP_PATH = join(NXC_PATH, "tmp") +CONFIG_PATH = join(NXC_PATH, "nxc.conf") +WORKSPACE_DIR = join(NXC_PATH, "workspaces") +DATA_PATH = join(dirname(nxc.__file__), "data") From 029ec26024a652d5ceb315e0ad5f0ad23ec063c1 Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Tue, 10 Jun 2025 08:03:49 -0400 Subject: [PATCH 35/39] Remove legacy code --- nxc/first_run.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nxc/first_run.py b/nxc/first_run.py index d1fb6024..7a0244a2 100755 --- a/nxc/first_run.py +++ b/nxc/first_run.py @@ -18,7 +18,6 @@ def first_run_setup(logger=nxc_logger): folders = ( "logs", "modules", - "protocols", "workspaces", "obfuscated_scripts", "screenshots", @@ -45,7 +44,3 @@ def first_run_setup(logger=nxc_logger): logger.display("Copying default configuration file") default_path = path_join(DATA_PATH, "nxc.conf") shutil.copy(default_path, NXC_PATH) - - # if not exists(CERT_PATH): - # if os.name != 'nt': - # if e.errno == errno.ENOENT: From 5101a96e03a82e19f4fc14b216fbeb785ff34522 Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Tue, 10 Jun 2025 08:14:51 -0400 Subject: [PATCH 36/39] Replace config paths with variable and formatting --- nxc/modules/enum_dns.py | 3 ++- nxc/netexec.py | 4 ++-- nxc/protocols/ldap.py | 4 ++-- nxc/protocols/rdp.py | 3 +-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nxc/modules/enum_dns.py b/nxc/modules/enum_dns.py index d10ae390..8d8abe10 100644 --- a/nxc/modules/enum_dns.py +++ b/nxc/modules/enum_dns.py @@ -2,6 +2,7 @@ from datetime import datetime from nxc.helpers.logger import write_log from nxc.paths import NXC_PATH + class NXCModule: """ Uses WMI to dump DNS from an AD DNS Server. @@ -34,7 +35,7 @@ class NXCModule: else: domains = [self.domains] data = "" - + for domain in domains: output = connection.wmi( f"Select TextRepresentation FROM MicrosoftDNS_ResourceRecord WHERE DomainName = {domain}", diff --git a/nxc/netexec.py b/nxc/netexec.py index 8591591f..b11b70dc 100755 --- a/nxc/netexec.py +++ b/nxc/netexec.py @@ -9,7 +9,7 @@ from nxc.cli import gen_cli_args from nxc.loaders.protocolloader import ProtocolLoader from nxc.loaders.moduleloader import ModuleLoader from nxc.first_run import first_run_setup -from nxc.paths import NXC_PATH, WORKSPACE_DIR +from nxc.paths import CONFIG_PATH, NXC_PATH, WORKSPACE_DIR from nxc.console import nxc_console from nxc.logger import nxc_logger from nxc.config import nxc_config, nxc_workspace, config_log, ignore_opsec @@ -195,7 +195,7 @@ def main(): nxc_logger.debug("ignore_opsec is set in the configuration, skipping prompt") nxc_logger.display("Ignore OPSEC in configuration is set and OPSEC unsafe module loaded") else: - ans = input(highlight("[!] Module is not opsec safe, are you sure you want to run this? [Y/n] For global configuration, change ignore_opsec value to True on ~/nxc/nxc.conf", "red")) + ans = input(highlight(f"[!] Module is not opsec safe, are you sure you want to run this? [Y/n] For global configuration, change ignore_opsec value to True on {CONFIG_PATH}", "red")) if ans.lower() not in ["y", "yes", ""]: exit(1) diff --git a/nxc/protocols/ldap.py b/nxc/protocols/ldap.py index fc579491..413590c3 100644 --- a/nxc/protocols/ldap.py +++ b/nxc/protocols/ldap.py @@ -44,7 +44,7 @@ from nxc.protocols.ldap.kerberos import KerberosAttacks from nxc.parsers.ldap_results import parse_result_attributes from nxc.helpers.ntlm_parser import parse_challenge from nxc.helpers.misc import get_bloodhound_info -from nxc.paths import NXC_PATH +from nxc.paths import CONFIG_PATH, NXC_PATH ldap_error_status = { "1": "STATUS_NOT_SUPPORTED", @@ -1355,7 +1355,7 @@ class ldap(connection): if use_bhce and not is_ce: self.logger.fail("⚠️ Configuration Issue Detected ⚠️") - self.logger.fail("Your configuration has BloodHound-CE enabled, but the regular BloodHound package is installed. Modify your ~/.nxc/nxc.conf config file or follow the instructions:") + self.logger.fail(f"Your configuration has BloodHound-CE enabled, but the regular BloodHound package is installed. Modify your {CONFIG_PATH} config file or follow the instructions:") self.logger.fail("Please run the following commands to fix this:") self.logger.fail("poetry remove bloodhound-ce # poetry falsely recognizes bloodhound-ce as a the old bloodhound package") self.logger.fail("poetry add bloodhound-ce") diff --git a/nxc/protocols/rdp.py b/nxc/protocols/rdp.py index 84e1ed2e..ae939089 100644 --- a/nxc/protocols/rdp.py +++ b/nxc/protocols/rdp.py @@ -9,8 +9,7 @@ from impacket.krb5.ccache import CCache from nxc.connection import connection from nxc.helpers.bloodhound import add_user_bh from nxc.logger import NXCAdapter -from nxc.config import host_info_colors -from nxc.config import process_secret +from nxc.config import host_info_colors, process_secret from nxc.paths import NXC_PATH from aardwolf.connection import RDPConnection From e2351bac12330dd7951835ae0b4a6ee0974b0a9c Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Tue, 10 Jun 2025 08:22:45 -0400 Subject: [PATCH 37/39] Remove legacy code --- nxc/loaders/protocolloader.py | 36 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/nxc/loaders/protocolloader.py b/nxc/loaders/protocolloader.py index fe37f941..83f94765 100755 --- a/nxc/loaders/protocolloader.py +++ b/nxc/loaders/protocolloader.py @@ -5,7 +5,6 @@ from os.path import join as path_join from os.path import dirname, exists import nxc -from nxc.paths import NXC_PATH class ProtocolLoader: @@ -17,27 +16,22 @@ class ProtocolLoader: def get_protocols(self): protocols = {} - protocol_paths = [ - path_join(dirname(nxc.__file__), "protocols"), - path_join(NXC_PATH, "protocols"), - ] - for path in protocol_paths: - for protocol in listdir(path): - if protocol[-3:] == ".py" and protocol[:-3] != "__init__": - protocol_path = path_join(path, protocol) - protocol_name = protocol[:-3] + proto_path = path_join(dirname(nxc.__file__), "protocols") + for protocol in listdir(proto_path): + if protocol[-3:] == ".py" and protocol[:-3] != "__init__": + protocol_path = path_join(proto_path, protocol) + protocol_name = protocol[:-3] - protocols[protocol_name] = {"path": protocol_path} - - db_file_path = path_join(path, protocol_name, "database.py") - db_nav_path = path_join(path, protocol_name, "db_navigator.py") - protocol_args_path = path_join(path, protocol_name, "proto_args.py") - if exists(db_file_path): - protocols[protocol_name]["dbpath"] = db_file_path - if exists(db_nav_path): - protocols[protocol_name]["nvpath"] = db_nav_path - if exists(protocol_args_path): - protocols[protocol_name]["argspath"] = protocol_args_path + protocols[protocol_name] = {"path": protocol_path} + db_file_path = path_join(proto_path, protocol_name, "database.py") + db_nav_path = path_join(proto_path, protocol_name, "db_navigator.py") + protocol_args_path = path_join(proto_path, protocol_name, "proto_args.py") + if exists(db_file_path): + protocols[protocol_name]["dbpath"] = db_file_path + if exists(db_nav_path): + protocols[protocol_name]["nvpath"] = db_nav_path + if exists(protocol_args_path): + protocols[protocol_name]["argspath"] = protocol_args_path return protocols From ea0a42af7ccc48e7362a30ec7fcac9bbc2df03ca Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Tue, 10 Jun 2025 08:38:57 -0400 Subject: [PATCH 38/39] Fix path in user-desc module --- nxc/modules/user-desc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nxc/modules/user-desc.py b/nxc/modules/user-desc.py index 47d6e574..1faacd72 100644 --- a/nxc/modules/user-desc.py +++ b/nxc/modules/user-desc.py @@ -3,6 +3,8 @@ from datetime import datetime from impacket.ldap import ldap, ldapasn1 from impacket.ldap.ldap import LDAPSearchError +from nxc.paths import NXC_PATH + class NXCModule: """ @@ -91,7 +93,7 @@ class NXCModule: def create_log_file(self, host, time): """Create a log file for dumping user descriptions.""" logfile = f"UserDesc-{host}-{time}.log" - logfile = Path.home().joinpath(".nxc").joinpath("logs").joinpath(logfile) + logfile = Path(NXC_PATH).joinpath(logfile) self.context.log.info(f"Creating log file '{logfile}'") self.log_file = open(logfile, "w") # noqa: SIM115 From 06c0a7fb3de742320895735e2f21b5fcfdbf343d Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Tue, 10 Jun 2025 08:43:08 -0400 Subject: [PATCH 39/39] Linting --- nxc/modules/get_netconnections.py | 1 + nxc/protocols/rdp.py | 1 - nxc/protocols/smb/atexec.py | 1 + nxc/protocols/smb/wmiexec.py | 1 + nxc/protocols/vnc.py | 1 + 5 files changed, 4 insertions(+), 1 deletion(-) diff --git a/nxc/modules/get_netconnections.py b/nxc/modules/get_netconnections.py index 39f9be68..0c3acee4 100755 --- a/nxc/modules/get_netconnections.py +++ b/nxc/modules/get_netconnections.py @@ -3,6 +3,7 @@ from nxc.helpers.logger import write_log from nxc.paths import NXC_PATH import json + class NXCModule: """ Uses WMI to extract network connections, used to find multi-homed hosts. diff --git a/nxc/protocols/rdp.py b/nxc/protocols/rdp.py index ae939089..0d481572 100644 --- a/nxc/protocols/rdp.py +++ b/nxc/protocols/rdp.py @@ -23,7 +23,6 @@ from asyauth.common.constants import asyauthSecret from asysocks.unicomm.common.target import UniTarget, UniProto - class rdp(connection): def __init__(self, args, db, host): self.domain = None diff --git a/nxc/protocols/smb/atexec.py b/nxc/protocols/smb/atexec.py index f7c0c773..b8482db2 100755 --- a/nxc/protocols/smb/atexec.py +++ b/nxc/protocols/smb/atexec.py @@ -7,6 +7,7 @@ from nxc.paths import TMP_PATH from time import sleep from datetime import datetime, timedelta + class TSCH_EXEC: def __init__(self, target, share_name, username, password, domain, doKerberos=False, aesKey=None, remoteHost=None, kdcHost=None, hashes=None, logger=None, tries=None, share=None): self.__target = target diff --git a/nxc/protocols/smb/wmiexec.py b/nxc/protocols/smb/wmiexec.py index eb10e0d2..4fa3ce1a 100755 --- a/nxc/protocols/smb/wmiexec.py +++ b/nxc/protocols/smb/wmiexec.py @@ -8,6 +8,7 @@ from impacket.dcerpc.v5.dcomrt import DCOMConnection from impacket.dcerpc.v5.dcom import wmi from impacket.dcerpc.v5.dtypes import NULL + class WMIEXEC: def __init__(self, target, share_name, username, password, domain, smbconnection, doKerberos=False, aesKey=None, kdcHost=None, remoteHost=None, hashes=None, share=None, logger=None, timeout=None, tries=None): self.__target = target diff --git a/nxc/protocols/vnc.py b/nxc/protocols/vnc.py index 460c749f..54d1f81b 100644 --- a/nxc/protocols/vnc.py +++ b/nxc/protocols/vnc.py @@ -14,6 +14,7 @@ from aardwolf.commons.queuedata.constants import VIDEO_FORMAT from asyauth.common.credentials import UniCredential from asyauth.common.constants import asyauthSecret, asyauthProtocol + class vnc(connection): def __init__(self, args, db, host): self.iosettings = RDPIOSettings()