Skip to content

Commit dbd20cb

Browse files
authored
Merge pull request Pennyw0rth#481 from Kahvi-0/main
schtask_as - Delete task when there is an error
2 parents 08b486d + 801420d commit dbd20cb

2 files changed

Lines changed: 63 additions & 51 deletions

File tree

nxc/modules/schtask_as.py

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import contextlib
12
import os
23
from time import sleep
3-
from datetime import datetime
4+
from datetime import datetime, timedelta
45
from impacket.dcerpc.v5.dtypes import NULL
56
from impacket.dcerpc.v5 import tsch, transport
67
from nxc.helpers.misc import gen_random_string
@@ -91,6 +92,10 @@ def on_admin_login(self, context, connection):
9192
except Exception as e:
9293
if "SCHED_S_TASK_HAS_NOT_RUN" in str(e):
9394
self.logger.fail("Task was not run, seems like the specified user has no active session on the target")
95+
with contextlib.suppress(Exception):
96+
exec_method.deleteartifact()
97+
else:
98+
self.logger.fail(f"Failed to execute command: {e}")
9499

95100

96101
class TSCH_EXEC:
@@ -143,6 +148,18 @@ def __init__(self, target, share_name, username, password, domain, user, cmd, fi
143148
)
144149
self.__rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost)
145150

151+
def deleteartifact(self):
152+
dce = self.__rpctransport.get_dce_rpc()
153+
if self.__doKerberos:
154+
dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
155+
dce.set_credentials(*self.__rpctransport.get_credentials())
156+
dce.connect()
157+
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
158+
dce.bind(tsch.MSRPC_UUID_TSCHS)
159+
self.logger.display(f"Deleting task \\{self.task}")
160+
tsch.hSchRpcDelete(dce, f"\\{self.task}")
161+
dce.disconnect()
162+
146163
def execute(self, command, output=False):
147164
self.__retOutput = output
148165
self.execute_handler(command)
@@ -151,24 +168,20 @@ def execute(self, command, output=False):
151168
def output_callback(self, data):
152169
self.__outputBuffer = data
153170

154-
def get_current_date(self):
155-
# Get current date and time
156-
now = datetime.now()
171+
def get_end_boundary(self):
172+
# Get current date and time + 5 minutes
173+
end_boundary = datetime.now() + timedelta(minutes=5)
157174

158175
# Format it to match the format in the XML: "YYYY-MM-DDTHH:MM:SS.ssssss"
159-
return now.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
176+
return end_boundary.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
160177

