From a0a7c2673ede52ff3b9103b7a29c279854789fbd Mon Sep 17 00:00:00 2001 From: T1erno Date: Tue, 5 May 2026 14:08:13 -0600 Subject: [PATCH 1/3] Improved Ctrl + c behavior --- nxc/netexec.py | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) mode change 100755 => 100644 nxc/netexec.py diff --git a/nxc/netexec.py b/nxc/netexec.py old mode 100755 new mode 100644 index 18e9a9e21f..08e08d4868 --- a/nxc/netexec.py +++ b/nxc/netexec.py @@ -14,11 +14,13 @@ from nxc.logger import nxc_logger from nxc.config import nxc_config, nxc_workspace, config_log from nxc.database import create_db_engine -from concurrent.futures import ThreadPoolExecutor, as_completed +from concurrent.futures import ThreadPoolExecutor import asyncio from nxc.helpers import powershell +import signal import shutil import os +import contextlib from os.path import exists from os.path import join as path_join from sys import exit @@ -40,34 +42,51 @@ resource.setrlimit(resource.RLIMIT_NOFILE, file_limit) -async def start_run(protocol_obj, args, db, targets): # noqa: RUF029 - futures = [] +async def start_run(protocol_obj, args, db, targets): nxc_logger.debug("Creating ThreadPoolExecutor") + loop = asyncio.get_running_loop() + if args.no_progress or len(targets) == 1: with ThreadPoolExecutor(max_workers=args.threads) as executor: nxc_logger.debug(f"Creating thread for {protocol_obj}") - futures = [executor.submit(protocol_obj, args, db, target) for target in targets] + futures = [loop.run_in_executor(executor, protocol_obj, args, db, target) for target in targets] + await asyncio.gather(*futures, return_exceptions=True) else: with Progress(console=nxc_console) as progress, ThreadPoolExecutor(max_workers=args.threads) as executor: - current = 0 total = len(targets) tasks = progress.add_task( f"[green]Running nxc against {total} {'target' if total == 1 else 'targets'}", total=total, ) nxc_logger.debug(f"Creating thread for {protocol_obj}") - futures = [executor.submit(protocol_obj, args, db, target) for target in targets] - for _ in as_completed(futures): - current += 1 # noqa: SIM113 + futures = [loop.run_in_executor(executor, protocol_obj, args, db, target) for target in targets] + for current, future in enumerate(asyncio.as_completed(futures), 1): + with contextlib.suppress(Exception): + await future progress.update(tasks, completed=current) - for future in as_completed(futures): + + for i, future in enumerate(futures): try: future.result() except Exception: - nxc_logger.exception(f"Exception for target {targets[futures.index(future)]}: {future.exception()}") + nxc_logger.exception(f"Exception for target {targets[i]}: {future.exception()}") + + +def ctrl_c(sig, frame): + nxc_logger.debug("Got keyboard interrupt") + try: + if hasattr(nxc_console, "_live_stack") and nxc_console._live_stack: + for live in nxc_console._live_stack: + live.stop() + nxc_console.show_cursor(True) + except Exception: + pass + nxc_logger.highlight("[!] Interrupted, exiting.") + os._exit(0) def main(): + signal.signal(signal.SIGINT, ctrl_c) first_run_setup(nxc_logger) args, version_info = gen_cli_args() @@ -209,8 +228,6 @@ def main(): try: asyncio.run(start_run(protocol_object, args, db, targets)) - except KeyboardInterrupt: - nxc_logger.debug("Got keyboard interrupt") finally: db_engine.dispose() From 9911e9a280e0989a690aa69598ee5c36cc8ac8c6 Mon Sep 17 00:00:00 2001 From: T1erno Date: Fri, 15 May 2026 20:04:04 -0600 Subject: [PATCH 2/3] Simplify CTRL+C exit --- nxc/netexec.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/nxc/netexec.py b/nxc/netexec.py index 08e08d4868..4276e78a18 100644 --- a/nxc/netexec.py +++ b/nxc/netexec.py @@ -14,13 +14,12 @@ from nxc.logger import nxc_logger from nxc.config import nxc_config, nxc_workspace, config_log from nxc.database import create_db_engine -from concurrent.futures import ThreadPoolExecutor +from concurrent.futures import ThreadPoolExecutor, as_completed import asyncio from nxc.helpers import powershell import signal import shutil import os -import contextlib from os.path import exists from os.path import join as path_join from sys import exit @@ -42,34 +41,31 @@ resource.setrlimit(resource.RLIMIT_NOFILE, file_limit) -async def start_run(protocol_obj, args, db, targets): +async def start_run(protocol_obj, args, db, targets): # noqa: RUF029 + futures = [] nxc_logger.debug("Creating ThreadPoolExecutor") - loop = asyncio.get_running_loop() - if args.no_progress or len(targets) == 1: with ThreadPoolExecutor(max_workers=args.threads) as executor: nxc_logger.debug(f"Creating thread for {protocol_obj}") - futures = [loop.run_in_executor(executor, protocol_obj, args, db, target) for target in targets] - await asyncio.gather(*futures, return_exceptions=True) + futures = [executor.submit(protocol_obj, args, db, target) for target in targets] else: with Progress(console=nxc_console) as progress, ThreadPoolExecutor(max_workers=args.threads) as executor: + current = 0 total = len(targets) tasks = progress.add_task( f"[green]Running nxc against {total} {'target' if total == 1 else 'targets'}", total=total, ) nxc_logger.debug(f"Creating thread for {protocol_obj}") - futures = [loop.run_in_executor(executor, protocol_obj, args, db, target) for target in targets] - for current, future in enumerate(asyncio.as_completed(futures), 1): - with contextlib.suppress(Exception): - await future + futures = [executor.submit(protocol_obj, args, db, target) for target in targets] + for _ in as_completed(futures): + current += 1 # noqa: SIM113 progress.update(tasks, completed=current) - - for i, future in enumerate(futures): + for future in as_completed(futures): try: future.result() except Exception: - nxc_logger.exception(f"Exception for target {targets[i]}: {future.exception()}") + nxc_logger.exception(f"Exception for target {targets[futures.index(future)]}: {future.exception()}") def ctrl_c(sig, frame): From 830b04ba5729e81b8df8c0bd07069f836f83074d Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Sat, 23 May 2026 05:53:12 -0400 Subject: [PATCH 3/3] Use contextlib instead of empty try&except --- nxc/netexec.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nxc/netexec.py b/nxc/netexec.py index 4276e78a18..f606e6e54f 100644 --- a/nxc/netexec.py +++ b/nxc/netexec.py @@ -1,4 +1,5 @@ # PYTHON_ARGCOMPLETE_OK +import contextlib import sys from nxc.helpers.logger import highlight from nxc.helpers.misc import identify_target_file, display_modules @@ -70,13 +71,11 @@ async def start_run(protocol_obj, args, db, targets): # noqa: RUF029 def ctrl_c(sig, frame): nxc_logger.debug("Got keyboard interrupt") - try: + with contextlib.suppress(Exception): if hasattr(nxc_console, "_live_stack") and nxc_console._live_stack: for live in nxc_console._live_stack: live.stop() nxc_console.show_cursor(True) - except Exception: - pass nxc_logger.highlight("[!] Interrupted, exiting.") os._exit(0)