Skip to content

Commit 6aa7d6a

Browse files
authored
Merge pull request Pennyw0rth#668 from Dfte/main
Upgrade the schtask_as module so that we can upload binaries and execute them
2 parents 9890316 + bb36b6d commit 6aa7d6a

1 file changed

Lines changed: 45 additions & 3 deletions

File tree

nxc/modules/schtask_as.py

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import contextlib
21
import os
2+
import contextlib
33
from time import sleep
44
from datetime import datetime, timedelta
55
from impacket.dcerpc.v5.dtypes import NULL
@@ -13,20 +13,35 @@ class NXCModule:
1313
"""
1414
Execute a scheduled task remotely as a already connected user by @Defte_
1515
Thanks @Shad0wC0ntr0ller for the idea of removing the hardcoded date that could be used as an IOC
16+
Modified by @Defte_ so that output on multiples lines are printed correctly (28/04/2025)
17+
Modified by @Defte_ so that we can upload a custom binary to execute using the BINARY option (28/04/2025)
1618
"""
1719

1820
def options(self, context, module_options):
1921
r"""
22+
BINARY Upload the binary to be executed by CMD
2023
CMD Command to execute
2124
USER User to execute command as
2225
TASK OPTIONAL: Set a name for the scheduled task name
2326
FILE OPTIONAL: Set a name for the command output file
2427
LOCATION OPTIONAL: Set a location for the command output file (e.g. '\tmp\')
28+
29+
Example:
30+
-------
31+
nxc smb <ip> -u <user> -p <password> -M schtask_as -o USER=Administrator CMD=whoami
32+
nxc smb <ip> -u <user> -p <password> -M schtask_as -o USER=Administrator CMD='bin.exe --option' BINARY=bin.exe
2533
"""
26-
self.cmd = self.user = self.task = self.file = self.location = self.time = None
34+
self.cmd = self.binary = self.user = self.task = self.file = self.location = self.time = None
35+
self.share = "C$"
36+
self.tmp_dir = "C:\\Windows\\Temp\\"
37+
self.tmp_share = self.tmp_dir.split(":")[1]
38+
2739
if "CMD" in module_options:
2840
self.cmd = module_options["CMD"]
2941

42+
if "BINARY" in module_options:
43+
self.binary = module_options["BINARY"]
44+
3045
if "USER" in module_options:
3146
self.user = module_options["USER"]
3247

@@ -47,13 +62,32 @@ def options(self, context, module_options):
4762

4863
def on_admin_login(self, context, connection):
4964
self.logger = context.log
65+
5066
if self.cmd is None:
5167
self.logger.fail("You need to specify a CMD to run")
5268
return 1
69+
5370
if self.user is None:
5471
self.logger.fail("You need to specify a USER to run the command as")
5572
return 1
5673

74+
if self.binary:
75+
if not os.path.isfile(self.binary):
76+
self.logger.fail(f"Cannot find {self.binary}")
77+
return 1
78+
else:
79+
self.logger.display(f"Uploading {self.binary}")
80+
with open(self.binary, "rb") as binary_to_upload:
81+
try:
82+
self.binary_name = os.path.basename(self.binary)
83+
connection.conn.putFile(self.share, f"{self.tmp_share}{self.binary_name}", binary_to_upload.read)
84+
self.logger.success(f"Binary {self.binary_name} successfully uploaded in {self.tmp_share}{self.binary_name}")
85+
except Exception as e:
86+
self.logger.fail(f"Error writing file to share {self.tmp_share}: {e}")
87+
return 1
88+
89+
# Returnes self.cmd or \Windows\temp\BinToExecute.exe depending if BINARY=BinToExecute.exe
90+
self.cmd = self.cmd if not self.binary else f"{self.tmp_share}{self.cmd}"
5791
self.logger.display("Connecting to the remote Service control endpoint")
5892
try:
5993
exec_method = TSCH_EXEC(
@@ -87,7 +121,8 @@ def on_admin_login(self, context, connection):
87121
# Required to decode specific French characters otherwise it'll print b"<result>"
88122
output = output.decode("cp437")
89123
if output:
90-
self.logger.highlight(output)
124+
for line in output.splitlines():
125+
self.logger.highlight(line.rstrip())
91126

92127
except Exception as e:
93128
if "SCHED_S_TASK_HAS_NOT_RUN" in str(e):
@@ -96,6 +131,13 @@ def on_admin_login(self, context, connection):
96131
exec_method.deleteartifact()
97132
else:
98133
self.logger.fail(f"Failed to execute command: {e}")
134+
finally:
135+
if self.binary:
136+
try:
137+
connection.conn.deleteFile(self.share, f"{self.tmp_share}{self.binary_name}")
138+
context.log.success(f"Binary {self.binary_name} successfully deleted")
139+
except Exception as e:
140+
context.log.fail(f"Error deleting {self.binary_name} on {self.share}: {e}")
99141

100142

101143
class TSCH_EXEC:

0 commit comments

Comments
 (0)