161178
def gen_xml(self, command, fileless=False):
162179
xml = f"""<?xml version="1.0" encoding="UTF-16"?>
163180
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
164181
<Triggers>
165-
<CalendarTrigger>
166-
<StartBoundary>{self.get_current_date()}</StartBoundary>
167-
<Enabled>true</Enabled>
168-
<ScheduleByDay>
169-
<DaysInterval>1</DaysInterval>
170-
</ScheduleByDay>
171-
</CalendarTrigger>
182+
<RegistrationTrigger>
183+
<EndBoundary>{self.get_end_boundary()}</EndBoundary>
184+
</RegistrationTrigger>
172185
</Triggers>
173186
<Principals>
174187
<Principal id="LocalSystem">
@@ -224,53 +237,58 @@ def gen_xml(self, command, fileless=False):
224237

225238
def execute_handler(self, command, fileless=False):
226239
dce = self.__rpctransport.get_dce_rpc()
240+
227241
if self.__doKerberos:
228242
dce.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE)
229243

230244
dce.set_credentials(*self.__rpctransport.get_credentials())
231245
dce.connect()
232-
tmpName = gen_random_string(8) if self.task is None else self.task
246+
# Give self.task a random string as name if not already specified
247+
self.task = gen_random_string(8) if self.task is None else self.task
233248
xml = self.gen_xml(command, fileless)
234249

235250
self.logger.info(f"Task XML: {xml}")
236-
taskCreated = False
237-
self.logger.info(f"Creating task \\{tmpName}")
251+
self.logger.info(f"Creating task \\{self.task}")
238252
try:
239253
# windows server 2003 has no MSRPC_UUID_TSCHS, if it bind, it will return abstract_syntax_not_supported
240254
dce.set_auth_level(RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
241255
dce.bind(tsch.MSRPC_UUID_TSCHS)
242-
tsch.hSchRpcRegisterTask(dce, f"\\{tmpName}", xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE)
256+
tsch.hSchRpcRegisterTask(dce, f"\\{self.task}", xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE)
243257
except Exception as e:
244258
if "ERROR_NONE_MAPPED" in str(e):
245259
self.logger.fail(f"User {self.user} is not connected on the target, cannot run the task")
246-
if e.error_code and hex(e.error_code) == "0x80070005":
247-
self.logger.fail("Schtask_as: Create schedule task got blocked.")
248-
if "ERROR_TRUSTED_DOMAIN_FAILURE" in str(e):
260+
with contextlib.suppress(Exception):
261+
tsch.hSchRpcDelete(dce, f"\\{self.task}")
262+
elif e.error_code and hex(e.error_code) == "0x80070005":
263+
self.logger.fail("Create schedule task got blocked.")
264+
with contextlib.suppress(Exception):
265+
tsch.hSchRpcDelete(dce, f"\\{self.task}")
266+
elif "ERROR_TRUSTED_DOMAIN_FAILURE" in str(e):
249267
self.logger.fail(f"User {self.user} does not exist in the domain.")
268+
with contextlib.suppress(Exception):
269+
tsch.hSchRpcDelete(dce, f"\\{self.task}")
270+
elif "SCHED_S_TASK_HAS_NOT_RUN" in str(e):
271+
with contextlib.suppress(Exception):
272+
tsch.hSchRpcDelete(dce, f"\\{self.task}")
273+
elif "ERROR_ALREADY_EXISTS" in str(e):
274+
self.logger.fail(f"Create schedule task failed: {e}")
250275
else:
251-
self.logger.fail(f"Schtask_as: Create schedule task failed: {e}")
276+
self.logger.fail(f"Create schedule task failed: {e}")
277+
with contextlib.suppress(Exception):
278+
tsch.hSchRpcDelete(dce, f"\\{self.task}")
252279
return
253-
else:
254-
taskCreated = True
255-
256-
self.logger.info(f"Running task \\{tmpName}")
257-
tsch.hSchRpcRun(dce, f"\\{tmpName}")
258280

259281
done = False
260282
while not done:
261-
self.logger.debug(f"Calling SchRpcGetLastRunInfo for \\{tmpName}")
262-
resp = tsch.hSchRpcGetLastRunInfo(dce, f"\\{tmpName}")
283+
self.logger.debug(f"Calling SchRpcGetLastRunInfo for \\{self.task}")
284+
resp = tsch.hSchRpcGetLastRunInfo(dce, f"\\{self.task}")
263285
if resp["pLastRuntime"]["wYear"] != 0:
264286
done = True
265287
else:
266288
sleep(2)
267289

268-
self.logger.info(f"Deleting task \\{tmpName}")
269-
tsch.hSchRpcDelete(dce, f"\\{tmpName}")
270-
taskCreated = False
271-
272-
if taskCreated is True:
273-
tsch.hSchRpcDelete(dce, f"\\{tmpName}")
290+
self.logger.info(f"Deleting task \\{self.task}")
291+
tsch.hSchRpcDelete(dce, f"\\{self.task}")
274292

275293
if self.__retOutput:
276294
if fileless:

nxc/protocols/smb/atexec.py

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_LEVEL_PKT_PRIVACY
55
from nxc.helpers.misc import gen_random_string
66
from time import sleep
7+
from datetime import datetime, timedelta
78

89

910
class TSCH_EXEC:
@@ -60,17 +61,20 @@ def execute(self, command, output=False):
6061
def output_callback(self, data):
6162
self.__outputBuffer = data
6263

64+
def get_end_boundary(self):
65+
# Get current date and time + 5 minutes
66+
end_boundary = datetime.now() + timedelta(minutes=5)
67+
68+
# Format it to match the format in the XML: "YYYY-MM-DDTHH:MM:SS.ssssss"
69+
return end_boundary.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
70+
6371
def gen_xml(self, command, fileless=False):
64-
xml = """<?xml version="1.0" encoding="UTF-16"?>
72+
xml = f"""<?xml version="1.0" encoding="UTF-16"?>
6573
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
6674
<Triggers>
67-
<CalendarTrigger>
68-
<StartBoundary>2015-07-15T20:35:13.2757294</StartBoundary>
69-
<Enabled>true</Enabled>
70-
<ScheduleByDay>
71-
<DaysInterval>1</DaysInterval>
72-
</ScheduleByDay>
73-
</CalendarTrigger>
75+
<RegistrationTrigger>
76+
<EndBoundary>{self.get_end_boundary()}</EndBoundary>
77+
</RegistrationTrigger>
7478
</Triggers>
7579
<Principals>
7680
<Principal id="LocalSystem">
@@ -134,7 +138,6 @@ def execute_handler(self, command, fileless=False):
134138
xml = self.gen_xml(command, fileless)
135139

136140
self.logger.debug(f"Task XML: {xml}")
137-
taskCreated = False
138141
self.logger.info(f"Creating task \\{tmpName}")
139142
try:
140143
# windows server 2003 has no MSRPC_UUID_TSCHS, if it bind, it will return abstract_syntax_not_supported
@@ -147,11 +150,6 @@ def execute_handler(self, command, fileless=False):
147150
else:
148151
self.logger.fail(str(e))
149152
return
150-
else:
151-
taskCreated = True
152-
153-
self.logger.info(f"Running task \\{tmpName}")
154-
tsch.hSchRpcRun(dce, f"\\{tmpName}")
155153

156154
done = False
157155
while not done:
@@ -164,10 +162,6 @@ def execute_handler(self, command, fileless=False):
164162

165163
self.logger.info(f"Deleting task \\{tmpName}")
166164
tsch.hSchRpcDelete(dce, f"\\{tmpName}")
167-
taskCreated = False
168-
169-
if taskCreated is True:
170-
tsch.hSchRpcDelete(dce, f"\\{tmpName}")
171165

172166
if self.__retOutput:
173167
if fileless:

0 commit comments

Comments
 (0)