Skip to content

Commit 776b84a

Browse files
authored
Merge pull request Pennyw0rth#812 from Pennyw0rth/neff-fix-wmi
Fix command execution in wmi
2 parents ed7db99 + ffa4636 commit 776b84a

3 files changed

Lines changed: 24 additions & 16 deletions

File tree

nxc/protocols/wmi.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -411,19 +411,20 @@ def wmi(self, wql=None, namespace=None):
411411
@requires_admin
412412
def execute(self, command=None, get_output=False):
413413
output = ""
414-
if not command:
415-
command = self.args.execute
416414

417-
if not self.args.no_output:
418-
get_output = True
415+
# Execution via -x
416+
if not command and self.args.execute:
417+
command = self.args.execute
418+
if not self.args.no_output:
419+
get_output = True
419420

420421
if "systeminfo" in command and self.args.exec_timeout < 10:
421422
self.logger.fail("Execute 'systeminfo' must set the interval time higher than 10 seconds")
422-
return False
423+
return ""
423424

424425
if self.server_os is not None and "NT 5" in self.server_os:
425426
self.logger.fail("Execute command failed, not support current server os (version < NT 6)")
426-
return False
427+
return ""
427428

428429
if self.args.exec_method == "wmiexec":
429430
exec_method = wmiexec.WMIEXEC(self.remoteName, self.username, self.password, self.domain, self.lmhash, self.nthash, self.doKerberos, self.kdcHost, self.host, self.aesKey, self.logger, self.args.exec_timeout, self.args.codec)
@@ -436,10 +437,12 @@ def execute(self, command=None, get_output=False):
436437
self.conn.disconnect()
437438
if output == "" and get_output:
438439
self.logger.fail("Execute command failed, probabaly got detection by AV.")
439-
return False
440-
else:
440+
return ""
441+
elif self.args.execute and get_output:
441442
self.logger.success(f'Executed command: "{command}" via {self.args.exec_method}')
442443
buf = StringIO(output).readlines()
443444
for line in buf:
444445
self.logger.highlight(line.strip())
445446
return output
447+
elif get_output:
448+
return output

nxc/protocols/wmi/proto_args.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def proto_args(parser, parents):
1717
cgroup.add_argument("--no-output", action="store_true", help="do not retrieve command output")
1818
cgroup.add_argument("-x", metavar="COMMAND", dest="execute", type=str, help="Creates a new cmd process and executes the specified command with output")
1919
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).")
20-
cgroup.add_argument("--exec-timeout", default=5, 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")
20+
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")
2121
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")
2222
return parser
2323

nxc/protocols/wmi/wmiexec.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def __init__(self, target, username, password, domain, lmhash, nthash, doKerbero
3939
self.__exec_timeout = exec_timeout
4040
self.__registry_Path = ""
4141
self.__outputBuffer = ""
42-
self.__retOutput = True
4342

4443
self.__shell = "cmd.exe /Q /c "
4544
self.__pwd = "C:\\"
@@ -53,8 +52,7 @@ def __init__(self, target, username, password, domain, lmhash, nthash, doKerbero
5352
self.__win32Process, _ = self.__iWbemServices.GetObject("Win32_Process")
5453

5554
def execute(self, command, output=False):
56-
self.__retOutput = output
57-
if self.__retOutput:
55+
if output:
5856
self.execute_WithOutput(command)
5957
else:
6058
command = self.__shell + command
@@ -77,9 +75,16 @@ def execute_WithOutput(self, command):
7775
keyName = str(uuid.uuid4())
7876
self.__registry_Path = f"Software\\Classes\\{gen_random_string(6)}"
7977

80-
command = rf"""{self.__shell} {command} 1> {result_output} 2>&1 && certutil -encodehex -f {result_output} {result_output_b64} 0x40000001 && for /F "usebackq" %G in ("{result_output_b64}") do reg add HKLM\{self.__registry_Path} /v {keyName} /t REG_SZ /d "%G" /f && del /q /f /s {result_output} {result_output_b64}"""
78+
commands = [
79+
f"{self.__shell} {command} 1> {result_output} 2>&1",
80+
f"{self.__shell} certutil -encodehex -f {result_output} {result_output_b64} 0x40000001",
81+
f'{self.__shell} for /F "usebackq" %G in ("{result_output_b64}") do reg add HKLM\\{self.__registry_Path} /v {keyName} /t REG_SZ /d "%G" /f',
82+
f"{self.__shell} del /q /f /s {result_output} {result_output_b64}",
83+
]
8184

82-
self.execute_remote(command)
85+
for cmd in commands:
86+
self.execute_remote(cmd)
87+
time.sleep(0.5)
8388
self.logger.info(f"Waiting {self.__exec_timeout}s for command completely executed.")
8489
time.sleep(self.__exec_timeout)
8590

@@ -90,13 +95,13 @@ def queryRegistry(self, keyName):
9095
self.logger.debug(f"Querying registry key: HKLM\\{self.__registry_Path}")
9196
descriptor, _ = self.__iWbemServices.GetObject("StdRegProv")
9297
descriptor = descriptor.SpawnInstance()
93-
retVal = descriptor.GetStringValue(2147483650, self.__registry_Path, keyName)
98+
retVal = descriptor.GetStringValue(0x80000002, self.__registry_Path, keyName)
9499
self.__outputBuffer = base64.b64decode(retVal.sValue).decode(self.__codec, errors="replace").rstrip("\r\n")
95100
except Exception:
96101
self.logger.fail("WMIEXEC: Could not retrieve output file, it may have been detected by AV. Please try increasing the timeout with the '--exec-timeout' option. If it is still failing, try the 'smb' protocol or another exec method")
97102

98103
try:
99104
self.logger.debug(f"Removing temporary registry path: HKLM\\{self.__registry_Path}")
100-
retVal = descriptor.DeleteKey(2147483650, self.__registry_Path)
105+
retVal = descriptor.DeleteKey(0x80000002, self.__registry_Path)
101106
except Exception as e:
102107
self.logger.debug(f"Target: {self.__target} removing temporary registry path error: {e!s}")

0 commit comments

Comments
 (0)