Skip to content

Commit 4e380b4

Browse files
authored
Update atexec.py
Signed-off-by: Kahvi-0xFF <46513413+Kahvi-0@users.noreply.github.com>
1 parent edb6f90 commit 4e380b4

1 file changed

Lines changed: 49 additions & 58 deletions

File tree

nxc/protocols/smb/atexec.py

Lines changed: 49 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@ def get_end_boundary(self):
8282
return end_boundary.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
8383

8484
def gen_xml(self, command):
85-
global cmdstdout
86-
global cmd_path
8785
#Random setting order to help with detection
8886
settings = [
8987
" <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>",
@@ -107,20 +105,23 @@ def gen_xml(self, command):
107105
random.shuffle(settings2)
108106
randomized_settings2 = "\n".join(settings2)
109107

110-
IdleSettings = [
108+
idleSettings = [
111109
" <StopOnIdleEnd>true</StopOnIdleEnd>",
112110
" <RestartOnIdle>false</RestartOnIdle>"
113111
]
114-
random.shuffle(IdleSettings)
115-
randomized_IdleSettings = "\n".join(IdleSettings)
112+
random.shuffle(idleSettings)
113+
randomized_idleSettings = "\n".join(idleSettings)
116114
random_digit = random.randint(2, 6)
117115

118116
match = re.match(r'^(.+?\\[^\\ ]+)\s+(.*)', command)
119117
if match:
120118
cmd_path = match.group(1)
121119
cmd_args = match.group(2)
122120
else:
123-
print("Could not split the command properly.")
121+
self.logger.display(f"Full Path not detected, defaulting to CMD")
122+
self.__retOutput = True
123+
cmd_path = f"C:\Windows\System32\cmd.exe"
124+
cmd_args = f"/c {command}"
124125

125126
xml = f"""<?xml version="1.0" encoding="UTF-16"?>
126127
<Task version="1.{random_digit}" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
@@ -138,35 +139,29 @@ def gen_xml(self, command):
138139
<Settings>
139140
{randomized_settings}
140141
<IdleSettings>
141-
{randomized_IdleSettings}
142+
{randomized_idleSettings}
142143
</IdleSettings>
143144
{randomized_settings2}
144145
</Settings>
145146
<Actions Context="LocalSystem">
146147
<Exec>
147148
<Command>{cmd_path}</Command>
148149
"""
150+
149151
if self.__retOutput:
150152
file_location = "\\Windows\\Temp\\" if self.output_file_location is None else self.output_file_location
151153
if self.output_filename is None:
152154
self.__output_filename = os.path.join(file_location, gen_random_string(8))
153155
else:
154156
self.__output_filename = os.path.join(file_location, self.output_filename)
155-
156-
if "cmd" in cmd_path.lower() or "powershell" in cmd_path.lower():
157-
cmd_output = f"&gt; {self.__output_filename} 2&gt;&amp;1"
158-
cmdstdout = 1
159-
argument_xml = f" <Arguments>{cmd_args} {cmd_output}</Arguments>"
160-
else:
161-
cmd_output = ""
162-
cmdstdout = 0
163-
argument_xml = f" <Arguments>{cmd_args} {cmd_output}</Arguments>"
157+
158+
cmd_output = f"&gt; {self.__output_filename} 2&gt;&amp;1"
159+
argument_xml = f" <Arguments>{cmd_args} {cmd_output}</Arguments>"
164160

165161

166162
elif self.__retOutput is False:
167163
argument_xml = f" <Arguments>{cmd_args}</Arguments>"
168164

169-
170165
self.logger.debug("Generated argument XML: " + argument_xml)
171166
xml += argument_xml
172167

@@ -186,9 +181,8 @@ def execute_handler(self, command):
186181

187182
dce.set_credentials(*self.__rpctransport.get_credentials())
188183
dce.connect()
189-
190184
xml = self.gen_xml(command)
191-
185+
192186
self.logger.debug(f"Task XML: {xml}")
193187
self.logger.info(f"Creating task \\{self.task_name}")
194188
try:
@@ -216,51 +210,48 @@ def execute_handler(self, command):
216210

217211
self.logger.info(f"Deleting task \\{self.task_name}")
218212
tsch.hSchRpcDelete(dce, f"\\{self.task_name}")
219-
213+
220214
if self.__retOutput:
221215
smbConnection = self.__rpctransport.get_smb_connection()
222216

223217
tries = 1
224218
# Give the command a bit of time to execute before we try to read the output, 0.4 seconds was good in testing
225219
sleep(0.4)
226-
if cmdstdout == 1:
227-
while True:
228-
try:
229-
self.logger.info(f"Attempting to read {self.__share}\\{self.__output_filename}")
230-
smbConnection.getFile(self.__share, self.__output_filename, self.output_callback)
231-
break
232-
except Exception as e:
233-
if tries >= self.__tries:
234-
self.logger.fail("ATEXEC: Could not retrieve output file, it may have been detected by AV. Please increase the number of tries with the option '--get-output-tries'. If it is still failing, try the 'wmi' protocol or another exec method")
235-
break
236-
if "STATUS_BAD_NETWORK_NAME" in str(e):
220+
while True:
221+
try:
222+
self.logger.info(f"Attempting to read {self.__share}\\{self.__output_filename}")
223+
smbConnection.getFile(self.__share, self.__output_filename, self.output_callback)
224+
break
225+
except Exception as e:
226+
if tries >= self.__tries:
227+
self.logger.fail("ATEXEC: Could not retrieve output file, it may have been detected by AV. Please increase the number of tries with the option '--get-output-tries'. If it is still failing, try the 'wmi' protocol or another exec method")
228+
break
229+
if "STATUS_BAD_NETWORK_NAME" in str(e):
237230
self.logger.fail(f"ATEXEC: Getting the output file failed - target has blocked access to the share: {self.__share} (but the command may have executed!)")
238231
break
239-
elif "STATUS_VIRUS_INFECTED" in str(e):
240-
self.logger.fail("Command did not run because a virus was detected")
241-
break
242-
# When executing PowerShell and the command is still running, we get a sharing violation
243-
# We can use that information to wait longer than if the file is not found (probably av or something)
244-
if "STATUS_SHARING_VIOLATION" in str(e):
245-
self.logger.info(f"File {self.__share}\\{self.__output_filename} is still in use with {self.__tries - tries} tries left, retrying...")
246-
tries += 1
247-
sleep(1)
248-
elif "STATUS_OBJECT_NAME_NOT_FOUND" in str(e):
249-
self.logger.info(f"File {self.__share}\\{self.__output_filename} not found with {self.__tries - tries} tries left, deducting 10 tries and retrying...")
250-
tries += 10
251-
sleep(1)
252-
else:
253-
self.logger.debug(f"Exception when trying to read output file: {e!s}. {self.__tries - tries} tries left, retrying...")
254-
tries += 1
255-
sleep(1)
256-
257-
258-
try:
259-
self.logger.debug(f"Deleting file {self.__share}\\{self.__output_filename}")
260-
smbConnection.deleteFile(self.__share, self.__output_filename)
261-
except Exception:
262-
pass
263-
264-
else:
265-
self.logger.display("No output file was saved to be retrived")
232+
elif "STATUS_VIRUS_INFECTED" in str(e):
233+
self.logger.fail("Command did not run because a virus was detected")
234+
break
235+
# When executing PowerShell and the command is still running, we get a sharing violation
236+
# We can use that information to wait longer than if the file is not found (probably av or something)
237+
if "STATUS_SHARING_VIOLATION" in str(e):
238+
self.logger.info(f"File {self.__share}\\{self.__output_filename} is still in use with {self.__tries - tries} tries left, retrying...")
239+
tries += 1
240+
sleep(1)
241+
elif "STATUS_OBJECT_NAME_NOT_FOUND" in str(e):
242+
self.logger.info(f"File {self.__share}\\{self.__output_filename} not found with {self.__tries - tries} tries left, deducting 10 tries and retrying...")
243+
tries += 10
244+
sleep(1)
245+
else:
246+
self.logger.debug(f"Exception when trying to read output file: {e!s}. {self.__tries - tries} tries left, retrying...")
247+
tries += 1
248+
sleep(1)
249+
250+
try:
251+
self.logger.debug(f"Deleting file {self.__share}\\{self.__output_filename}")
252+
smbConnection.deleteFile(self.__share, self.__output_filename)
253+
except Exception:
254+
pass
255+
else:
256+
self.logger.display("No output file was saved to be retrived")
266257
dce.disconnect()

0 commit comments

Comments
 (0)