Skip to content

Commit

Permalink
fixed error with ls of an individual file. added task sched interval
Browse files Browse the repository at this point in the history
  • Loading branch information
ghost-ng committed Jan 12, 2024
1 parent 68fc840 commit 8b9365b
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 33 deletions.
3 changes: 0 additions & 3 deletions TODO..md
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
### File System
- recursive ls
- ls a single file
- rm with wildcard

### Task Scheduler
- all in one (create, execute, delete)
- add task run modifiers (run every X min/hour)
- load task xml

### Registry
Expand Down
2 changes: 1 addition & 1 deletion src/slingerpkg/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = '0.4.0'
__version__ = '0.5.0'
__package__ = 'slinger'
7 changes: 2 additions & 5 deletions src/slingerpkg/lib/dcetransport.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,8 @@ def _create_task(self, task_name, folder_path, task_xml):
flags = tsch.TASK_CREATE | tsch.TASK_FLAG_SYSTEM_REQUIRED | tsch.TASK_FLAG_HIDDEN
sddl = '' # Security descriptor definition language string (empty string for default permissions)
abs_path = folder_path + "\\" + task_name
abs_path = abs_path .replace(r'\\', chr(92))
print_log(f"Creating Task: {abs_path}")
# Register the task
# tsch.hSchRpcRegisterTask(dce, '\\%s' % tmpName, xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE)

abs_path = abs_path.replace(r'\\', chr(92))

response = tsch.hSchRpcRegisterTask(self.dce, abs_path, task_xml, tsch.TASK_CREATE, NULL, tsch.TASK_LOGON_NONE)
return response

