From ed4e4a1e3e0945b813028da289ce184d43f9be2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20CHALOT?= Date: Fri, 4 Jul 2025 18:30:33 +0200 Subject: [PATCH 1/2] Add the taskkill option --- nxc/protocols/smb.py | 27 +++++++++++++++++++++++++++ nxc/protocols/smb/proto_args.py | 1 + tests/e2e_commands.txt | 4 ++++ 3 files changed, 32 insertions(+) diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index dfca0cc2..c3a0a45f 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -974,6 +974,33 @@ class smb(connection): except Exception as e: self.logger.debug(f"Error getting client address for session {SessionId}: {e}") + @requires_admin + def taskkill(self): + with TSTS.LegacyAPI(self.conn, self.host, self.kerberos) as legacy: + handle = legacy.hRpcWinStationOpenServer() + if self.args.taskkill.isdigit(): + pidList = [int(self.args.taskkill)] + else: + r = legacy.hRpcWinStationGetAllProcesses(handle) + if not r: + self.logger.error("Could not get process list") + return + + pidList = [i["UniqueProcessId"] for i in r if i["ImageName"].lower() == self.args.taskkill.lower()] + if not pidList: + self.logger.fail(f"Could not find process named {self.args.taskkill}") + return + + for pid in pidList: + try: + if legacy.hRpcWinStationTerminateProcess(handle, pid)["ErrorCode"]: + self.logger.highlight(f"Terminated PID {pid} ({self.args.taskkill})") + else: + self.logger.fail(f"Failed terminating PID {pid}") + except Exception: + import traceback + self.logger.error(f"Error terminating PID {pid}: {traceback.format_exc()}") + @requires_admin def qwinsta(self): desktop_states = { diff --git a/nxc/protocols/smb/proto_args.py b/nxc/protocols/smb/proto_args.py index cc914988..8095ec4b 100644 --- a/nxc/protocols/smb/proto_args.py +++ b/nxc/protocols/smb/proto_args.py @@ -55,6 +55,7 @@ def proto_args(parser, parents): mapping_enum_group.add_argument("--rid-brute", nargs="?", type=int, const=4000, metavar="MAX_RID", help="Enumerate users by bruteforcing RIDs") mapping_enum_group.add_argument("--qwinsta", action="store_true", help="Enumerate RDP connections") mapping_enum_group.add_argument("--tasklist", action="store_true", help="Enumerate running processes") + mapping_enum_group.add_argument("--taskkill", type=str, help="Kills a specific PID or a proces name's PID's") wmi_group = smb_parser.add_argument_group("WMI", "Options for WMI Queries") wmi_group.add_argument("--wmi", metavar="QUERY", type=str, help="issues the specified WMI query") diff --git a/tests/e2e_commands.txt b/tests/e2e_commands.txt index e6f8dcf1..9b78892f 100644 --- a/tests/e2e_commands.txt +++ b/tests/e2e_commands.txt @@ -17,6 +17,10 @@ netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --users-exp netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --computers netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --rid-brute netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --local-groups +netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --qwinsta +netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --tasklist +netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --taskkill PID +netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --taskkill PROCESS_NAME netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --gen-relay-list /tmp/relaylistOutputFilename.txt netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --local-auth netexec smb TARGET_HOST -u LOGIN_USERNAME -p LOGIN_PASSWORD KERBEROS --delegate LOGIN_USERNAME From c1dfefd2a1944e984e41d3241cb873087d806ff9 Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Sat, 5 Jul 2025 10:50:25 -0400 Subject: [PATCH 2/2] Use build in exception traceback instead of traceback.format_exc --- nxc/protocols/smb.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/nxc/protocols/smb.py b/nxc/protocols/smb.py index c3a0a45f..e1aea193 100755 --- a/nxc/protocols/smb.py +++ b/nxc/protocols/smb.py @@ -981,12 +981,12 @@ class smb(connection): if self.args.taskkill.isdigit(): pidList = [int(self.args.taskkill)] else: - r = legacy.hRpcWinStationGetAllProcesses(handle) - if not r: + res = legacy.hRpcWinStationGetAllProcesses(handle) + if not res: self.logger.error("Could not get process list") return - pidList = [i["UniqueProcessId"] for i in r if i["ImageName"].lower() == self.args.taskkill.lower()] + pidList = [i["UniqueProcessId"] for i in res if i["ImageName"].lower() == self.args.taskkill.lower()] if not pidList: self.logger.fail(f"Could not find process named {self.args.taskkill}") return @@ -997,9 +997,8 @@ class smb(connection): self.logger.highlight(f"Terminated PID {pid} ({self.args.taskkill})") else: self.logger.fail(f"Failed terminating PID {pid}") - except Exception: - import traceback - self.logger.error(f"Error terminating PID {pid}: {traceback.format_exc()}") + except Exception as e: + self.logger.exception(f"Error terminating PID {pid}: {e}") @requires_admin def qwinsta(self):