def on_finish(container, summary): phantom.debug('on_finish() called') # This function is called after all actions are completed. # summary of all the action and/or all detals of actions # can be collected here. # summary_json = phantom.get_summary() # if 'result' in summary_json: # for action_result in summary_json['result']: # if 'action_run_id' in action_result: # action_results = phantom.get_action_results(action_run_id=action_result['action_run_id'], result_data=False, flatten=False) # phantom.debug(action_results) qa_overall_result = phantom.get_data(key=keyfile, clear_data=False) qa_overall_result['message'] = qa_overall_result['message'] + '\n\n' + summary # # if qa_overall_result['qa_fail_count'] == 0: if expected_pass_count == qa_overall_result['qa_pass_count']: qa_overall_result['overall_result'] = 'Pass' # set final pass/fail result in on_finish phantom.debug( 'Overall Qa result: {} - Pass: {} - Fail: {} \nMessage: {}'.format(qa_overall_result['overall_result'], qa_overall_result['qa_pass_count'], qa_overall_result['qa_fail_count'], qa_overall_result['message'], )) phantom.save_data(qa_overall_result, key=keyfile) return
def Post_Start_Event_to_Splunk(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None): phantom.debug('post_data_1() called') import platform import uuid # collect data for 'post_data_1' call formatted_data_1 = phantom.get_format_data(name='format_3') parameters = [] splunk_status_index_list = phantom.collect( container, "artifact:*.cef.splunk_status_index") if len(splunk_status_index_list) > 0: splunk_status_index = str(splunk_status_index_list[0]) else: splunk_status_index = "default" splunk_status_source_type_list = phantom.collect( container, "artifact:*.cef.splunk_status_source_type") if len(splunk_status_source_type_list) > 0: splunk_status_source_type = str(splunk_status_source_type_list[0]) else: splunk_status_source_type = "advsim:atr" try: guid = phantom.collect(container, "artifact:*.cef.request")[0] except: guid = uuid.uuid4().hex playbook_info = phantom.get_playbook_info() phantom.save_data(guid, playbook_info[0]['id']) source = playbook_info[0]['name'] data = {} data['msg'] = formatted_data_1 data['guid'] = guid data['playbook_info'] = playbook_info[0] data_json = json.dumps(data) # build parameters list for 'post_data_1' call parameters.append({ 'index': splunk_status_index, 'host': platform.node(), 'source_type': splunk_status_source_type, 'data': data_json, 'source': source, }) phantom.act("post data", parameters=parameters, app={"name": 'Splunk'}, callback=decision_2, name="Post_Start_Event_to_Splunk") return
def pin_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None): import random phantom.debug('pin_1() called') # collect data for 'pin_to_hud_6' call dest_ip_artifacts = filter( lambda x: x[0], phantom.collect2(container=container, datapath=['artifact:*.cef.destinationAddress'])) sorc_ip_artifacts = filter( lambda x: x[0], phantom.collect2(container=container, datapath=['artifact:*.cef.sourceAddress'])) styles = set(["white", "red", "purple"]) pin_name = pin_name_mangle("pin_1", container) pin_id = phantom.get_data(pin_name) if not pin_id: ret_val, message, pin_id = phantom.pin( container=container, message="Affected IPs", data=str(len(dest_ip_artifacts) + len(sorc_ip_artifacts)), pin_type="card_medium", pin_style="white") phantom.debug("new pin_1") else: style = random.sample(styles, 1)[0] phantom.debug(style) ret_val, message = phantom.update_pin( pin_id, message="Affected IPs", data=str(len(dest_ip_artifacts) + len(sorc_ip_artifacts)), pin_style=style) if ret_val: phantom.save_data(pin_id, pin_name) # set container properties for: update_data = {} phantom.update(container, update_data) return
def pin_2(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None): import random phantom.debug('pin_2() called') # collect data for 'pin_to_hud_6' call dest_username = filter( lambda x: x[0], phantom.collect2(container=container, datapath=['artifact:*.cef.destinationUserName'])) sorc_username = filter( lambda x: x[0], phantom.collect2(container=container, datapath=['artifact:*.cef.sourceUserName'])) styles = set(["white", "red", "purple"]) pin_name = pin_name_mangle("pin_2", container) pin_id = phantom.get_data(pin_name) if not pin_id: ret_val, message, pin_id = phantom.pin( container=container, message="Affected Users", data=str(len(dest_username) + len(sorc_username)), pin_type="card_medium", pin_style="purple") phantom.debug("new pin_2") else: # Delete and remake this one, for the sake of demonstration ret_val, message = phantom.delete_pin(pin_id) ret_val, message, pin_id = phantom.pin( container=container, message="Affected Users", data=str(len(dest_username) + len(sorc_username)), pin_type="card_medium", pin_style=random.sample(styles, 1)[0]) if ret_val: phantom.save_data(pin_id, pin_name) # set container properties for: update_data = {} phantom.update(container, update_data) return
def on_start(incident): # lets do VT lookup of file hashes in the artifacts of an incident params = [] hashes = list( set(phantom.collect(incident, 'artifact:*.cef.fileHash', scope='all'))) if len(hashes) > 0: for filehash in hashes: params.append({'hash': filehash}) phantom.act("file reputation", parameters=params, callback=generic_cb) # lets do geo lookup of attacker IPs params = [] attacker_ips = phantom.attacker_ips(incident, scope='all') if len(attacker_ips) > 0: for ip in attacker_ips: params.append({'ip': ip}) key = phantom.save_data(str(params)) phantom.act("geolocate ip", parameters=params, callback=generic_cb, handle=key) return
def _save_data(qa_pass_count=0, qa_fail_count=0, qa_overall_result="Fail", message="", init=False, offset=0): if init: if message == "": message = 'At on_start' qa_overall_result = {'qa_pass_count': 0, 'qa_fail_count': 0, 'overall_result': 'Fail', 'message': message} phantom.save_data(qa_overall_result, key=keyfile) else: with padlock: qa_overall_result = phantom.get_data(key=keyfile, clear_data=False) if len(message) > 0: message = "{}():{}> {}".format(inspect.stack()[1 + offset][3], inspect.stack()[1 + offset][2], message) phantom.debug(message) qa_overall_result['message'] += "\n" + message qa_overall_result['qa_pass_count'] += qa_pass_count qa_overall_result['qa_fail_count'] += qa_fail_count phantom.save_data(qa_overall_result, key=keyfile)
def pin_3(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None): import random phantom.debug('pin_3() called') # collect data for 'pin_to_hud_6' call dest_domain = filter( lambda x: x[0], phantom.collect2(container=container, datapath=['artifact:*.cef.destinationDnsDomain'])) pin_name = pin_name_mangle("pin_3", container) try: most_rcnt_domain = dest_domain[0][0] except: pass else: pin_id = phantom.get_data(pin_name) if not pin_id: ret_val, message, pin_id = phantom.pin( container=container, message="Most Recent Domain", data=most_rcnt_domain, pin_type="card_medium", pin_style="red") phantom.debug("new pin_3") else: ret_val, message = phantom.update_pin(pin_id, message="Most Recent Domain", data=most_rcnt_domain, pin_type="card_medium", pin_style="red") if ret_val: phantom.save_data(pin_id, pin_name) # set container properties for: update_data = {} phantom.update(container, update_data) return
def on_start(email): # #phantom.debug('Email container data:\n {}\n\n'.format(email)) email_to = "email_to@my_enterprise.com" email_from = "*****@*****.**" smtp_asset = "smtp" # these keys are used to save persistent data across the playbook, # they must be unique by rule run ID, otherwise its possible the data # could be clobbered in another playbook running at the same time setupkey = 'setup_data' + str(email['current_rule_run_id']) collectkey = 'collect_data' + str(email['current_rule_run_id']) phantom.save_data([email_to, email_from, smtp_asset], key=setupkey) # collected_results = dict() collected_vault_items = dict() container_owner = "None" container_url = phantom.get_base_url() + 'container/' + str(email['id']) ## # we needed to get the vault_id for the email attachment to be detonated and pass that to the detonate action # so we use phantom.collect to grab the cef field (cs6) where we place the vault_id on the artifact vaultid = phantom.collect(email, 'artifact:*.cef.cs6', scope='new') # if len(vaultid) > 0: # we have at least one item to process # lets grab the owner of the container and make it something useful if blank if email['owner'] == '': container_owner = 'None' else: container_owner = email['owner'] phantom.debug('url: {}'.format(phantom.get_base_url())) email_body = "\nStarted file detonations on container_id: {} - Owner: {}\nURL: {}\nvault_item_info:\n".format(email['id'], container_owner, container_url) for vault_item in vaultid: vaultinfo = phantom.get_vault_item_info(vault_item) for vault_item_info in vaultinfo: collected_vault_items[vault_item] = vault_item_info email_body = email_body + pprint.pformat(vault_item_info, indent=4) + '\n' phantom.act('detonate file', parameters=[{'vault_id':vault_item}], assets=["threatgrid"], callback=detonate_file_cb) email_subject = "Running: Detonating files from ingest" # save modified data phantom.save_data([collected_results, collected_vault_items, container_owner], key=collectkey) # send email phantom.act('send email', parameters=[{ "from" : email_from, "to" : email_to, "subject" : email_subject, "body" : email_body }], assets=[smtp_asset], callback=send_email_cb) else: # no artifacts run on phantom.debug('No artifacts to process, ending on_start without running any actions. \n{}'.format(email)) return
def detonate_file_cb(action, success, email, results, handle): collectkey = 'collect_data' + str(email['current_rule_run_id']) if not success: phantom.debug("Error running detonate action.\n{}".format(json.dumps(results))) return # grab just the results url from the threatgrid return data, perhaps send the entire results dict # later as an email attachment? #result_url = results[0]['action_results'][0]['summary']['results_url'] # get the app run ID, and use it as a key to the dictionary we build with results app_run_id = results[0]['app_run_id'] collected_results, collected_vault_items, container_owner = phantom.get_data(collectkey, clear_data=False) collected_results[app_run_id] = dict() collected_results[app_run_id]['asset'] = results[0]['asset'] collected_results[app_run_id]['message'] = results[0]['message'] collected_results[app_run_id]['summary'] = results[0]['summary'] collected_results[app_run_id]['detonate_summary'] = results[0]['action_results'][0]['summary'] phantom.save_data([collected_results, collected_vault_items, container_owner], key=collectkey) return
def get_system_info_1(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None): #phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) # collect data for 'get_system_info_1' call filtered_container_data = phantom.collect2( container=container, datapath=[ 'filtered-artifact:*.cef.sourceAddress', 'filtered-artifact:*.id' ], filter_artifacts=filtered_artifacts) phantom.save_data(filtered_container_data, key="rkitdata") parameters = [] # build parameters list for 'get_system_info_1' call for filtered_container_item in filtered_container_data: if filtered_container_item[0]: parameters.append({ 'ip_hostname': filtered_container_item[0], }) if parameters: phantom.act("get system info", parameters=parameters, assets=['carbonblack'], callback=Send_Email_malicious, name="get_system_info_1") else: phantom.error( "'get_system_info_1' will not be executed due to lack of parameters" ) return
def on_start(incident): # lets do VT lookup of file hashes in the artifacts of an incident params = [] hashes = list(set(phantom.collect(incident, 'artifact:*.cef.fileHash', scope='all'))) if len(hashes) > 0: for filehash in hashes: params.append({'hash':filehash}) phantom.act("file reputation", parameters=params, callback=generic_cb) # lets do geo lookup of attacker IPs params = [] attacker_ips = phantom.attacker_ips(incident, scope='all') if len(attacker_ips) > 0: for ip in attacker_ips: params.append({'ip':ip}) key = phantom.save_data(str(params)) phantom.act("geolocate ip", parameters=params, callback=generic_cb, handle=key) return
def pin_4(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None): phantom.debug('pin_4() called') artifacts = phantom.collect(container=container, datapath='artifacts:*', scope='all') artifacts = sorted(artifacts, key=lambda x: x['update_time'], reverse=True) ioc_count = 0 most_recent_ioc = None ioc_types = set() for artifact in artifacts: for key, value in artifact['cef'].iteritems(): value = str(value) ret, ioc_type = is_ioc(value) if ret: if most_recent_ioc is None: most_recent_ioc = value ioc_count += 1 ioc_types.add(ioc_type) pin4_name = pin_name_mangle("pin_4", container) pin5_name = pin_name_mangle("pin_5", container) pin6_name = pin_name_mangle("pin_6", container) pin_id_ioc_cnt = phantom.get_data(pin4_name) pin_id_ioc_rct = phantom.get_data(pin5_name) pin_id_ioc_type = phantom.get_data(pin6_name) if not pin_id_ioc_cnt: ret_val, message, pin_id_ioc_cnt = phantom.pin(container=container, message="IOC Count", data=str(ioc_count), pin_type="card_medium", pin_style="white") else: ret_val, message = phantom.update_pin(pin_id_ioc_cnt, message="IOC Count", data=str(ioc_count), pin_type="card_medium", pin_style="red") if ret_val: phantom.save_data(pin_id_ioc_cnt, pin4_name) if ioc_count: if not pin_id_ioc_rct: ret_val, message, pin_id_ioc_rct = phantom.pin( container=container, message="Most Recent IOC", data=most_recent_ioc, pin_type="card_medium", pin_style="purple") else: ret_val, message = phantom.update_pin(pin_id_ioc_rct, message="Most Recent IOC", data=most_recent_ioc, pin_type="card_medium", pin_style="purple") if ret_val: phantom.save_data(pin_id_ioc_rct, pin5_name) if not pin_id_ioc_type: ret_val, message, pin_id_ioc_type = phantom.pin( container=container, message="IOC Types", data=", ".join(ioc_types)) else: ret_val, message = phantom.update_pin(pin_id_ioc_type, message="IOC Types", data=", ".join(ioc_types)) if ret_val: phantom.save_data(pin_id_ioc_type, pin6_name) return