From bab59de4bfc2eb06f2a372e5df0b5e8aea80e9d5 Mon Sep 17 00:00:00 2001 From: Alexander Neff Date: Wed, 23 Jul 2025 08:56:39 -0400 Subject: [PATCH] Optimize execution speed --- nxc/protocols/wmi/proto_args.py | 2 +- nxc/protocols/wmi/wmiexec.py | 33 +++++++++++++++------------------ 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/nxc/protocols/wmi/proto_args.py b/nxc/protocols/wmi/proto_args.py index a4750c03..e23ba81b 100644 --- a/nxc/protocols/wmi/proto_args.py +++ b/nxc/protocols/wmi/proto_args.py @@ -17,7 +17,7 @@ def proto_args(parser, parents): cgroup.add_argument("--no-output", action="store_true", help="do not retrieve command output") cgroup.add_argument("-x", metavar="COMMAND", dest="execute", type=str, help="Creates a new cmd process and executes the specified command with output") cgroup.add_argument("--exec-method", choices={"wmiexec", "wmiexec-event"}, default="wmiexec", help="method to execute the command. (default: wmiexec). [wmiexec (win32_process + StdRegProv)]: get command results over registry instead of using smb connection. [wmiexec-event (T1546.003)]: this method is not very stable, highly recommend use this method in single host, using on multiple hosts may crash (just try again if it crashed).") - cgroup.add_argument("--exec-timeout", default=3, metavar="exec_timeout", dest="exec_timeout", type=int, help="Set timeout (in seconds) when executing a command, minimum 5 seconds is recommended. Default: %(default)s") + cgroup.add_argument("--exec-timeout", default=2, metavar="exec_timeout", dest="exec_timeout", type=int, help="Set timeout (in seconds) when executing a command, minimum 5 seconds is recommended. Default: %(default)s") cgroup.add_argument("--codec", default="utf-8", help="Set encoding used (codec) from the target's output (default: utf-8). If errors are detected, run chcp.com at the target & map the result with https://docs.python.org/3/library/codecs.html#standard-encodings and then execute again with --codec and the corresponding codec") return parser diff --git a/nxc/protocols/wmi/wmiexec.py b/nxc/protocols/wmi/wmiexec.py index 8f922738..ab56e2d4 100644 --- a/nxc/protocols/wmi/wmiexec.py +++ b/nxc/protocols/wmi/wmiexec.py @@ -73,16 +73,19 @@ class WMIEXEC: result_output = f"C:\\windows\\temp\\{uuid.uuid4()!s}.txt" result_output_b64 = f"C:\\windows\\temp\\{uuid.uuid4()!s}.txt" keyName = str(uuid.uuid4()) - self.__registry_Path = f"Software\\Classes\\{gen_random_string(6)}" + self.__registry_Path = f"Software\\Classes\\test_nxc_{gen_random_string(6)}" - commands = [ - # 1. Run the command and write output to file - f'{self.__shell} {command} 1> "{result_output}" 2>&1', + # 1. Run the command and write output to file + self.execute_remote(f'{self.__shell} {command} 1> "{result_output}" 2>&1') + self.logger.info(f"Waiting {self.__exec_timeout}s for command to complete.") + time.sleep(self.__exec_timeout) - # 2. Base64 encode the file using PowerShell - f'{self.__shell} powershell -Command "[Convert]::ToBase64String([IO.File]::ReadAllBytes(\'{result_output}\')) | Out-File -Encoding ASCII \'{result_output_b64}\'"', + # 2. Base64 encode the file using PowerShell + self.execute_remote(f'{self.__shell} powershell -Command "[Convert]::ToBase64String([IO.File]::ReadAllBytes(\'{result_output}\')) | Out-File -Encoding ASCII \'{result_output_b64}\'"') + time.sleep(0.5) - # 3. Use PowerShell to split base64 content into 16KB chunks and store in registry + # 3. Use PowerShell to split base64 content into 16KB chunks and store in registry + self.execute_remote( f'{self.__shell} powershell -Command "$b64 = Get-Content -Raw \'{result_output_b64}\'; ' f'$chunksize = 16000; ' f'$count = [math]::Ceiling($b64.Length / $chunksize); ' @@ -90,18 +93,12 @@ class WMIEXEC: f' $chunk = $b64.Substring($i * $chunksize, [math]::Min($chunksize, $b64.Length - ($i * $chunksize))); ' f' $name = \\"{keyName}_chunk_$i\\"; ' f' reg add \\"HKLM\\{self.__registry_Path}\\" /v $name /t REG_SZ /d $chunk /f }}; ' - f'reg add \\"HKLM\\{self.__registry_Path}\\" /v \\"{keyName}\\" /t REG_DWORD /d $count /f"', + f'reg add \\"HKLM\\{self.__registry_Path}\\" /v \\"{keyName}\\" /t REG_DWORD /d $count /f"' + ) + time.sleep(1) - # 4. Delete temporary files - f'{self.__shell} del /q /f "{result_output}" "{result_output_b64}"' - ] - - for cmd in commands: - self.execute_remote(cmd) - time.sleep(0.5) - - self.logger.info(f"Waiting {self.__exec_timeout}s for command to complete.") - time.sleep(self.__exec_timeout) + # 4. Delete temporary files + self.execute_remote(f'{self.__shell} del /q /f "{result_output}" "{result_output_b64}"') self.queryRegistry(keyName)