Expand Down
97 changes: 90 additions & 7 deletions src/slingerpkg/lib/schtasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,27 @@ def task_create(self, args):
arguments = args.arguments
folder_path = args.folder
# generate random date in last year using format 2023-01-01T08:00:00
new_date = generate_random_date()
task_xml = f"""<?xml version="1.0" encoding="UTF-16"?>

if args.date:
new_date = reformat_datetime(args.date)
else:
new_date = generate_random_date()

interval = None
if args.interval:
#if less than 60, -> PT_M
#if greater than 60, -> PT_H
if int(args.interval) % 60 == 0:
h = int(args.interval) / 60
interval = f"PT{h}H"
elif int(args.interval) < 60:
interval = f"PT{args.interval}M"
else:
h = round(int(args.interval) / 60)
m = int(args.interval) % 60
interval = f"PT{h}H{m}M"

task_xml_once = f"""<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>{new_date}</Date>
Expand Down Expand Up @@ -229,21 +248,84 @@ def task_create(self, args):
</Actions>
</Task>
"""

task_xml_interval = f"""<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>{new_date}</Date>
<Author>SYSTEM</Author>
<URI>{folder_path}\{task_name}</URI>
</RegistrationInfo>
<Triggers>
<CalendarTrigger>
<Repetition>
<Interval>{interval}</Interval>
<StopAtDurationEnd>false</StopAtDurationEnd>
</Repetition>
<StartBoundary>{new_date}</StartBoundary>
<Enabled>true</Enabled>
<ScheduleByDay>
<DaysInterval>1</DaysInterval>
</ScheduleByDay>
</CalendarTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>S-1-5-18</UserId>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>true</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>{program}</Command>
<Arguments>{xml_escape(arguments)}</Arguments>
</Exec>
</Actions>
</Task>
"""
task_xml = task_xml_interval if args.interval else task_xml_once
#validate_xml(task_xml)
self.setup_dce_transport()
self.dce_transport._connect('atsvc')

print_info(f"Creating task '{task_name}' in folder '{folder_path}'")

print_info("Using Program: " + program)
print_info("Using Arguments: " + arguments)
print_info("Task XML:")
print_log(task_xml)
print_info("Using Date: " + new_date)
print_info("Using Interval: " + interval if args.interval else "Using Interval: None")
print_debug("Task XML:")
print_debug(task_xml)
abs_path = folder_path + "\\" + task_name
abs_path = abs_path.replace(r'\\', chr(92))
print_log(f"Creating Task: {abs_path}")
try:
response = self.dce_transport._create_task(task_name, folder_path, task_xml)
except Exception as e:
if "ERROR_ALREADY_EXISTS" in str(e):
print_warning(f"Task '{task_name}' already exists in folder '{folder_path}'")
return
else:
print_bad(f"Error creating task '{task_name}': {e}")
return

if response['ErrorCode'] == 0:
print_log(f"Task '{task_name}' created successfully.")
Expand Down Expand Up @@ -313,10 +395,11 @@ def task_show_handler(self, args):

if not self.folder_list_dict and args.taskid:
print_warning("No tasks have been enumerated. Run enumtasks first.")
else:
elif args.task_path:
task_arg = args.taskid if args.taskid else args.task_path
self.view_task_details(task_arg)

else:
print_warning("No task specified. Use taskshow -i <taskid> or taskshow <name> to specify a task.")

def task_manager(self):
pass
Expand Down
44 changes: 31 additions & 13 deletions src/slingerpkg/lib/smblib.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ def rm_handler(self, args):
if args.remote_path == "." or args.remote_path == "" or args.remote_path is None:
print_warning("Please specify a file to remove.")
return
if args.remote_path == "*":
# get file listing
list_path = self.relative_path + '\\*' if self.relative_path else '*'
files = self.conn.listPath(self.share, list_path)
for f in files:
if f.is_directory() and f.get_longname() in ['.', '..']:
continue
path = ntpath.normpath(ntpath.join(self.relative_path, f.get_longname()))
print_debug(f"Removing file {path}")
self.conn.deleteFile(self.share, path)
print_info(f"File Removed {path}")
return
path = ntpath.normpath(ntpath.join(self.relative_path, args.remote_path))

if self.check_if_connected():
Expand Down Expand Up @@ -141,16 +153,18 @@ def update_current_path(self):
self.current_path = ntpath.normpath(self.share + "\\" + self.relative_path)

# validate the directory exists
def is_valid_directory(self, path):
def is_valid_directory(self, path, print_error=True):
list_path = path + '\\*' if path else '*'
try:
self.conn.listPath(self.share, list_path)
return True
except Exception as e:
if "STATUS_STOPPED_ON_SYMLINK" in str(e):
print_warning(f"Remote directory {path} is a symlink.")
if print_error:
print_warning(f"Remote directory {path} is a symlink.")
elif "STATUS_NOT_A_DIRECTORY" in str(e):
print_warning(f"Remote object {path} is not a directory.")
if print_error:
print_warning(f"{path} is not a directory.")

print_debug(f"Failed to list directory {path} on share {self.share}: {e}", sys.exc_info())
return False
Expand Down Expand Up @@ -328,16 +342,17 @@ def dir_list(self, args=None):
path = os.path.normpath(os.path.join(self.relative_path,path))


if not self.is_valid_directory(path):
print_bad(f"Invalid directory: {path}")
return
#if not self.is_valid_directory(path):
# print_bad(f"Invalid directory: {path}")
#return

dirList = []
if self.share is None:
print_warning("No share is connected. Use the 'use' command to connect to a share.")
return

try:
list_path = path + '\\*' if path else '*'
if not self.is_valid_directory(path, print_error=False) and "\\" not in path:
list_path = path
else:
list_path = path + '\\*' if path else '*'
files = self.conn.listPath(self.share, list_path)
for f in files:
creation_time = (datetime.datetime(1601, 1, 1) + datetime.timedelta(microseconds=f.get_ctime()/10)).replace(microsecond=0)
Expand All @@ -358,7 +373,7 @@ def dir_list(self, args=None):
suffix = ""
else:
suffix = path + "\\"
print_info("Showing directory listing for: " + os.path.normpath(self.share + "\\" + suffix))
print_debug("Showing file listing for: " + os.path.normpath(self.share + "\\" + suffix))

# get sort option from arg.sort
sort_option = args.sort
Expand Down Expand Up @@ -391,5 +406,8 @@ def dir_list(self, args=None):

print_log(tabulate(dirList, headers=['Attribs', 'Created', 'LastAccess', 'LastWrite', 'Size', 'Name'], tablefmt='psql'))
except Exception as e:
print_debug(f"Failed to list directory {path} on share {self.share}: {e}", sys.exc_info())
print_bad(f"Failed to list directory {path} on share {self.share}: {e}")
if "STATUS_NO_SUCH_FILE" in str(e):
print_warning(f"Invalid directory or file: {path}")
else:
print_debug(f"Failed to list file or directory {path} on share {self.share}: {e}", sys.exc_info())

10 changes: 6 additions & 4 deletions src/slingerpkg/utils/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def setup_cli_parser(slingerClient):
parser_taskenum = subparsers.add_parser('enumtasks', help='Enumerate scheduled tasks', description='Enumerate scheduled tasks on the remote server', epilog='Example Usage: enumtasks', aliases=['tasksenum','taskenum'])
parser_taskenum.set_defaults(func=slingerClient.enum_task_folders_recursive)
# Subparser for 'tasksshow' command
parser_taskshow = subparsers.add_parser('tasksshow', help='Show task details', description='Show details of a specific task on the remote server', epilog='Example Usage: tasksshow -i 123', aliases=['taskshow','showtask'])
parser_taskshow = subparsers.add_parser('taskshow', help='Show task details', description='Show details of a specific task on the remote server', epilog='Example Usage: tasksshow -i 123', aliases=['tasksshow','showtask'])
taskshowgroup = parser_taskshow.add_mutually_exclusive_group(required=True)
taskshowgroup.add_argument('-i', '--taskid', type=int, help='Specify the ID of the task to show')
taskshowgroup.add_argument('task_path', type=str, nargs='?', help='Specify the full path of the task to show')
Expand All @@ -220,9 +220,11 @@ def setup_cli_parser(slingerClient):
# Subparser for 'taskcreate' command
parser_taskcreate = subparsers.add_parser('taskcreate', help='Create a new task', description='Create a new scheduled task on the remote server', epilog="Example Usage: taskcreate -n newtask -p cmd.exe -a '/c ipconfig /all > C:\\test' -f \\\\Windows", aliases=['taskadd'], formatter_class=argparse.RawDescriptionHelpFormatter)
parser_taskcreate.add_argument('-n', '--name', required=True, help='Specify the name of the new task')
parser_taskcreate.add_argument('-p', '--program', required=True, help='Specify the program to run in the task')
parser_taskcreate.add_argument('-a', '--arguments', required=True, help='Specify the arguments to pass to the program')
parser_taskcreate.add_argument('-f', '--folder', required=True, default="\\", help='Specify the folder to create the task in')
parser_taskcreate.add_argument('-p', '--program', required=True, help='Specify the program to run (cmd.exe)')
parser_taskcreate.add_argument('-a', '--arguments', required=False, help='Specify the arguments to pass to the program')
parser_taskcreate.add_argument('-f', '--folder', required=False, default="", help='Specify the folder to create the task in')
parser_taskcreate.add_argument('-i', '--interval', required=False, default=None, help='Specify an interval in minutes to run the task')
parser_taskcreate.add_argument('-d', '--date', required=False, default=None, help='Specify the date to start the task (2099-12-31 14:01:00)')
parser_taskcreate.set_defaults(func=slingerClient.task_create)

# Subparser for 'taskrun' command
Expand Down
12 changes: 12 additions & 0 deletions src/slingerpkg/utils/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ def generate_random_date(lower_time_bound=None):
random_date = lower_time_bound + datetime.timedelta(seconds=random_second)
return random_date.strftime("%Y-%m-%dT%H:%M:%S")

def reformat_datetime(datetime_str):
original_format = "%Y-%m-%d %H:%M:%S" # Assuming the original format is "%Y-%m-%d %H:%M:%S"
new_format = "%Y-%m-%dT%H:%M:%S" # Desired format "%Y-%m-%dT%H:%M:%S"

# Parse the original datetime string
dt = datetime.datetime.strptime(datetime_str, original_format)

# Convert the datetime object to the desired format
formatted_datetime = dt.strftime(new_format)

return formatted_datetime

def xml_escape(data):
replace_table = {
"&": "&amp;",
Expand Down

0 comments on commit 8b9365b

Please sign in to comment.