def create_hive_case(self, customer, data): create_hive_bool = self.get_hive_cases(customer, data) # Returns if case already merged. if not create_hive_bool: return False # Baseline for creating a case title = ("%s: %s - %s" % (customer.name, str(data["id"]), data["description"])) static_task = "Why did it happen? Check rule.", task_data = self.get_hive_task_data(data) tasks = [ CaseTask(title=static_task) ] if task_data: for item in task_data: tasks.append(CaseTask(title=item)) # Creates a case object case = Case(title=title, tlp=0, flag=False, tags=data["categories"], \ description=data["description"], tasks=tasks) # Creates the actual case based on prior info ret = self.hive.create_case(case) if ret.ok: # FIX, datatype is static self.add_observable_data(ret.json()["id"], create_hive_bool, \ "ip", data, data["categories"]) return True return False
def run(self, case_id, task_name, status): api = TheHiveApiExtended(self.config['thehive_url'], self.config['thehive_api_key']) response = api.get_case_tasks(case_id, query=Eq('title', task_name)) if response.status_code == 200: tasks = response.json() if len(tasks) == 1: task_id = tasks[0]['id'] else: raise ValueError('[ChangeStatusTaskByNameAction]: task not found') else: raise ValueError('[ChangeStatusTaskByNameAction]: tasks status_code %d' % response.status_code) response = api.get_task(task_id) if response.status_code == 200: task_object = response.json() task = CaseTask(json=task_object) task.id = task_id task.status = status task.owner = self.config['thehive_bot_username'] api.update_case_task(task) else: raise ValueError('[ChangeStatusTaskByNameAction]: status_code %d' % response.status_code) return True
def run(self, task_id, status): api = TheHiveApiExtended(self.config['thehive_url'], self.config['thehive_api_key']) response = api.get_task(task_id) if response.status_code == 200: task_object = response.json() task = CaseTask(json=task_object) task.id = task_id task.status = status task.owner = self.config['thehive_bot_username'] api.update_case_task(task) else: raise ValueError('[ChangeStatusTaskAction]: status_code %d' % response.status_code) return True
def __init__(self, event, tenant): # Case attributes user = event['user'] nature = event['nature'] case_name = event['case']['name'] case_id = event['case']['id'] case_url = event['case']['url'] case_tags = ['McAfee Investigator', case_id, nature] # Task attributes task_owner = tenant.hive_user # task_start_date = datetime.datetime.now().strftime("%d-%m-%Y %H:%M") task_start_date = int(time.time()) * 1000 task_description = "Autogenerated task to track MI case events" tasks = [ CaseTask(title='MI - analytics investigation', status='InProgress', owner=task_owner, startDate=task_start_date, description=task_description), CaseTask(title='MI - system events', status='InProgress', owner=task_owner, startDate=task_start_date, description=task_description), CaseTask(title='MI - user events', status='Waiting', description="Auto generated task to track MI user events") ] # Prepare the custom fields (values are searchable) customFields = CustomFieldHelper()\ .add_boolean('MI-autogenerated', True)\ .add_string('MI-caseid', case_id)\ .add_string('MI-user', user)\ .add_string('MI-nature', nature)\ .build() case = Case(title=case_name, tlp=0, flag=False, description="For additional info see " + self.get_case_ui_url(case_url), tags=case_tags, tasks=tasks, customFields=customFields) self.case = case
def run(self, params={}): client = self.connection.client self.logger.info("Input: %s", params) task = CaseTask( title=params.get("task").get("title", None), description=params.get("task").get("description", None), flag=params.get("task").get("flag", False), owner=params.get("task").get("owner", None), status=params.get("task").get("status", None), startDate=params.get("task").get("startDate", None), ) case = Case( title=params.get("title", None), tlp=params.get("tlp", 2), flag=params.get("flag", False), tags=params.get("tags", []), description=params.get("description", None), tasks=[task], customFields=params.get("customFields", None), ) try: new_case = client.create_case(case) new_case.raise_for_status() except requests.exceptions.HTTPError: self.logger.error(new_case.json()) raise except: self.logger.error("Failed to create case") raise return {"case": new_case.json()}
def run(self, params={}): client = self.connection.client self.logger.info('Input: %s', params) task = CaseTask(title=params.get('task').get('title', None), description=params.get('task').get( 'description', None), flag=params.get('task').get('flag', False), owner=params.get('task').get('owner', None), status=params.get('task').get('status', None), startDate=params.get('task').get('startDate', None)) case = Case(title=params.get('title', None), tlp=params.get('tlp', 2), flag=params.get('flag', False), tags=params.get('tags', []), description=params.get('description', None), tasks=[task], customFields=params.get('customFields', None)) try: new_case = client.create_case(case) new_case.raise_for_status() except requests.exceptions.HTTPError: self.logger.error(new_case.json()) raise except: self.logger.error('Failed to create case') raise return {'case': new_case.json()}
async def create_case_task(self, case_id, url, api_key, data=None): self.logger.info(f'Creating task for {case_id} in TheHive...') if not url.startswith("http"): url = f"http://{url}" api = TheHiveApi(url, api_key) results = {} for item in data: try: title = item["title"] description = item["description"] startDate = time.time_ns() // 1000000 task = CaseTask(title=title, description=description, startDate=startDate) r = api.create_case_task(case_id, task) if r.status_code == 201: results[title] = r.json() else: raise IOError(r.text) except Exception as e: self.console_logger.info(f"Failed to create task with input {item} because: {e}") return results
def sendtoHIVE(title, description, domain): tasks = [ CaseTask(title='Tracking'), CaseTask(title='Communication'), CaseTask(title='Investigation', status='Waiting', flag=True) ] # Prepare the custom fields customFields = CustomFieldHelper()\ .add_boolean('booleanField', True)\ .add_string('businessImpact', 'HIGH')\ .add_date('occurDate', int(time.time())*1000)\ .add_number('cvss', 9)\ .build() case = Case(title=title, tlp=3, flag=True, tags=['wordpress', domain], description=description, tasks=tasks, customFields=customFields) # Create the case print('Create Case') print('-----------------------------') id = None response = api.create_case(case) if response.status_code == 201: print(json.dumps(response.json(), indent=4, sort_keys=True)) print('') id = response.json()['id'] else: print('ko: {}/{}'.format(response.status_code, response.text)) sys.exit(0) # Get all the details of the created case print('Get created case {}'.format(id)) print('-----------------------------') response = api.get_case(id) if response.status_code == requests.codes.ok: print(json.dumps(response.json(), indent=4, sort_keys=True)) print('') else: print('ko: {}/{}'.format(response.status_code, response.text))
def craftCommTask(self): self.logger.info('%s.craftCommTask starts', __name__) commTask = CaseTask(title='Communication', status='InProgress', owner='synapse') return commTask
async def update_case_task(self, url, api_key, task_id, title=None, description=None, status=None, flag=None): self.logger.info(f'Updating task {task_id} in TheHive...') if not url.startswith("http"): url = f"http://{url}" api = TheHiveApi(url, api_key) task = CaseTask(**api.get_case_task(task_id).json()) task.id = task_id if title: task.title = title if description: task.description = description if status: task.status = status if flag is not None: task.flag = flag r = api.update_case_task(task) if r.status_code == 200: return r.json() else: raise IOError(r.text)
def run(self, task_id): api = TheHiveApi(self.config['thehive_url'], self.config['thehive_api_key']) response = api.find_tasks(query=Eq('_id', task_id)) if response.status_code == 200: tasks = response.json() if len(tasks) == 1: task = CaseTask(json=tasks[0]) task.id = task_id task.status = 'InProgress' task.owner = self.config['thehive_bot_username'] api.update_case_task(task) else: raise ValueError('[TakeTaskAction]: no tasks with this id') else: raise ValueError('[TakeTaskAction]: status_code %d' % response.status_code) return True
def addTask(self, caseId): response = self.api.create_case_task( caseId, CaseTask(title='Autogenerated Report', startDate=int(time.time()) * 1000)) if response.status_code == 201: return (json.dumps(response.json(), indent=4, sort_keys=True)) else: self.error('ko: {}/{}'.format(response.status_code, response.text))
def do_newtask(self, *_): '''Create a new task within this case''' print("Let's create a new task within this case! The next few steps \ will request some data from you: ") nt_title = input("Task Title: ") nt_description = input("Task Description: ") new_task = CaseTask(title=nt_title, description=nt_description) api = config.get_api() resp = api.create_case_task(self.case_id, new_task) if resp.status_code == 201: print("Successfully created task {0} with the case {1}.".format( nt_title, self.case_name))
def run(self, params={}): client = self.connection.client self.logger.info(params) task = CaseTask( title=params.get("task").get("title", None), description=params.get("task").get("description", None), flag=params.get("task").get("flag", False), owner=params.get("task").get("owner", None), status=params.get("task").get("status", None), ) try: task = client.create_case_task(params.get("id"), task) task.raise_for_status() except requests.exceptions.HTTPError: self.logger.error(task.json()) raise except: self.logger.error("Failed to create task") raise d = task.json() # If API returns None, manually do what the library does elsewhere # https://github.com/CERT-BDF/TheHive4py/blob/master/thehive4py/models.py#L44 if "startDate" in d: if isinstance(d["startDate"], type(None)): d["startDate"] = int(time.time()) * 1000 return {"case": d}
def run(self, job_id, status): task_id = self.action_service.get_value( name='thehive_job_{}'.format(job_id), local=False) api = TheHiveApiExtended(self.config['thehive_url'], self.config['thehive_api_key']) response = api.get_task(task_id) if response.status_code == 200: task_object = response.json() task = CaseTask(json=task_object) task.id = task_id task.status = status task.owner = self.config['thehive_bot_username'] api.update_case_task(task) if status == 'Completed': self.action_service.delete_value( name='thehive_job_{}'.format(job_id), local=False) else: raise ValueError( '[ChangeStatusTaskByJobIdAction]: status_code %d' % response.status_code) return True
def create_case(self, title, tasks=None, tlp=TLP.AMBER, pap=PAP.AMBER, severity=HiveSeverity.MEDIUM, additional_fields=None, additional_tags=None, flag=False, description='N/A'): case_tags = self.case_tags.copy() if additional_tags is not None: for additional_tag in additional_tags: case_tags.append(additional_tag) custom_fields_helper = CustomFieldHelper() if additional_fields is not None: for field in additional_fields: custom_fields_helper.add_string(field['name'], field['value']) custom_fields = custom_fields_helper.build() new_tasks = list() if tasks is not None: for task in tasks: new_tasks.append(CaseTask(title=task)) hive_case = Case(title=title, tlp=tlp.value, pap=pap.value, description=description, tags=case_tags, severity=severity.value, flag=flag, customFields=custom_fields, tasks=new_tasks) response = self.api.create_case(hive_case) if response.status_code == 201: print('Caso Creada Exitosamente') print(json.dumps(response.json(), indent=4, sort_keys=True)) else: print('Error') print(response.text) return response.json()
def playbook_mapper(rules_list, case_num): tasks_dict = (chk_mapping(rules_list)) order_by_count = 0 for k, v in tasks_dict.items(): for items in v: task = CaseTask(group='{}'.format(k), title='{}'.format(items), order=order_by_count) r = hive_api.create_case_task( get_case_by_casenum(case_num)['id'], task) print(r.content) order_by_count += 1 # #Usage: Use a list of rule-groups/attack vectors etc..to map related tasks into the target case #. # Exp: # rule_list = ['Initial Access', 'Drive-by Compromise'] # playbook_mapper(rule_list, 3)
def main(api): i = 0 while i < (currentNum): check = True string = searchCaseByDescription(threats.json['data'][i]['id']) if string == None and check == True: threat = createKeys(threats.json['data'][i], i) parsed = createAlertDescription(threat, i) case = Case(title=threats.json['data'][i]['description'], tlp=0, pap=0, severity=1, flag=False, tags=[ 'Sentinel One', threats.json['data'][i]['classification'], threats.json['data'][i]['agentOsType'], ], description=parsed, tasks=[ CaseTask( title='Communication', description='Auto Imported Sentinel One Alert', owner='sentinelone', group='default', createdAt=time.time()) ], status='Open', user='******', createdAt=threats.json['data'][i]['createdDate']) response = api.create_case(case) postUpdate(searchCaseByDescription(threats.json['data'][i]['id']), i) if response.status_code == 201: logging.info( json.dumps(response.json(), indent=4, sort_keys=True)) logging.info('') id = response.json()['id'] else: print(check) logging.error('ko: {}/{}'.format(response.status_code, response.text)) i += 1
def submitTheHive(message): ''' Create a new case in TheHive based on the email Return 'TRUE' is successfully processed otherwise 'FALSE' ''' # Decode email msg = email.message_from_bytes(message) # gets full content of the email decode = email.header.decode_header(msg['From'])[0] fromField = str(decode[0]) decode = email.header.decode_header(msg['Subject'])[0] subjectField = str(decode[0]) if args.verbose: print("[INFO] From: %s Subject: %s" % (fromField, subjectField)) attachments = [] observables = [] body = '' bodyMessage = '' for part in msg.walk(): if part.get_content_type() == "text/plain": body = part.get_payload(decode=True).decode() bodyMessage += body observables = searchObservables( body, observables ) # searches the body of the email for supplied observables elif part.get_content_type( ) == "text/html": # if email is html based will search throuh html source code if args.verbose: print("[INFO] Searching for observable in HTML code") html = part.get_payload(decode=True).decode() observables = searchObservables(html, observables) elif part.get_content_type( ) == "application/vnd.ms-excel": #ONLY WORKS FOR .CSV body = part.get_payload(decode=True).decode('UTF-8') observables = searchObservables(body, observables) else: # Extract MIME parts filename = part.get_filename() mimetype = part.get_content_type() if filename and mimetype: if mimetype in config['caseFiles'] or not config['caseFiles']: print("[INFO] Found attachment: %s (%s)" % (filename, mimetype)) # Decode the attachment and save it in a temporary file charset = part.get_content_charset() if charset is None: charset = chardet.detect(bytes(part))['encoding'] fd, path = tempfile.mkstemp(prefix=slugify(filename) + "_") try: with os.fdopen(fd, 'w+b') as tmp: tmp.write(part.get_payload(decode=1)) attachments.append(path) except OSError as e: print("[ERROR] Cannot dump attachment to %s: %s" % (path, e.errno)) return False api = TheHiveApi(config['thehiveURL'], config['thehiveUser'], config['thehivePassword'], { 'http': '', 'https': '' }) # if '[ALERT]' in subjectField: if re.match(config['alertKeywords'], subjectField, flags=0): # # Add observables found in the mail body # artifacts = [] if config['thehiveObservables'] and len(observables) > 0: print("t1") for o in observables: print("t2") artifacts.append( AlertArtifact(dataType=o['type'], data=o['value'])) # # Prepare tags - add alert keywords found to the list of tags # tags = config['alertTags'] match = re.findall(config['alertKeywords'], subjectField) for m in match: tags.append(m) # # Prepare the alert # sourceRef = str(uuid.uuid4())[0:6] alert = Alert( title=subjectField.replace('[ALERT]', ''), tlp=int( config['alertTLP'] ), #setting it blank since custom template allows default color, set it back to tlp = int for conf value tags=tags, description=body, type='external', source=fromField, sourceRef=sourceRef, artifacts=artifacts) # Create the Alert id = None response = api.create_alert(alert) if response.status_code == 201: if args.verbose: print('[INFO] Created alert %s' % response.json()['sourceRef']) else: print('[ERROR] Cannot create alert: %s (%s)' % (response.status_code, response.text)) return False else: # Prepare the sample case tasks = [] for task in config['caseTasks']: tasks.append(CaseTask(title=task)) # Prepare the custom fields customFields = CustomFieldHelper() \ .add_string('from', fromField) \ .add_string('attachment', str(attachments)) \ .build() # If a case template is specified, use it instead of the tasks m = 1 if m == 1: templates = [] for task in config['caseTemplates']: templates.append(task) temptouse = config['caseTemplate'] descrip = re.compile('-"(.+)"') name = re.compile('(.+)-"') for x in templates: z = descrip.search(x) tempVar = name.search(x) searchVar = z.group(1) tempVar = tempVar.group(1) if searchVar in subjectField: print( x ) #if 2 template names in subject, take the latest defined temptouse = tempVar print("TEMPLATE", temptouse) if body: testerVar = False print("body") try: albert = re.compile('Albert Incident #: (\d+)') m = albert.search(body) albertId = m.group(1) print(albertId) customFields = CustomFieldHelper() \ .add_string('from', fromField) \ .add_string('attachment', str(attachments)) \ .add_string('albertId', albertId) \ .build() print(customFields) except: print("albert id doesnt exist") if "Update" in subjectField: #update code testerVar = True print("UPDATE") #INTIAL try: findBodyInfo = re.compile('---((?:.+[\r\n]+)+)---') except: print( "Unable to update, unable to find two '---'s, exiting.." ) sys.exit(0) m = findBodyInfo.search(body) bigGroup = m.group(1) caseId = parseBody("Case Id", bigGroup) print("caseid", caseId) try: caseId = int(caseId) except: print("invalid case id") updateACase(caseId, bigGroup, fromField, attachments) id = None if testerVar == True: print("g") sys.exit(0) #end update code caseTags = [] for tag in config['caseTags']: descripFound = descrip.search(tag) nameFound = name.search(tag) descripFound = descripFound.group(1) nameFound = nameFound.group(1) if descripFound == 'always': caseTags.append(nameFound) elif descripFound in bodyMessage: caseTags.append(nameFound) try: # # Add observables found in the mail body # artifacts = [] if config['thehiveObservables'] and len(observables) > 0: for o in observables: artifacts.append( AlertArtifact(dataType=o['type'], data=o['value'])) # # Prepare tags - add alert keywords found to the list of tags # tags = config['alertTags'] match = re.findall(config['alertKeywords'], subjectField) for m in match: tags.append(m) # # Prepare the alert # sourceRef = str(uuid.uuid4())[0:6] alert = Alert( title=subjectField, tlp=int( config['alertTLP'] ), #setting it blank since custom template allows default color, set it back to tlp = int for conf value tags=caseTags, description=body, type='external', source=fromField, sourceRef=sourceRef, customFields=customFields, severity=None, artifacts=artifacts) except FileExistsError: print( "Error with creating alert, wrong template name or tags?") else: print("") # Create the alert response = api.create_alert(alert) print("Alert being created..") if response.status_code == 201: newID = response.json()['id'] if args.verbose: print('[INFO] Created alert %s' % response.json()['caseId']) if len(attachments) > 0: for path in attachments: observable = CaseObservable( dataType='file', data=[path], tlp=int(config['caseTLP']), ioc=False, tags=config['caseTags'], message='Found as email attachment') response = api.create_case_observable(newID, observable) if response.status_code == 201: if args.verbose: print('[INFO] Added observable %s to case ID %s' % (path, newID)) os.unlink(path) else: print('[WARNING] Cannot add observable: %s - %s (%s)' % (path, response.status_code, response.text)) # # Add observables found in the mail body # if config['thehiveObservables'] and len(observables) > 0: for o in observables: observable = CaseObservable( dataType=o['type'], data=o['value'], tlp=int(config['caseTLP']), ioc=False, tags=caseTags, #switched to custom tags message='Found in the email body') response = api.create_case_observable(newID, observable) if response.status_code == 201: if args.verbose: print( '[INFO] Added observable %s: %s to case ID %s' % (o['type'], o['value'], newID)) else: print( '[WARNING] Cannot add observable %s: %s - %s (%s)' % (o['type'], o['value'], response.status_code, response.text)) else: print('[ERROR] Cannot create case: %s (%s)' % (response.status_code, response.text)) return False return True
def submitTheHive(message): '''Create a new case in TheHive based on the email''' # Decode email msg = email.message_from_bytes(message) decode = email.header.decode_header(msg['From'])[0] fromField = str(decode[0]) decode = email.header.decode_header(msg['Subject'])[0] subjectField = str(decode[0]) if args.verbose: print("[INFO] From: %s Subject: %s" % (fromField, subjectField)) attachments = [] body = '' for part in msg.walk(): if part.get_content_type() == "text/plain": body = part.get_payload(decode=True).decode() else: # Extract MIME parts filename = part.get_filename() mimetype = part.get_content_type() if filename and mimetype: if mimetype in config['caseFiles'] or not config['caseFiles']: print("[INFO] Found attachment: %s (%s)" % (filename, mimetype)) # Decode the attachment and save it in a temporary file charset = part.get_content_charset() if charset is None: charset = chardet.detect(bytes(part))['encoding'] fd, path = tempfile.mkstemp(prefix=slugify(filename) + "_") try: with os.fdopen(fd, 'w+b') as tmp: tmp.write(part.get_payload(decode=1)) attachments.append(path) except OSError as e: print("[ERROR] Cannot dump attachment to %s: %s" % (path, e.errno)) api = TheHiveApi(config['thehiveURL'], config['thehiveUser'], config['thehivePassword'], { 'http': '', 'https': '' }) if '[ALERT]' in subjectField: # Prepare the alert sourceRef = str(uuid.uuid4())[0:6] alert = Alert(title=subjectField.replace('[ALERT]', ''), tlp=int(config['alertTLP']), tags=config['alertTags'], description=body, type='external', source=fromField, sourceRef=sourceRef) # Create the Alert id = None response = api.create_alert(alert) if response.status_code == 201: if args.verbose: print('[INFO] Created alert %s' % response.json()['sourceRef']) else: print('[ERROR] Cannot create alert: %s (%s)' % (response.status_code, response.text)) sys.exit(0) else: # Prepare the sample case tasks = [] for task in config['caseTasks']: tasks.append(CaseTask(title=task)) # Prepare the custom fields customFields = CustomFieldHelper()\ .add_string('from', fromField)\ .add_string('attachment', str(attachments))\ .build() case = Case(title=subjectField, tlp=int(config['caseTLP']), flag=False, tags=config['caseTags'], description=body, tasks=tasks, customFields=customFields) # Create the case id = None response = api.create_case(case) if response.status_code == 201: newID = response.json()['id'] if args.verbose: print('[INFO] Created case %s' % response.json()['caseId']) if len(attachments) > 0: for path in attachments: observable = CaseObservable( dataType='file', data=[path], tlp=int(config['caseTLP']), ioc=False, tags=config['caseTags'], message='Created by imap2thehive.py') response = api.create_case_observable(newID, observable) if response.status_code == 201: if args.verbose: print('[INFO] Added observable %s to case ID %s' % (path, newID)) os.unlink(path) else: print('[ERROR] Cannot add observable: %s - %s (%s)' % (path, response.status_code, response.text)) sys.exit(0) else: print('[ERROR] Cannot create case: %s (%s)' % (response.status_code, response.text)) sys.exit(0) return
def submitTheHive(message): ''' Create a new case in TheHive based on the email Return 'TRUE' is successfully processed otherwise 'FALSE' ''' global log # Decode email msg = email.message_from_bytes(message) decode = email.header.decode_header(msg['From'])[0] if decode[1] is not None: fromField = decode[0].decode(decode[1]) else: fromField = str(decode[0]) decode = email.header.decode_header(msg['Subject'])[0] if decode[1] is not None: subjectField = decode[0].decode(decode[1]) else: subjectField = str(decode[0]) log.info("From: %s Subject: %s" % (fromField, subjectField)) attachments = [] observables = [] # Extract SMTP headers and search for observables parser = HeaderParser() headers = parser.parsestr(msg.as_string()) headers_string = '' i = 0 while i < len(headers.keys()): headers_string = headers_string + headers.keys( )[i] + ': ' + headers.values()[i] + '\n' i += 1 # Temporary disabled # observables = searchObservables(headers_string, observables) body = '' for part in msg.walk(): if part.get_content_type() == "text/plain": try: body = part.get_payload(decode=True).decode() except UnicodeDecodeError: body = part.get_payload(decode=True).decode('ISO-8859-1') observables.extend(searchObservables(body, observables)) elif part.get_content_type() == "text/html": try: html = part.get_payload(decode=True).decode() except UnicodeDecodeError: html = part.get_payload(decode=True).decode('ISO-8859-1') observables.extend(searchObservables(html, observables)) else: # Extract MIME parts filename = part.get_filename() mimetype = part.get_content_type() if filename and mimetype: if mimetype in config['caseFiles'] or not config['caseFiles']: log.info("Found attachment: %s (%s)" % (filename, mimetype)) # Decode the attachment and save it in a temporary file charset = part.get_content_charset() if charset is None: charset = chardet.detect(bytes(part))['encoding'] fd, path = tempfile.mkstemp(prefix=slugify(filename) + "_") try: with os.fdopen(fd, 'w+b') as tmp: tmp.write(part.get_payload(decode=1)) attachments.append(path) except OSerror as e: log.error("Cannot dump attachment to %s: %s" % (path, e.errno)) return False # Cleanup observables (remove duplicates) new_observables = [] for o in observables: if not {'type': o['type'], 'value': o['value']} in new_observables: # Is the observable whitelisted? if isWhitelisted(o['value']): log.debug('Skipping whitelisted observable: %s' % o['value']) else: new_observables.append({ 'type': o['type'], 'value': o['value'] }) log.debug('Found observable %s: %s' % (o['type'], o['value'])) else: log.info('Ignoring duplicate observable: %s' % o['value']) log.info("Removed duplicate observables: %d -> %d" % (len(observables), len(new_observables))) observables = new_observables if config['thehiveAuthMethod'] == 'APIKey': api = TheHiveApi(config['thehiveURL'], config['thehiveAPIKey'], None, { 'http': '', 'https': '' }) else: api = TheHiveApi(config['thehiveURL'], config['thehiveUser'], config['thehivePassword'], { 'http': '', 'https': '' }) # Search for interesting keywords in subjectField: log.debug("Searching for %s in '%s'" % (config['alertKeywords'], subjectField)) if re.match(config['alertKeywords'], subjectField, flags=0): # # Add observables found in the mail body # artifacts = [] if config['thehiveObservables'] and len(observables) > 0: for o in observables: artifacts.append( AlertArtifact(dataType=o['type'], data=o['value'])) # # Prepare tags - add alert keywords found to the list of tags # tags = list(config['alertTags']) match = re.findall(config['alertKeywords'], subjectField) for m in match: tags.append(m) # # Prepare the alert # sourceRef = str(uuid.uuid4())[0:6] alert = Alert(title=subjectField.replace('[ALERT]', ''), tlp=int(config['alertTLP']), tags=tags, description=body, type='external', source=fromField, sourceRef=sourceRef, artifacts=artifacts) # Create the Alert id = None response = api.create_alert(alert) if response.status_code == 201: log.info('Created alert %s' % response.json()['sourceRef']) else: log.error('Cannot create alert: %s (%s)' % (response.status_code, response.text)) return False else: # Prepare the sample case tasks = [] for task in config['caseTasks']: tasks.append(CaseTask(title=task)) # Prepare the custom fields customFields = CustomFieldHelper()\ .add_string('from', fromField)\ .add_string('attachment', str(attachments))\ .build() # If a case template is specified, use it instead of the tasks if len(config['caseTemplate']) > 0: case = Case(title=subjectField, tlp=int(config['caseTLP']), flag=False, tags=config['caseTags'], description=body, template=config['caseTemplate'], customFields=customFields) else:
import time from thehive4py.api import TheHiveApi from thehive4py.models import Case, CustomFieldHelper, CaseTask, CaseObservable #To use this script correctly please configure the following lines file_id = "</path/to/id_file.txt>" api = TheHiveApi('<URL_THE_HIVE>', '<THE_HIVE_API_KEY>') warnings.filterwarnings('ignore') url = 'https://<QRadar_IP_address>/api/siem/offenses?fields=id%2Cstatus%2Cdescription%2Coffense_type%2Coffense_source%2Cmagnitude%2Csource_network%2Cdestination_networks%2Cassigned_to%2Cstart_time%2Cevent_count' headers = {'accept': 'application/json', 'SEC': '<QRADAR_API_KEY>', 'Version': '9.0'} #If you're using JIRA as ticketing platform in the task 'Communication' you can add the URL of your JIRA, else delete the description parameter. tasks = [ CaseTask(title='Tracking'), CaseTask(title='Communication', description= '**[Ticket creation](https://PATH/TO/JIRA/CreateIssue!default.jspa)**'), CaseTask(title='Investigation', status='Waiting', flag=True) ] def OffensesRequest(): #If you're using a selfsigned certificate on your QRadar instance you have to use "verify=false" parameter: response_1 = requests.get(url,headers=headers,verify=False) if (response_1.status_code) == 200: data = response_1.json() last_id = (str((data[0]['id']))) with open(file_id) as f: data_file = f.readlines() if data_file == []: last_line = int(last_id)-1
custom_fields = CustomFieldHelper() custom_fields.add_number('qradar_id', offense_id) custom_fields.add_string('offense_source', offense_source) custom_fields.build() tlp = offense_severity_mapper(offense_magnitude)['sev'] # #Case - Offense summary md. build_desc = """|Offense Summary:|\n|---|\n|Offense Description: {}|\n|Source NW: {}|\n|Destination NW: {}|\n|Source IPs: {}|\n|Local Destination IPs: {}|\n|Remote Destination IPs: {}|\n|Usernames: {}|\n---\nLink to the Offense: {}""".format( offense_desc, offense_src_nw, offense_dst_nw, source_address_list, local_dest_list, remote_dest_list, username_list, offense_link) # #Some sample tasks-response actions for posting in the case. Customize per your reqs. # #TODO: You can also utilize - thehive-playbook-creator - for dynamic task/playbook assignment using your QRadar Rule groups. tasks = [ CaseTask(title='PB:- Phase:Identification'), CaseTask(title='PB: - Phase:Remediation'), CaseTask(title='PB: - Phase:Lessons Learned', status='Waiting', flag=True) ] #Build TheHive Case with custom fields thehive_case = Case(title=offense_desc, tlp=tlp, flag=True, tags=['offense', 'qradar', offense_type_name], description=build_desc, customFields=custom_fields.fields, tasks=tasks)
from __future__ import print_function from __future__ import unicode_literals import requests import sys import json import time from thehive4py.api import TheHiveApi from thehive4py.models import Case, CaseTask, CustomFieldHelper api = TheHiveApi('http://127.0.0.1:9000', '**YOUR_API_KEY**') # Prepare the sample case tasks = [ CaseTask(title='Identify'), CaseTask(title='Contain'), CaseTask(title='Investigate'), CaseTask(title='Eradicate'), CaseTask(title='Recovery'), CaseTask(title='Lessons Learned', status='Waiting', flag=True) ] # Prepare the custom fields customFields = CustomFieldHelper()\ .add_boolean('booleanField', True)\ .add_string('businessImpact', 'HIGH')\ .add_date('occurDate', int(time.time())*1000)\ .add_number('cvss', 9)\ .build()
def craftTask(self, **attributes): self.log.info('%s.craftTask starts', __name__) commTask = CaseTask(**attributes) return commTask
def parse_hooks(self): """ Check for new MISP Alert containing supported IOC to search automatically """ if self.webhook.isNewMispAlert(): logger.info( 'Alert {} has been tagged as MISP and is just created'.format( self.webhook.data['rootId'])) #Check alert for supported ioc types supported_iocs = False for artifact in self.webhook.data['object']['artifacts']: if artifact['dataType'] in self.qr_config[ 'supported_datatypes']: supported_iocs = True #Promote alert to case if there are support ioc types if supported_iocs: alert_id = self.webhook.data['rootId'] casetemplate = "MISP Event" logger.info('Alert {} contains IOCs that are supported'.format( alert_id)) response = self.TheHiveConnector.createCaseFromAlert( alert_id, casetemplate) self.report_action = 'createCase' """ Add timestamps to keep track of the search activity per case (we do not want to keep searching forever) """ #Perform automated Analyzer runs for supported observables in a case that has been created from a MISP alert if self.webhook.isNewMispCase(): logger.info( 'Case {} has been tagged as MISP and is just created'.format( self.webhook.data['rootId'])) #Retrieve caseid caseid = self.webhook.data['object']['id'] #Add customFields firstSearched and lastSearched #Create a Case object? Or whatever it is case = Case() #Add the case id to the object case.id = caseid #Debug output logger.info('Updating case %s' % case.id) #Define which fields need to get updated fields = ['customFields'] #Retrieve all required attributes from the alert and add them as custom fields to the case current_time = int(round(time.time() * 1000)) customFields = CustomFieldHelper()\ .add_date('firstSearched', current_time)\ .add_date('lastSearched', current_time)\ .build() #Add custom fields to the case object case.customFields = customFields #Update the case self.TheHiveConnector.updateCase(case, fields) self.report_action = 'updateCase' """ Start the analyzers automatically for MISP observables that are supported and update the case with a new timestamp """ #Automatically run Analyzers for newly created MISP cases where supported IOC's are present if self.webhook.isNewMispArtifact(): logger.info( 'Case artifact is tagged with "MISP-extern". Checking if observable is of a supported type' ) #Retrieve caseid caseid = self.webhook.data['rootId'] #Retrieve case data case_data = self.TheHiveConnector.getCase(caseid) #List all supported ioc's for the case observable = self.webhook.data['object'] #When supported, start a cortex analyzer for it if observable['dataType'] in self.qr_config['supported_datatypes']: supported_observable = observable['_id'] #Trigger a search for the supported ioc logger.info('Launching analyzers for observable: {}'.format( observable['_id'])) response = self.CortexConnector.runAnalyzer( "Cortex-intern", supported_observable, "IBMQRadar_Search_Manual_0_1") #Add customFields firstSearched and lastSearched #Create a Case object case = Case() #Add the case id to the object case.id = caseid #Debug output logger.info('Updating case %s' % case.id) #Define which fields need to get updated fields = ['customFields'] #Retrieve all required attributes from the alert and add them as custom fields to the case current_time = int(round(time.time() * 1000)) customFields = CustomFieldHelper()\ .add_date('firstSearched', case_data['customFields']['firstSearched']['date'])\ .add_date('lastSearched', current_time)\ .build() #Add custom fields to the case object case.customFields = customFields #Update the case self.TheHiveConnector.updateCase(case, fields) self.report_action = 'updateCase' """ Automatically create a task for a found IOC """ #If the Job result contains a successful search with minimum of 1 hit, create a task to investigate the results if self.webhook.isCaseArtifactJob() and self.webhook.isSuccess( ) and self.webhook.isMisp(): #Case ID caseid = self.webhook.data['rootId'] #Load Case information case_data = self.TheHiveConnector.getCase(caseid) logger.info( 'Job {} is part of a case that has been tagged as MISP case and has just finished' .format(self.webhook.data['object']['cortexJobId'])) #Check if the result count higher than 0 if int( float(self.webhook.data['object']['report']['summary'] ['taxonomies'][0]['value'])) > 0: logger.info( 'Job {} contains hits, checking if a task is already present for this observable' .format(self.webhook.data['object']['cortexJobId'])) #Retrieve case task information response = self.TheHiveConnector.getCaseTasks(caseid) case_tasks = response.json() #Load CaseTask template casetask = CaseTask() #Observable + Link observable = self.webhook.data['object']['artifactId'] observable_link = TheHive.get( 'url' ) + "/index.html#!/case/" + caseid + "/observables/" + self.webhook.data[ 'object']['artifactId'] #Task name casetask.title = "Investigate found IOC with id: {}".format( observable) #Date date_found = time.strftime("%d-%m-%Y %H:%M") case_task_found = False for case_task in case_tasks: #Check if task is present for investigating the new results if casetask.title == case_task['title']: case_task_found = True if not case_task_found: logger.info( 'No task found, creating task for observable found in job {}' .format(self.webhook.data['object']['cortexJobId'])) #Add description casetask.description = "The following ioc is hit in the environment. Investigate the results and act accordingly:\n\n" casetask.description = casetask.description + "{} is seen on {}\n".format( observable_link, date_found) #Check if case is closed if case_data['status'] == "Resolved": #Create a Case object? Or whatever it is case = Case() #Add the case id to the object case.id = caseid logger.info('Updating case %s' % case.id) #Define which fields need to get updated fields = ['status'] #Reopen the case case.status = "Open" #Update the case self.TheHiveConnector.updateCase(case, fields) #Add the case task self.TheHiveConnector.createTask(caseid, casetask) self.report_action = 'createTask'
from __future__ import print_function from __future__ import unicode_literals import requests import sys import json import time from thehive4py.api import TheHiveApi from thehive4py.models import Case, CaseTask, CustomFieldHelper api = TheHiveApi('http://127.0.0.1:9000', '**YOUR_API_KEY**') # Prepare the sample case tasks = [ CaseTask(title='Tracking'), CaseTask(title='Communication'), CaseTask(title='Investigation', status='Waiting', flag=True) ] # Prepare the custom fields customFields = CustomFieldHelper()\ .add_boolean('booleanField', True)\ .add_string('businessImpact', 'HIGH')\ .add_date('occurDate', int(time.time())*1000)\ .add_number('cvss', 9)\ .build() case = Case(title='From TheHive4Py', tlp=3, flag=True,
def submitTheHive(emailFilePath): ''' Create a new case in TheHive based on the email Return 'TRUE' is successfully processed otherwise 'FALSE' ''' global log mailName, mailType = os.path.splitext(emailFilePath) if mailType == ".msg": fromField, subjectField, observables, body, attachments = readMsg(emailFilePath) elif mailType == ".eml": fromField, subjectField, observables, body, attachments = readEml(emailFilePath) # Cleanup observables (remove duplicates) new_observables = [] for o in observables: if not {'type': o['type'], 'value': o['value'] } in new_observables: # Is the observable whitelisted? if isWhitelisted(o['value']): log.debug('Skipping whitelisted observable: %s' % o['value']) else: new_observables.append({ 'type': o['type'], 'value': o['value'] }) log.debug('Found observable %s: %s' % (o['type'], o['value'])) else: log.info('Ignoring duplicate observable: %s' % o['value']) log.info("Removed duplicate observables: %d -> %d" % (len(observables), len(new_observables))) observables = new_observables api = TheHiveApi(config['thehiveURL'], config['thehiveApiKey']) # Search for interesting keywords in subjectField: log.debug("Searching for %s in '%s'" % (config['alertKeywords'], subjectField)) if re.match(config['alertKeywords'], subjectField, flags=0): # # Add observables found in the mail body # artifacts = [] if config['thehiveObservables'] and len(observables) > 0: for o in observables: artifacts.append(AlertArtifact(dataType=o['type'], data=o['value'])) # # Prepare tags - add alert keywords found to the list of tags # tags = list(config['alertTags']) match = re.findall(config['alertKeywords'], subjectField) for m in match: tags.append(m) # # Prepare the alert # sourceRef = str(uuid.uuid4())[0:6] alert = Alert(title=subjectField.replace('[ALERT]', ''), tlp = int(config['alertTLP']), tags = tags, description = body, type = 'external', source = fromField, sourceRef = sourceRef, artifacts = artifacts) # Create the Alert id = None response = api.create_alert(alert) if response.status_code == 201: log.info('Created alert %s' % response.json()['sourceRef']) else: log.error('Cannot create alert: %s (%s)' % (response.status_code, response.text)) return False else: # Prepare the sample case tasks = [] for task in config['caseTasks']: tasks.append(CaseTask(title=task)) # Prepare the custom fields customFields = CustomFieldHelper()\ .add_string('from', fromField)\ .add_string('attachment', str(attachments))\ .build() # If a case template is specified, use it instead of the tasks if len(config['caseTemplate']) > 0: case = Case(title=subjectField, tlp = int(config['caseTLP']), flag = False, tags = config['caseTags'], description = body, template = config['caseTemplate'], customFields = customFields) else:
is_mandatory=True)) createDate = float( configuration.checkAndValidate( result, "date", default=DATE_DEFAULT, is_mandatory=False)) * 1000 createTLP = int( configuration.checkAndValidate(result, "tlp", default=TLP_DEFAULT, is_mandatory=True)) createDescription = configuration.checkAndValidate(result, "description", default="", is_mandatory=True) createTasks = [ CaseTask(title=t) for t in configuration.checkAndValidate( result, "tasks", default=[], is_mandatory=False).split(" ;") ] # create the query from parameters new_case = Case(title=createTitle, severity=createSeverity, tags=createTags, pap=createPAP, startDate=createDate, tlp=createTLP, description=createDescription, tasks=createTasks) logger.info("[THCC-5] Query is: " + str(new_case.jsonify()))
from __future__ import print_function from __future__ import unicode_literals import requests import sys import json import time from thehive4py.api import TheHiveApi from thehive4py.models import Case, CaseTask api = TheHiveApi('http://127.0.0.1:9000', 'username', 'password', {'http': '', 'https': ''}) # Prepare the sample case tasks = [ CaseTask(title='Tracking'), CaseTask(title='Communication'), CaseTask(title='Investigation', status='Waiting', flag=True) ] # tasks = [] case = Case(title='From TheHive4Py', tlp=3, flag=True, tags=['TheHive4Py', 'sample'], description='N/A', tasks=tasks) # Create the case print('Create Case') print('-----------------------------') id = None response = api.create_case(case) if response.status_code == 201: print(json.dumps(response.json(), indent=4, sort_keys=True)) print('') id = response.json()['id']