def execute(event): #queryResults = None #timestamp, srcIP, dstIP, signature = None, None, None, None def set_sID_cID(): if hasattr(event, 'sguilID'): event.setAttribute('sguilID', prompt='Alert ID', header= '', force=True) else: event.setAttribute('sguilID', prompt='Alert ID', header="Sguil Initial Indicator") event.setAttribute('alertID', event.sguilID, force=True) event.setAttribute('alertType', 'Sguil', force=True) try: splitID = event.sguilID.split('.') event.setAttribute('_sID', value=splitID[0], force=True) event.setAttribute('_cID', value=splitID[1], force=True) query = 'SELECT timestamp, INET_NTOA(src_ip), INET_NTOA(dst_ip), signature FROM event WHERE sid in (%s) AND cid in (%s);' % (event._sID, event._cID) log.debug('msg="MySQL query statement for alert id" alertID="%s" query="%s"' % (event.sguilID, query)) queryResults = getSguilSql('SELECT timestamp, INET_NTOA(src_ip), INET_NTOA(dst_ip), signature FROM event WHERE sid in (%s) AND cid in (%s);' % (event._sID, event._cID), sguilserver=SGUIL_SERVER, tableSplit=True) return queryResults[-1] except(IndexError): print('Invalid AlertID or DB Error. Try again.\n') return set_sID_cID() timestamp, srcIP, dstIP, signature = set_sID_cID() event.setOutPath(event.sguilID) # Note the utc offset for the US will always be -x so by adding the offset you are adding a negative, i.e. subtracting # This is very important for accurate time conversion. You should always add the offset if the time is in UTC and # subtract the offset if the time is local. If the reverse makes more sense to you, event._absUTCOffsetTimeDelta # is available # Also note, setEventDateTime is called twice to initialize utcOffsetTimeDelta then adjust. event.setEventDateTime(datetime.datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S')) event.setEventDateTime(event._DT + event._utcOffsetTimeDelta) print('\nLocal Timestamp Source IP Destination IP Signature') print('-' * 80) print('%-20s %-16s %-16s %s\n' % (event._DT.strftime('%Y-%m-%d %H:%M:%S'), srcIP, dstIP, signature)) event.setAttribute('Event_Date/Time', event._DT.strftime('%Y-%m-%d %H:%M:%S')) ans = getUserInWithDef('Track source or destination (s/d)', 's') if 's' in ans: event.setAttribute('ip_address', srcIP) elif 'd' in ans: event.setAttribute('ip_address', dstIP) else: event.setAttribute('ip_address', prompt='IP Address', default=ans, description='Neither the source or destination was chosen, please confirm.') print('') event.setAttribute('description', prompt='Description', default=signature) event.setDateRange()
def setEventDateTime(self, dt=None): if dt: self.Date = dt.strftime('%Y-%m-%d') self.Time = dt.strftime('%H:%M:%S') self._DT = dt else: printStatusMsg("Event Date & Time") default = self._DT.strftime('%Y-%m-%d %H:%M:%S') userDate = getUserInWithDef("Event Date/Time", default) try: if userDate != default: self._DT = datetime.datetime.strptime(userDate, '%Y-%m-%d %H:%M:%S') self.Date = self._DT.strftime('%Y-%m-%d') self.Time = self._DT.strftime('%H:%M:%S') except(ValueError): print("Error: Invalid input. Try again.") self.setEventDateTime() self.setAttribute('eventDT', self._DT.strftime('%Y-%m-%d %H:%M:%S')) self.setAttribute('eventEpoch', datetimeToEpoch(self._DT)) self._localTZ = self._configs['cirta']['settings']['TIMEZONE'] self._utcOffsetTimeDelta = pytz.timezone(self._localTZ).localize(datetime.datetime(self._DT.year, self._DT.month, self._DT.day)).utcoffset() self._absUTCOffsetTimeDelta = abs(self._utcOffsetTimeDelta)
def checkPath(filePath): proposedPath = getUserInWithDef('Path', filePath) existingFiles = glob.glob(proposedPath + '.*') if not existingFiles: return proposedPath else: try: with open(existingFiles[0], 'a'): log.warn('Warning: files with this base path exist. Proceeding will very likely overwrite a previous run.') if getUserInWithDef('Proceed? (Yes/No)', 'No') in YES: return proposedPath else: print('') return checkPath(filePath) except(IOError): log.warn('Warning: files with this base path exist. You are not able to overwrite, please modify and try again.') return checkPath(filePath)
def priority(self): priorities = [["1", "High"], ["3", "Normal"], ["5", "Low"]] print("\n-------------------") print("| Priorities |") print("-------------------") i = 1 for prior in priorities: print("[%d] %s" % (i, prior[1])) i += 1 return map(lambda x: priorities[int(x.strip()) - 1], getUserInWithDef("\nPriority", "2"))[0]
def verifyAttributes(event): for attr in [attr for attr in event._fifoAttrs.values() if attr.verify]: if attr.conflictsExist(): printStatusMsg('Warning: %s Conflicts' % attr.name, 30, '-', color=colors.WARNING) print('\n'.join(["%s --> %s" %(x, y) for x, y in attr.valuesHistory if y is not None])) print('') if attr.value: event.setAttribute(attr.name, getUserInWithDef(attr.formalName, attr.value), force=True) elif attr.alwaysVerify: event.setAttribute(attr.name, getUserIn(attr.formalName, allowBlank=True), force=True)
def setDateRange(self): if self._DT and hasattr(self, '_startDate') and hasattr(self, '_endDate'): return printStatusMsg("Date & Surrounding Days") userDate = getUserInWithDef("Date of interest", self._DT.date().isoformat()) try: if userDate != self._DT.date().isoformat(): self._DT = datetime.datetime.strptime(userDate, '%Y-%m-%d') self._daysBefore = int(getUserInWithDef("Days Before", '0')) self._daysAfter = int(getUserInWithDef("Days After", '0')) self._startDate = self._DT - datetime.timedelta(days=self._daysBefore) self._endDate = self._DT + datetime.timedelta(days=self._daysAfter) if self._endDate > datetime.datetime.today(): print("\nI'm good, but not that good... I can't predict system") print("behavior days into the future, pulling logs up to today.") self._endDate = datetime.datetime.today() except(ValueError): print("Error: Invalid input. Try again.") self.setDateRange()
def setPCAPRange(event): if event._DT and hasattr(event, '_pcapStart') and hasattr(event, '_pcapEnd'): return printStatusMsg("PCAP Date & Time Window") print('Configured Timezone: %s\n' % event._localTZ) if event.adHoc: tz = getUserInWithDef('Timezone (Local/UTC)', 'UTC') else: tz = getUserInWithDef('Timezone (Local/UTC)', 'Local') if not (tz.lower() == 'utc' or tz.lower() == 'local'): print(colors.FAIL + "Error: Invalid timezone, expected UTC or Local. Try again." + colors.ENDC) setPCAPRange(event) return utc = tz.lower() == 'utc' if utc: eventDT = event._DT - event._utcOffsetTimeDelta today = datetime.datetime.today() - event._utcOffsetTimeDelta else: eventDT = event._DT today = datetime.datetime.today() - event._utcOffsetTimeDelta try: event._pcapDT = datetime.datetime.strptime(getUserInWithDef("Date/Time of interest", eventDT.strftime("%Y-%m-%d %H:%M:%S")), '%Y-%m-%d %H:%M:%S') if utc: event._pcapStart = event._pcapDT - datetime.timedelta(minutes=int(getUserInWithDef("Minutes Before", confVars.defaultBefore))) event._pcapEnd = event._pcapDT + datetime.timedelta(minutes=int(getUserInWithDef("Minutes After", confVars.defaultAfter))) else: event._pcapStart = event._pcapDT - datetime.timedelta(minutes=int(getUserInWithDef("Minutes Before", confVars.defaultBefore))) - event._utcOffsetTimeDelta event._pcapEnd = event._pcapDT + datetime.timedelta(minutes=int(getUserInWithDef("Minutes After", confVars.defaultAfter))) - event._utcOffsetTimeDelta if event._pcapEnd > today: print(colors.WARNING + "\nI'm good, but not that good... I can't predict traffic\ninto the future, pulling pcaps up to now." + colors.ENDC) event._pcapEnd = today except(ValueError): print(colors.FAIL + "Error: Invalid input. Try again." + colors.ENDC) setPCAPRange(event) return print('\nPCAP range set from %s to %s' % (event._pcapStart, event._pcapEnd))
def runPrompt(self): if self.header: printStatusMsg(self.header) self.header = None if self.description: if self.multiline: print(self.description + '\n(Ctrl+D to end input)\n') else: print(self.description + '\n') if self.default: if self.multiline: raise EventSetAttributeError("Incompatible argument combination: default can't be used for multiline input mode.") self.setValue(getUserInWithDef(self.prompt, self.default)) elif self.multiline: print(self.prompt) self.setValue(sys.stdin.read()) else: self.setValue(getUserIn(self.prompt))
def detectInputCases(self, text, yes=False, trailingChar='\\b'): modified = text pipeSplit = re.split('\|', text) matches = [re.match(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", x) for x in re.split('\|', text)] if all(matches): if len(matches) == 1: modified = text.replace('.', '\.') + trailingChar else: modified = text.replace('.', '\.',).replace('|', trailingChar + '|') + trailingChar print('\nIP address(es) detected.\nModified: %s\n' % (modified)) if yes or getUserInWithDef('Use modified', 'y') in YES: log.debug('msg="replace text" original="%s" modified="%s"' % (text, modified)) return modified else: return text return text
def execute(event): sp = Splunk(host=SPLUNK_SEARCH_HEAD, port=SPLUNK_SEARCH_HEAD_PORT, username=SPLUNK_SEARCH_HEAD_USERNAME, password=SPLUNK_SEARCH_HEAD_PASSWORD, scheme=SPLUNK_SEARCH_HEAD_SCHEME) if hasattr(event, 'mcAfeeID'): event.setAttribute('mcAfeeID', prompt='McAfee ID', header= '', force=True) else: event.setAttribute('mcAfeeID', prompt='McAfee ID', header="McAfee Initial Indicator") event.setAttribute('alertID', event.mcAfeeID, force=True) event.setAttribute('alertType', 'McAfee', force=True) query = '''search index=mcafee earliest=-30d@d | eval mcafee_id = "mc".substr(detected_timestamp, -5, 2).".".AutoID | search mcafee_id="%s" | head 1 | table detected_timestamp src_ip src_mac dest_ip dest_mac signature category''' % (event.mcAfeeID) print('\nChecking Splunk...'), sys.stdout.flush() results = sp.search(query) print('Done') try: result = results.next() except(StopIteration): log.warn("Error: unable to pull McAfee ID event details from Splunk") exit() event.setOutPath(event.mcAfeeID) timestamp = epochToDatetime(result['detected_timestamp'][:-3]) srcIP = result['src_ip'] srcMAC = result['src_mac'] dstIP = result['dest_ip'] dstMAC = result['dest_mac'] secondaryName = result['signature'] name = result['category'] signature = '%s %s' % (name, secondaryName) # Note the utc offset for the US will always be -x so by adding the offset you are adding a negative, i.e. subtracting # This is very important for accurate time conversion. You should always add the offset if the time is in UTC and # subtract the offset if the time is local. If the reverse makes more sense to you, event._absUTCOffsetTimeDelta # is available # Also note, setEventDateTime is called twice to initialize utcOffsetTimeDelta then adjust. #event.setEventDateTime(datetime.datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S')) event.setEventDateTime(timestamp) event.setEventDateTime(event._DT) print('\nLocal Timestamp Source IP Destination IP Signature') print('-' * 80) print('%-20s %-16s %-16s %s\n' % (event._DT.strftime('%Y-%m-%d %H:%M:%S'), srcIP, dstIP, signature)) event.setAttribute('Event_Date/Time', event._DT.strftime('%Y-%m-%d %H:%M:%S')) ans = getUserInWithDef('Track source or destination (s/d)', 's') if 's' in ans: if srcIP: event.setAttribute('ip_address', srcIP) else: event.setAttribute('ip_address', prompt="\nIP Address") #if srcMAC: # event.setAttribute('mac_address', srcMAC) elif 'd' in ans: if dstIP: event.setAttribute('ip_address', dstIP) else: event.setAttribute('ip_address', prompt="\nIP Address") #if dstMAC: # event.setAttribute('mac_address', dstMAC) else: event.setAttribute('ip_address', prompt='IP Address', default=ans, description='Neither the source or destination was chosen, please confirm.') print('') event.setAttribute('description', prompt='Description', default=signature) event.setDateRange()
def execute(event): def splitAndStrip(raw): return [x.strip() for x in raw.split(',')] #subject = getUserInWithDef('Subject', '%s %s' % (subjectStart, event.Category.split(',')[0])) event.ir_ticket = getUserIn('IR Ticket') toAddress = splitAndStrip(getUserInWithDef('Recipient(s)', confVars.toAddr)) if confVars.cc: cc = [confVars.cc] else: cc = [] if confVars.bcc: bcc = [confVars.bcc] else: bcc = [] mailServer = MailServer(confVars.fromAddr, toAddress, server=confVars.mailServerName) if event.hostname: subjectAdd = "%s - %s" % (event.hostname, event.description) else: subjectAdd = "%s - %s" % (event.ip_address, event.description) subject = getUserInWithDef('Subject', '%s - %s' % (confVars.subject, subjectAdd)) print('') msg = confVars.header eventStage = splitAndStrip(confVars.eventStage) eventDefaultStage = splitAndStrip(confVars.eventDefaultStage) containmentActions = splitAndStrip( confVars.containmentActions) containmentPreferred = splitAndStrip( confVars.containmentPreferred) containmentAlternative = splitAndStrip( confVars.containmentAlternative) containmentTimeline = splitAndStrip( confVars.containmentTimeline) containmentDefaultTimeline = splitAndStrip( confVars.containmentDefaultTimeline) eradicationActions = splitAndStrip( confVars.eradicationActions) eradicationDefaultActions = splitAndStrip( confVars.eradicationDefaultActions) eradicationTimeline = splitAndStrip( confVars.eradicationTimeline) eradicationDefaultTimeline = splitAndStrip( confVars.eradicationDefaultTimeline) event.eventStage = ', '.join(getUserMultiChoice('Current Event Stage', 'Selection', eventStage, numCols=1, default=eventDefaultStage, allowMultiple=False)) event.containmentPreferred = ', '.join(getUserMultiChoice('Preferred Containment', 'Selection', containmentActions, numCols=2, default=containmentPreferred, allowMultiple=True, other=True)) event.containmentAlternative = ', '.join(getUserMultiChoice('Alternative Containment', 'Selection', containmentActions, numCols=2, default=containmentAlternative, allowMultiple=True, other=True)) event.containmentTimeline = ', '.join(getUserMultiChoice('Containment Timeline', 'Selection', containmentTimeline, numCols=2, default=containmentDefaultTimeline, allowMultiple=False, other=True)) event.eradicationActions = ', '.join(getUserMultiChoice('Mitigation Actions', 'Selection', eradicationActions, numCols=1, default=eradicationDefaultActions, allowMultiple=True, other=True)) event.eradicationTimeline = ', '.join(getUserMultiChoice('Mitigation Timeline', 'Selection', eradicationTimeline, numCols=2, default=eradicationDefaultTimeline, allowMultiple=False, other=True)) msg += 'Incident Response Details\n' msg += '------------------------------------------------\n' msg += 'Response Stage -- %s\n\n' % event.eventStage msg += 'Containment Timeline -- %s\n' % event.containmentTimeline msg += 'Containment Preference -- %s\n\n' % event.containmentPreferred msg += 'Containment Alternatives -- %s\n\n' % event.containmentAlternative msg += 'Mitigation Timeline -- %s\n' % event.eradicationTimeline msg += 'Mitigation Action -- %s\n' % event.eradicationActions emailSections = splitAndStrip(confVars.emailSections) for emailSection in emailSections: sectionAttrs = [attr for attr in event._fifoAttrs.values() if attr.value and attr.verify and attr.emailSection == emailSection] if sectionAttrs: msg += '\n%s\n' % emailSection msg += '------------------------------------------------\n' for attr in sectionAttrs: msg += '%s -- %s\n' % (attr.formalName, attr.value) msg += confVars.footer ticketFilePath = event._baseFilePath + '.ticket' f = open(ticketFilePath, 'w') f.write(msg) f.close() subprocess.call(['nano', ticketFilePath]) f = open(ticketFilePath, 'r') msg = f.read() f.close() printStatusMsg('IR Final Ticket', 22, '>', color=colors.HEADER2) print('Subject: %s\n' % subject) print(msg + '\n') printStatusMsg('IR Final Ticket', 22, '<', color=colors.HEADER2) raw_input(colors.BOLDON + "Hit 'Enter' to continue..." + colors.BOLDOFF) printStatusMsg('Email Final Ticket', 22, '-', color=colors.HEADER2) f = open(ticketFilePath, 'w') f.write(msg) f.close() print('From: %s' % confVars.fromAddr) print('To: %s' % ', '.join(toAddress)) if cc: print('CC: %s' % ', '.join(cc)) if bcc: print('BCC: %s' % ', '.join(bcc)) print('Subject: %s\n' % subject) print(msg + '\n') if getUserIn('Send Email?') in YES: if not event._testing: mailServer.sendMail(subject, msg, ccAddr=cc, bccAddr=bcc, prior=priority)
def execute(event): def normMV(prompt, result, field): if result.get(field): value = result[field] if isinstance(value, list): if len(set(value)) > 1: return ", ".join( getUserMultiChoice( prompt, "Selection", list(set(value)), numCols=1, default=[value[-1]], allowMultiple=False ) ) else: return value[0] elif value: return value return "" sp = Splunk( host=SPLUNK_SEARCH_HEAD, port=SPLUNK_SEARCH_HEAD_PORT, username=SPLUNK_SEARCH_HEAD_USERNAME, password=SPLUNK_SEARCH_HEAD_PASSWORD, scheme=SPLUNK_SEARCH_HEAD_SCHEME, ) if not sp.connected: log.warn( "FireEye initializer requires the Splunk API, please ensure your Splunk instance is available for API connections" ) exit() if hasattr(event, "fireID"): event.setAttribute("fireID", prompt="FireEye ID", header="", force=True) else: event.setAttribute("fireID", prompt="FireEye ID", header="FireEye Initial Indicator") event.setAttribute("alertID", event.fireID, force=True) event.setAttribute("alertType", "FireEye", force=True) query = """search index=fireeye earliest_time=-60d | spath output="alert_id" alert.id | spath output="alert_id_mv" "alert{}.id" | eval alert_id = coalesce(alert_id, alert_id_mv) | spath output="alert_product" alert.product | spath output="alert_product_mv" "alert{}.product" | eval alert_product = coalesce(alert_product, alert_product_mv) | spath output="alert_sensor" alert.sensor | spath output="alert_sensor_mv" "alert{}.sensor" | eval alert_sensor = coalesce(alert_sensor, alert_sensor_mv) | spath output="alert_occurred" alert.occurred | spath output="alert_occurred_mv" "alert{}.occurred" | eval alert_occurred = coalesce(alert_occurred, alert_occurred_mv) | spath output="alert_src_ip" alert.src.ip | spath output="alert_src_ip_mv" "alert{}.src.ip" | eval alert_src_ip = coalesce(alert_src_ip, alert_src_ip_mv) | spath output="alert_src_mac" alert.src.mac | spath output="alert_src_mac_mv" "alert{}.src.mac" | eval alert_src_mac = coalesce(alert_src_mac, alert_src_mac_mv) | spath output="alert_dst_ip" alert.dst.ip | spath output="alert_dst_ip_mv" "alert{}.dst.ip" | eval alert_dst_ip = coalesce(alert_dst_ip, alert_dst_ip_mv) | spath output="alert_dst_mac" alert.dst.mac | spath output="alert_dst_mac_mv" "alert{}.dst.mac" | eval alert_dst_mac = coalesce(alert_dst_mac, alert_dst_mac_mv) | spath output="alert_name" alert.name | spath output="alert_name_mv" "alert{}.name" | eval alert_name = coalesce(alert_name, alert_name_mv) | spath output="malware_names" "alert.explanation.malware-detected.malware{}.name" | spath output="malware_names_mv" "alert{}.explanation.malware-detected.malware{}.name" | eval malware_names = coalesce(malware_names, malware_names_mv) | search alert_id="%s" | table alert_occurred alert_product alert_sensor alert_id alert_src_ip alert_src_mac alert_dst_ip alert_dst_mac alert_name malware_names""" % ( event.fireID ) print("\nChecking Splunk..."), sys.stdout.flush() results = sp.search(query) print("Done") try: result = results.next() except (StopIteration): log.warn("Error: unable to pull FireEye ID event details from Splunk") exit() event.setOutPath(event.fireID) product = normMV("Product", result, "alert_product") sensor = normMV("Sensor", result, "alert_sensor") printStatusMsg("%s - %s" % (product, sensor)) occurred = normMV("Occurred", result, "alert_occurred") if "T" in occurred: timestamp = datetime.datetime.strptime(occurred, "%Y-%m-%dT%H:%M:%SZ").strftime("%Y-%m-%d %H:%M:%S") else: timestamp = occurred.split("+")[0] srcIP = normMV("Source IP", result, "alert_src_ip") srcMAC = normMV("Source Mac", result, "alert_src_mac") dstIP = normMV("Destination IP", result, "alert_dst_ip") dstMAC = normMV("Destination Mac", result, "alert_dst_mac") secondaryName = normMV("Secondary Alert Name", result, "malware_names") name = normMV("Alert Name", result, "alert_name") signature = "%s %s" % (name, secondaryName) """ if isinstance(malwareNames, list): secondaryName = ', '.join(getUserMultiChoice('Secondary Alert Name', 'Selection', malwareNames, numCols=1, default=[malwareNames[-1]], allowMultiple=False)) else: secondaryName = malwareNames """ # Note the utc offset for the US will always be -x so by adding the offset you are adding a negative, i.e. subtracting # This is very important for accurate time conversion. You should always add the offset if the time is in UTC and # subtract the offset if the time is local. If the reverse makes more sense to you, event._absUTCOffsetTimeDelta # is available # Also note, setEventDateTime is called twice to initialize utcOffsetTimeDelta then adjust. event.setEventDateTime(datetime.datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")) event.setEventDateTime(event._DT + event._utcOffsetTimeDelta) print("\nLocal Timestamp Source IP Destination IP Signature") print("-" * 80) print("%-20s %-16s %-16s %s\n" % (event._DT.strftime("%Y-%m-%d %H:%M:%S"), srcIP, dstIP, signature)) event.setAttribute("Event_Date/Time", event._DT.strftime("%Y-%m-%d %H:%M:%S")) if "CMS" in product: event.setAttribute("ip_address", prompt="IP Address") else: ans = getUserInWithDef("Track source or destination (s/d)", "s") if "s" in ans: if srcIP: event.setAttribute("ip_address", srcIP) else: event.setAttribute("ip_address", prompt="\nIP Address") # if srcMAC: # event.setAttribute('mac_address', srcMAC) elif "d" in ans: if dstIP: event.setAttribute("ip_address", dstIP) else: event.setAttribute("ip_address", prompt="\nIP Address") # if dstMAC: # event.setAttribute('mac_address', dstMAC) else: event.setAttribute( "ip_address", prompt="IP Address", default=ans, description="Neither the source or destination was chosen, please confirm.", ) print("") event.setAttribute("description", prompt="Description", default=signature) event.setDateRange()
def execute(event): sp = Splunk(host=SPLUNK_SEARCH_HEAD, port=SPLUNK_SEARCH_HEAD_PORT, username=SPLUNK_SEARCH_HEAD_USERNAME, password=SPLUNK_SEARCH_HEAD_PASSWORD, scheme=SPLUNK_SEARCH_HEAD_SCHEME) def createFWObject(): event.setAttribute('cirtaID', prompt='CIRTA ID', header='Quarantine', force=True) query = '''search index=cirta cirta_id=%s level=STATE | head 1 | fields - _raw | table *''' % (event.cirtaID) print('\nChecking Splunk...'), results = sp.search(query) print('Done\n') try: result = results.next() except(StopIteration): log.warn("Error: unable to pull CIRTA ID state from Splunk") exit() if result.get('hostname'): defaultName = 'cmpd-host-' + result.get('hostname') else: defaultName = 'cmpd-host-' + result.get('ip_address') event.setAttribute('fw_object_name', default=defaultName, prompt="Firewall Object Name", force=True) event.setAttribute('ip_address', default=result['ip_address'], prompt="IP to Quarantine", force=True) event.setAttribute('subnet_mask', default='255.255.255.255', prompt="Subnet Mask", force=True) msg = '' for qAttr in [x.strip() for x in quarantineAttrs.split(',') if x if x.strip()]: value = result.get(qAttr.lstrip('_')) if value: event.setAttribute(qAttr, result.get(qAttr.lstrip('_')), force=True) msg += '%s -- %s\n' % (event._fifoAttrs[qAttr].formalName, event._fifoAttrs[qAttr].value) event._baseFilePath = result['baseFilePath'] outfilePath = event._baseFilePath + '.eventd' with open(outfilePath, 'w') as outfile: outfile.write(msg) subprocess.call(['nano', outfilePath]) with open(outfilePath, 'r') as infile: msg = infile.read() firewallObject = '''config vdom edit vd-inet config firewall address edit "%s" set comment "%s" set color 13 set subnet %s %s next end end''' % (event.fw_object_name, msg.replace('"', '').rstrip(), event.ip_address, event.subnet_mask) printStatusMsg('Firewall Object(s)', 22, '>', color=colors.HEADER2) print firewallObject printStatusMsg('Firewall Object(s)', 22, '<', color=colors.HEADER2) return event.fw_object_name, firewallObject def getGroupModifications(fwObjects): query = '''search index=cirta level=INFO msg="quarantine hosts" | head 1 | table _time hosts''' print('\nChecking Splunk...'), results = sp.search(query) print('Done\n') try: result = results.next() originalHosts = [x.strip() for x in result['hosts'].split(',')] hosts = originalHosts[:] hosts.extend(fwObjects.keys()) hosts = set(hosts) except(StopIteration): log.warn("Unable to retrieve previous quarantine hosts from Splunk") hosts = fwObjects.keys() toRemove = getUserMultiChoice("Unquarantine Hosts", "Hosts to Unquarantine", hosts, 2, default=['None'], noneChoice=True) remainingHosts = [host for host in hosts if host not in toRemove] print('') print(colors.BOLDON + "Hosts before: " + colors.BOLDOFF + ' '.join(['"%s"' % x for x in originalHosts])) print(colors.BOLDON + "Hosts to add: " + colors.BOLDOFF + ' '.join(['"%s"' % x for x in fwObjects.keys()])) print(colors.BOLDON + "Hosts to remove: " + colors.BOLDOFF + ' '.join(['"%s"' % x for x in toRemove])) print(colors.BOLDON + "Hosts after: " + colors.BOLDOFF + ' '.join(['"%s"' % x for x in remainingHosts])) event.setAttribute('quarantine_hosts', ' '.join(['"%s"' % x for x in set(remainingHosts)])) groupMods = '''config vdom edit vd-inet config firewall addrgrp edit "grp-infosec-blacklist-hosts" set member %s next end end''' % (event.quarantine_hosts) return groupMods if getUserInWithDef("Reset current quarantine state? (y/n)", "n") in YES: reset = True print(''' This option should be used sparingly. Intended use is to take the command preview output from the Fortigate and paste the existing address object names including quotes. Please note that little, if any, validation is done with this input. (Ctrl+D on empty line to end input)\n''') event.quarantine_hosts = sys.stdin.read().strip() groupModifications = '''config vdom edit vd-inet config firewall addrgrp edit "grp-infosec-blacklist-hosts" set member %s next end end''' % (event.quarantine_hosts) final = '\n' + groupModifications else: reset = False fwObjects = {} name, obj = createFWObject() fwObjects[name] = obj while(getUserIn('Quarantine another device? (y/n)') in YES): name, obj = createFWObject() fwObjects[name] = obj groupModifications = getGroupModifications(fwObjects) final = '\n'.join([x.strip() for x in fwObjects.values()]) final += '\n' + groupModifications printStatusMsg('Final FW Change', 22, '>', color=colors.HEADER2) print final printStatusMsg('Final FW Change', 22, '<', color=colors.HEADER2) if getUserIn('Commit final changes to quarantine state? (y/n)') in YES: #print '''msg="quarantine hosts" hosts="%s"''' % (','.join(event.quarantine_hosts.strip('"').split('" "'))) log.info('''msg="quarantine hosts" hosts="%s"''' % (','.join(event.quarantine_hosts.strip('"').split('" "')))) if not reset: with open(event._baseFilePath + '.fgblock', 'w') as outFile: outFile.write(final)