def get_token(): """ Retrieve the token using the credentials """ demisto_params = demisto.params() said = demisto_params.get('credentials').get('identifier') sasecret = demisto_params.get('credentials').get('password') auth_payload = parse.urlencode({ 'grant_type': 'client_credentials', 'audience': 'beyond-api', 'client_id': said, 'client_secret': sasecret }) response = requests.post("https://auth.wiz.io/oauth/token", headers=HEADERS_AUTH, data=auth_payload) if response.status_code != requests.codes.ok: raise Exception('Error authenticating to Wiz [%d] - %s' % (response.status_code, response.text)) try: response_json = response.json() TOKEN = response_json.get('access_token') if not TOKEN: demisto.debug(json.dumps(response_json)) message = 'Could not retrieve token from Wiz: {}'.format( response_json.get("message")) raise Exception(message) except ValueError as exception: demisto.log(exception) # pylint: disable=E9012 raise Exception('Could not parse API response') HEADERS["Authorization"] = "Bearer " + TOKEN return TOKEN
def remove_identity_key(source): """ this function removes identity key (application, device or user) from LastModifiedBy and CreatedBy keys and convert it to "type" key. :param source: LastModifiedBy and CreatedBy dictionaries :return: camel case dictionary with identity key as type. """ if not isinstance(source, dict): LOG("Input is not dictionary. Exist function.") return source dict_keys = list(source.keys()) if len(dict_keys) != 1: demisto.log("Got more then one identity creator. Exit function") return source identity_key = dict_keys[0] new_source = {} if source[identity_key].get("ID"): new_source["ID"] = source[identity_key].get("ID") new_source["DisplayName"] = source[identity_key].get("DisplayName") new_source["Type"] = identity_key return new_source
def create_new_folder(self, object_type, object_type_id, parent_id, folder_name): """ Create a new folder in a Drive with a specified parent item or path. :param object_type: ms graph resource. :param object_type_id: the selected object type id. :param parent_id: an ID of the Drive to upload the folder to. :param folder_name: folder name :return: graph api raw response """ if object_type == "drives": url = f"{object_type}/{object_type_id}/items/{parent_id}/children" elif object_type in ["groups", "sites", "users"]: url = f"{object_type}/{object_type_id}/drive/items/{parent_id}/children" # send request url = self.base_url + f"/{url}" payload = { "name": folder_name, "folder": {}, "@microsoft.graph.conflictBehavior": "rename", } self.headers["Content-Type"] = "application/json" demisto.log(f"sending POST to {url}, with the next payload: {payload}") return self.http_call( "POST", full_url=url, json_data=payload, headers=self.headers, url_suffix="" )
def __status_and_id(self, status_name: str = None, status_id: str = None) -> Dict: """ :param status_name: the status name for search (the status id) :param status_id: the status id for search (the status name) :return: {"name": <status name>, "id": <status id>} """ if not status_id: looking_for = status_name if status_name else 'Open' looking_in = 'name' else: looking_for = status_id looking_in = 'id' if not self.__cache['status']: def filter_statuses_data(status_dict): try: status_dict.pop('showInCasePane') status_dict.pop('default') except KeyError: pass return status_dict self.__cache['status'] = list( map(filter_statuses_data, (self.get_case_statuses(raw=True))[2])) for status in self.__cache['status']: if status.get(looking_in) == looking_for: return status demisto.log(f'{looking_for} is not a {looking_in}(status).') return {}
def parse_tag_field(tags_str): tags = [] regex = re.compile( r'key=([\w\d_:.-]+),value=([ /\w\d@_,.*-]+)', flags=re.I) if demisto.args().get('tag_key') and demisto.args().get('tag_value'): if demisto.args().get('tags'): return_error( "Please select either the arguments 'tag_key' and 'tag_value' or only 'tags'.") tags.append({ 'Key': demisto.args().get('tag_key'), 'Value': demisto.args().get('tag_value') }) else: if tags_str is not None: for f in tags_str.split(';'): match = regex.match(f) if match is None: demisto.log('could not parse field: %s' % (f,)) continue tags.append({ 'Key': match.group(1), 'Value': match.group(2) }) return tags
def test_close_task_set_context(mocker): demisto.log('stuff') def executeCommand(name, args=None): if name == 'taskComplete': # Success return {} else: raise ValueError('Unimplemented command called: {}'.format(name)) mocker.patch.object(demisto, 'args', return_value={ "entry_id": "waiter", "context_key": "XMatters.UserResponseOut", "comments": "This is a comment" }) # mocker.patch.object(demisto, 'executeCommand', side_effect=executeCommand) mocker.patch.object(demisto, 'results') main() # If we got here we're good. assert True
def __username_and_id(self, user_name: str = None, user_id: str = None) -> Dict: """ :param user_name: the user name for search (the user id) :param user_id: the user id for search (the user name) :return: {"name": <user name>, "id": <user id>} """ if user_name: if user_name.lower() == 'me': user_name = self.__user_name looking_in = 'username' looking_for = user_name elif user_id: looking_in = 'id' looking_for = user_id else: return {} if not self.__cache.get('users'): _, _, self.__cache['users'] = self.get_user_list() for user in self.__cache['users']: if user.get(looking_in) == looking_for: return {'id': user.get('id'), 'name': user.get('username')} demisto.log(f'{looking_for} is not a {looking_in}(user).') return {}
def get_stats_archive(self, job_id): # Get firewall system name, serial number system_info = self.get_system_info() resp = xmltodict.parse(system_info.content) system_name = resp['response']['result']['system']['devicename'] system_serial = resp['response']['result']['system']['serial'] time_stamp = time.strftime(DATE_FORMAT) output_file = str(system_name) + '-' + str(system_serial) + '-' + str( time_stamp) + '-stats_dump.tar.gz' if self.params['ngfw_verbose'] is True: demisto.log('Constructed archive name as: [`' + output_file + '`]') params = { 'type': 'export', 'category': 'stats-dump', 'action': 'get', 'job-id': job_id, 'key': self.api_key } response = self._http_request('GET', 'api', params=params, resp_type='content', proxies=self.proxies, timeout=self.params['ngfw_timeout']) result = {'file_name': output_file, 'file_contents': response} return result
def main(): try: args = demisto.args() pwd_generation_script = args.get("pwdGenerationScript") user_profile = args.get("userProfile") to_email = args.get("email") mapper_in = args.get("mapperIn", DEFAULT_OUTGOING_MAPPER) if not user_profile: # no user was created return # Generate a random password outputs = demisto.executeCommand(pwd_generation_script, {}) password_dict = demisto.get(outputs[0], 'Contents') password = password_dict.get("NEW_PASSWORD") user = demisto.mapObject(json.loads(user_profile), mapper_in, MAPPING_TYPE) user_email = user.get("email") username = user_email.split("@")[0] display_name = user.get("displayname") # setting a new password ad_create_user_arguments = { 'username': username, 'password': password, 'attribute-name': 'pwdLastSet', 'attribute-value': -1 } flow_worked = True password_outputs = demisto.executeCommand("ad-set-new-password", ad_create_user_arguments) if is_error(password_outputs): flow_worked = False return_results(password_outputs) enable_outputs = demisto.executeCommand("ad-enable-account", ad_create_user_arguments) if is_error(enable_outputs): flow_worked = False return_results(enable_outputs) update_outputs = demisto.executeCommand("ad-update-user", ad_create_user_arguments) if is_error(update_outputs): flow_worked = False return_results(update_outputs) if flow_worked: send_email(display_name, username, user_email, password, to_email) return_results("User was enabled and a password was set.") else: return_results("Some commands failed, please check the errors.") except Exception as e: demisto.log(traceback.format_exc()) return_error(str(e))
def portal_check(): ''' Poking to the portal to make sure it's up ''' try: Portal(bearer=API_KEY) return True except Exception: demisto.log(traceback.format_exc()) return False
def get_host_id_from_ip_address(ip_address): ''' Get host ID within Frontline.Cloud given IP address. Host ID used to pull vulnerability data for that specific host. ''' hosts_with_given_ip = get_fvm_data(HOST_ENDPOINT, params={'_0_eq_host_ip_address': str(ip_address)}) if len(hosts_with_given_ip) < 1: msg = 'Host not found within Frontline.Cloud given host IP Address. Host will not be included in querying vulnerabilities' demisto.error('Frontline.Cloud get_host_id_from_ip_address -- ' + msg) # print to demisto log in ERROR demisto.log('Frontline.Cloud get_host_id_from_ip_address -- ' + msg) # print to war room first_relevant_host = hosts_with_given_ip[0] return first_relevant_host.get('id')
def parse_tag_field(tags_str): tags = [] regex = re.compile(r'key=([\w\d_:.-]+),value=([ /\w\d@_,.\*-]+)', flags=re.I) for f in tags_str.split(';'): match = regex.match(f) if match is None: demisto.log('could not parse field: %s' % (f, )) continue tags.append({'Key': match.group(1), 'Value': match.group(2)}) return tags
def get_mssp_sub_accounts(): account_id = demisto.getParam('credentials')['identifier'] accounts = req('GET', 'public/v1/mssp/customers', json_response=True) if not accounts: return_error("intsights-mssp-get-sub-accounts failed to return data.") # Fix accounts _id keys for account in accounts: account["ID"] = account["_id"] del account["_id"] if len(accounts) < 1: return_error('Current MSSP Account has no sub accounts.') account_ids = [i["ID"] for i in accounts] if mssp_account_id not in account_ids: demisto.log("[DEBUG] - MSSP sub accounts:" + str(accounts)) return_error( 'Entered sub account id ({}) is not part of this mssp account'. format(mssp_account_id)) for i, account in enumerate(account_ids): # Call account HEADERS['Account-Id'] = account account_ua = req('GET', 'public/v1/account/used-assets', json_response=True) if not account_ua: continue accounts[i].update(account_ua) demisto.results({ 'Type': entryTypes['note'], 'EntryContext': { 'IntSights.MsspAccount(val.ID === obj.ID)': accounts }, 'HumanReadable': tableToMarkdown( 'IntSights MSSP accounts used assets ' + account_id, [a for a in accounts], ["ID", 'CompanyName', "Status", "AssetsLimit", "AssetsCount"]), 'Contents': accounts, 'ContentsFormat': formats['json'] }) # Restore the header HEADERS['Account-Id'] = mssp_account_id
def parse_response(lst: list): """Convert a Api response to wanted format. Args: lst: A list of dictionaries that return from api call. Returns: converted list of dictionaries from snake case to camel case. """ list_res = [] for dic in lst: context_dict = convert_dict_snake_to_camel(dic) list_res.append(context_dict) demisto.log('log test') return list_res
def main(): try: args = demisto.args() user_profile = args.get("value") title = user_profile.get("title") profile_id = title.get(title) return profile_id except Exception as e: demisto.log(traceback.format_exc()) return_error(str(e))
def parse_subnet_mappings(subnets_str): subnets = [] regex = re.compile(r"subnetid=([\w\d_:.-]+),allocationid=([ /\w\d@_,.*-]+)", flags=re.I) for f in subnets_str.split(';'): match = regex.match(f) if match is None: demisto.log('could not parse field: %s' % (f,)) continue subnets.append({ 'SubnetId': match.group(1), 'AllocationId': match.group(2) }) return subnets
def main(): """ PARSE AND VALIDATE INTEGRATION PARAMS """ params = demisto.params() base_url = params['url'] api_key = params['api_key'] # Flag if use server proxy use_proxy = params.get('proxy', False) # Flag if use server 'verification' insecure = not params.get('insecure', False) headers = { "Authorization": f"Bearer {api_key}" # Replace ${token} with the token you have obtained } demisto.debug(" ---- MAIN CALL -----") demisto.debug(" ---- PARAMS -----") demisto.debug(f"base_url: {base_url}") demisto.debug(f"insecure: {insecure}") demisto.debug(f"use_proxy: {use_proxy}") demisto.info(f'Command being called is: {demisto.command()}') client = Client(base_url=base_url, headers=headers, proxy=use_proxy, verify=insecure) try: # This is the call made when pressing the integration Test button. if demisto.command() == 'test-module': return api_test(client) elif demisto.command() == 'cymptom-get-mitigations': return_results(get_mitigations(client)) elif demisto.command() == 'cymptom-get-users-with-cracked-passwords': return_results(get_users_with_cracked_passwords(client)) # Log exceptions except Exception as e: demisto.log(str(e)) return_error( f'Failed to execute {demisto.command()} command. Error: {str(e)}')
def parse_filter_field(filter_str): filters = [] regex = re.compile(r'name=([\w\d_:.-]+),values=([ /\w\d@_,.*-]+)', flags=re.I) for f in filter_str.split(';'): match = regex.match(f) if match is None: demisto.log('could not parse filter: %s' % (f, )) continue filters.append({ 'Name': match.group(1), 'Values': match.group(2).split(',') }) return filters
def checkAPIerrors(query, variables): if not TOKEN: get_token() data = {"variables": variables, "query": query} try: result = requests.post(url=URL, json=data, headers=HEADERS) except Exception as e: if '502: Bad Gateway' not in str(e) and '503: Service Unavailable' not in str(e): demisto.error("<p>Wiz-API-Error: %s</p>" % str(e)) return(e) else: demisto.log("Retry") return result.json()
def main(): try: args = demisto.args() user_profile = args.get("value") location = user_profile.get("location") timezonesidkey = location_to_timezonesidkey.get(location) if not timezonesidkey: timezonesidkey = location_default return timezonesidkey except Exception as e: demisto.log(traceback.format_exc()) return_error(str(e))
def xmlapi_request_validate(self, response): # Load result into an XML object result = xmltodict.parse(response.content) # Get API response status status = result['response']['@status'] if self.params['ngfw_verbose'] is True: demisto.log('Got execution status back from API: ' + str(status)) demisto.log(str(response.text)) if "success" in status: return True else: message = result['response']['msg']['line'] raise Exception('API call encountered an error, received "' + str(status) + ' " as status code with error message: ' + str(message))
def get_token(): """ Retrieve the token using the credentials """ response = requests.post(URL + 'login', headers=HEADERS, verify=VERIFY, json={ 'customerName': demisto.getParam('customer') or '', 'username': demisto.getParam('credentials')['identifier'], 'password': demisto.getParam('credentials')['password'] }) if response.status_code != requests.codes.ok: # pylint: disable=no-member raise Exception('Error authenticating to RedLock service [%d] - %s' % (response.status_code, response.text)) try: response_json = response.json() TOKEN = response_json.get('token') if not TOKEN: demisto.debug(json.dumps(response_json)) message = 'Could not retrieve token from server: {}'.format( response_json.get("message")) if response_json.get('message') == 'login_needs_customer_name': available_customer_names = [ name.get('customerName') for name in response_json.get('customerNames') ] message = 'In order to login a customer name need to be configured. Available customer names: {}'.format( {", ".join(available_customer_names)}) raise Exception(message) except ValueError as exception: demisto.log(exception) raise Exception('Could not parse API response.') HEADERS['x-redlock-auth'] = TOKEN
def __org_and_id(self, org_name: str = None, org_id: str = None) -> Dict: """ :param org_name: the org name for search (the org id) :param org_id: the org id for search (the org name) :return: {"name": <org name>, "id": <org id>} """ if not org_id: if not org_name: org_name = 'None' looking_for = org_name looking_in = 'name' else: looking_for = org_id looking_in = 'id' if not self.__cache['org']: _, _, self.__cache['org'] = self.get_organization_list(raw=True) for org in self.__cache['org']: if org.get(looking_in) == looking_for: return org demisto.log(f'{looking_for} is not a {looking_in}(org).') return {}
def upload_stats_to_panw(csp, input_file): get_path = demisto.getFilePath(input_file) file_data = { 'file_friendly_name': get_path.get('name'), 'file_actual_name': get_path.get('path') } demisto.log('Got file name [' + file_data['file_friendly_name'] + '] as path [' + file_data['file_actual_name'] + ']') result = csp.upload_to_panw(file_data) send_to = demisto.params().get('slr_send_to') slr_id = result['Id'] readable_output = 'Success! The SLR Report will be emailed to ' + str( send_to) + ' (SLR ID: `' + str(slr_id) + '`)' context = {'id': slr_id, 'send_to': send_to} return CommandResults(readable_output=readable_output, outputs_prefix='AutoSLR.upload', outputs_key_field=['id', 'send_to'], outputs=context)
def ngfw_get_stats_dump_status(xmlapi, job_id): state = False while not state: demisto.log('Checking status for job ID: `' + str(job_id) + '`') result = xmlapi.get_stats_job_id_status(job_id) if 'FIN' in result['status']: state = True elif 'ACT' in result['status']: demisto.log('Job `' + str(job_id) + '` is currently executing, current progress: `' + result['progress'] + '%`') elif 'PEND' in result['status']: demisto.log( 'Another job is currently executing, this job is currently in the queue' ) else: raise Exception( 'Unexpected value returned from API, expected [`ACT/FIN/PEND`] got: `' + str(result) + '`') time.sleep(1) if state is True: readable_output = 'Successfully finished executing stats_dump generation job for job ID: `' + str( job_id) + '`' return CommandResults(readable_output=readable_output, outputs_prefix='AutoSLR.generate.job_status', outputs_key_field='job_status', outputs=state) else: raise Exception('Could not check stats_dump generation task [ID: `' + str(job_id) + '`]')
def upload_to_panw(self, file_data): file_handler = open(file_data['file_actual_name'], 'rb') file = { "files": (file_data['file_friendly_name'], file_handler, 'application/gzip') } payload = { "EmailIdList": self.slr_params['slr_send_to'], "RequestedBy": self.slr_params['slr_requested_by'], "PreparedBy": self.slr_params['slr_prepared_by'], "AccountName": self.slr_params['slr_account_name'], "Industry": self.slr_params['slr_industry'], "Country": self.slr_params['slr_country'], "GeographicRegion": self.slr_params['slr_geographic_region'], "DeploymentLocation": self.slr_params['slr_deployment_location'], "Language": self.slr_params['slr_language'] } if self.params['csp_verbose'] is True: demisto.log('Upload -> Parameters -> [' + str(payload) + ']') demisto.log('Upload -> Files -> [' + str(file) + ']') demisto.log('Uploading ' + file_data['file_friendly_name'] + ' to Palo Alto Networks...') response = self._http_request('POST', '/API/v1/Create/', data=payload, files=file, resp_type='json', proxies=self.proxies, timeout=self.params['csp_timeout']) return response
def remedy_update_ticket_command(): demisto.log('TODO')
'Type': entryTypes['error'], 'ContentsFormat': formats['text'], 'Contents': 'More than one sensor returned.\nResult:\n' + str(matches) }) sys.exit() else: demisto.results({ 'Type': entryTypes['error'], 'ContentsFormat': formats['text'], 'Contents': 'Sensor not found.' }) sys.exit() demisto.log('[*] Located sensor ID ' + sensorId) # Get a live session to the endpoint resSessions = demisto.executeCommand('cb-list-sessions', {}) if isError(resSessions[0]): demisto.results(resSessions) sys.exit() else: existingSessions = [ s for s in resSessions[0]['Contents'] if str(s['sensor_id']) == sensorId and s['status'] in ['pending', 'active'] ] if not existingSessions: resSessionCreate = demisto.executeCommand('cb-session-create', {'sensor': sensorId}) if isError(resSessionCreate[0]):
def format_results(uuid): # Scan Lists sometimes returns empty scan_lists = None while scan_lists is None: try: response = urlscan_submit_request(uuid) scan_data = response['data'] scan_lists = response['lists'] scan_tasks = response['task'] scan_page = response['page'] scan_stats = response['stats'] scan_meta = response['meta'] url_query = scan_tasks['url'] except Exception: pass ec = makehash() dbot_score = makehash() human_readable = makehash() cont = makehash() file_context = makehash() url_cont = makehash() LIMIT = int(demisto.args().get('limit')) if 'certificates' in scan_lists: cert_md = [] cert_ec = [] certs = scan_lists['certificates'] for x in certs[:LIMIT]: info, ec_info = cert_format(x) cert_md.append(info) cert_ec.append(ec_info) CERT_HEADERS = ['Subject Name', 'Issuer', 'Validity'] cont['Certificates'] = cert_ec url_cont['Data'] = url_query if 'urls' in scan_lists: url_cont['Data'] = demisto.args().get('url') cont['URL'] = demisto.args().get('url') # effective url of the submitted url human_readable['Effective URL'] = response['page']['url'] cont['EffectiveURL'] = response['page']['url'] if 'uuid' in scan_tasks: ec['URLScan']['UUID'] if 'ips' in scan_lists: ip_asn_MD = [] ip_ec_info = makehash() ip_list = scan_lists['ips'] asn_list = scan_lists['asns'] ip_asn_dict = dict(zip(ip_list, asn_list)) i = 1 for k in ip_asn_dict: if i - 1 == LIMIT: break v = ip_asn_dict[k] ip_info = {'Count': i, 'IP': k, 'ASN': v} ip_ec_info[i]['IP'] = k ip_ec_info[i]['ASN'] = v ip_asn_MD.append(ip_info) i = i + 1 cont['RelatedIPs'] = ip_ec_info IP_HEADERS = ['Count', 'IP', 'ASN'] # add redirected URLs if 'requests' in scan_data: redirected_urls = [] demisto.log(str(scan_data['requests'])) for o in scan_data['requests']: if 'redirectResponse' in o['request']: if 'url' in o['request']['redirectResponse']: url = o['request']['redirectResponse']['url'] redirected_urls.append(url) cont['RedirectedURLs'] = redirected_urls if 'countries' in scan_lists: countries = scan_lists['countries'] human_readable['Associated Countries'] = countries cont['Country'] = countries if None not in scan_lists['hashes']: hashes = scan_lists['hashes'] cont['RelatedHash'] = hashes human_readable['Related Hashes'] = hashes if 'domains' in scan_lists: subdomains = scan_lists['domains'] cont['Subdomains'] = subdomains human_readable['Subdomains'] = subdomains if 'asn' in scan_page: cont['ASN'] = scan_page['asn'] if 'malicious' in scan_stats: human_readable['Malicious URLs Found'] = scan_stats['malicious'] if int(scan_stats['malicious']) >= THRESHOLD: human_readable['Malicious'] = 'Malicious' url_cont['Data'] = demisto.args().get('url') cont['Data'] = demisto.args().get('url') dbot_score['Indicator'] = demisto.args().get('url') url_cont['Malicious']['Vendor'] = 'urlscan.io' cont['Malicious']['Vendor'] = 'urlscan.io' dbot_score['Vendor'] = 'urlscan.io' url_cont['Malicious'][ 'Description'] = 'Match found in Urlscan.io database' cont['Malicious'][ 'Description'] = 'Match found in Urlscan.io database' dbot_score['Score'] = 3 dbot_score['Type'] = 'url' else: dbot_score['Vendor'] = 'urlscan.io' dbot_score['Indicator'] = demisto.args().get('url') dbot_score['Score'] = 0 dbot_score['Type'] = 'url' human_readable['Malicious'] = 'Benign' if 'url' in scan_meta['processors']['gsb']['data'] is None: mal_url_list = [] matches = scan_meta['processors']['gsb']['data']['matches'] for match in matches: mal_url = match['threat']['url'] mal_url_list.append(mal_url) human_readable['Related Malicious URLs'] = mal_url_list if len(scan_meta['processors']['download']['data']) > 0: meta_data = scan_meta['processors']['download']['data'][0] sha256 = meta_data['sha256'] filename = meta_data['filename'] filesize = meta_data['filesize'] filetype = meta_data['mimeType'] human_readable['File']['Hash'] = sha256 cont['File']['Hash'] = sha256 file_context['SHA256'] = sha256 human_readable['File']['Name'] = filename cont['File']['FileName'] = filename file_context['Name'] = filename human_readable['File']['Size'] = filesize cont['File']['FileSize'] = filesize file_context['Size'] = filesize human_readable['File']['Type'] = filetype cont['File']['FileType'] = filetype file_context['Type'] = filetype file_context['Hostname'] = demisto.args().get('url') ec = { 'URLScan(val.URL && val.URL == obj.URL)': cont, 'DBotScore': dbot_score, 'URL': url_cont, outputPaths['file']: file_context } if 'screenshotURL' in scan_tasks: human_readable['Screenshot'] = scan_tasks['screenshotURL'] screen_path = scan_tasks['screenshotURL'] response_img = requests.request("GET", screen_path) stored_img = fileResult('screenshot.png', response_img.content) demisto.results({ 'Type': entryTypes['note'], 'ContentsFormat': formats['markdown'], 'Contents': response, 'HumanReadable': tableToMarkdown('{} - Scan Results'.format(url_query), human_readable), 'EntryContext': ec }) if len(cert_md) > 0: demisto.results({ 'Type': entryTypes['note'], 'ContentsFormat': formats['markdown'], 'Contents': tableToMarkdown('Certificates', cert_md, CERT_HEADERS), 'HumanReadable': tableToMarkdown('Certificates', cert_md, CERT_HEADERS) }) if 'ips' in scan_lists: demisto.results({ 'Type': entryTypes['note'], 'ContentsFormat': formats['markdown'], 'Contents': tableToMarkdown('Related IPs and ASNs', ip_asn_MD, IP_HEADERS), 'HumanReadable': tableToMarkdown('Related IPs and ASNs', ip_asn_MD, IP_HEADERS) }) if 'screenshotURL' in scan_tasks: demisto.results({ 'Type': entryTypes['image'], 'ContentsFormat': formats['text'], 'File': stored_img['File'], 'FileID': stored_img['FileID'], 'Contents': '' })
def format_results(uuid): # Scan Lists sometimes returns empty scan_lists = None while scan_lists is None: try: response = urlscan_submit_request(uuid) scan_data = response['data'] scan_lists = response['lists'] scan_tasks = response['task'] scan_page = response['page'] scan_stats = response['stats'] scan_meta = response['meta'] url_query = scan_tasks['url'] except Exception: pass ec = makehash() dbot_score = makehash() human_readable = makehash() cont = makehash() file_context = makehash() url_cont = makehash() LIMIT = int(demisto.args().get('limit')) if 'certificates' in scan_lists: cert_md = [] cert_ec = [] certs = scan_lists['certificates'] for x in certs[:LIMIT]: info, ec_info = cert_format(x) cert_md.append(info) cert_ec.append(ec_info) CERT_HEADERS = ['Subject Name', 'Issuer', 'Validity'] cont['Certificates'] = cert_ec url_cont['Data'] = url_query if 'urls' in scan_lists: url_cont['Data'] = demisto.args().get('url') cont['URL'] = demisto.args().get('url') # effective url of the submitted url human_readable['Effective URL'] = response['page']['url'] cont['EffectiveURL'] = response['page']['url'] if 'uuid' in scan_tasks: ec['URLScan']['UUID'] if 'ips' in scan_lists: ip_asn_MD = [] ip_ec_info = makehash() ip_list = scan_lists['ips'] asn_list = scan_lists['asns'] ip_asn_dict = dict(zip(ip_list, asn_list)) i = 1 for k in ip_asn_dict: if i - 1 == LIMIT: break v = ip_asn_dict[k] ip_info = { 'Count': i, 'IP': k, 'ASN': v } ip_ec_info[i]['IP'] = k ip_ec_info[i]['ASN'] = v ip_asn_MD.append(ip_info) i = i + 1 cont['RelatedIPs'] = ip_ec_info IP_HEADERS = ['Count', 'IP', 'ASN'] # add redirected URLs if 'requests' in scan_data: redirected_urls = [] demisto.log(str(scan_data['requests'])) for o in scan_data['requests']: if 'redirectResponse' in o['request']: if 'url' in o['request']['redirectResponse']: url = o['request']['redirectResponse']['url'] redirected_urls.append(url) cont['RedirectedURLs'] = redirected_urls if 'countries' in scan_lists: countries = scan_lists['countries'] human_readable['Associated Countries'] = countries cont['Country'] = countries if None not in scan_lists['hashes']: hashes = scan_lists['hashes'] cont['RelatedHash'] = hashes human_readable['Related Hashes'] = hashes if 'domains' in scan_lists: subdomains = scan_lists['domains'] cont['Subdomains'] = subdomains human_readable['Subdomains'] = subdomains if 'asn' in scan_page: cont['ASN'] = scan_page['asn'] if 'malicious' in scan_stats: human_readable['Malicious URLs Found'] = scan_stats['malicious'] if int(scan_stats['malicious']) >= THRESHOLD: human_readable['Malicious'] = 'Malicious' url_cont['Data'] = demisto.args().get('url') cont['Data'] = demisto.args().get('url') dbot_score['Indicator'] = demisto.args().get('url') url_cont['Malicious']['Vendor'] = 'urlscan.io' cont['Malicious']['Vendor'] = 'urlscan.io' dbot_score['Vendor'] = 'urlscan.io' url_cont['Malicious']['Description'] = 'Match found in Urlscan.io database' cont['Malicious']['Description'] = 'Match found in Urlscan.io database' dbot_score['Score'] = 3 dbot_score['Type'] = 'url' else: dbot_score['Vendor'] = 'urlscan.io' dbot_score['Indicator'] = demisto.args().get('url') dbot_score['Score'] = 0 dbot_score['Type'] = 'url' human_readable['Malicious'] = 'Benign' if 'url' in scan_meta['processors']['gsb']['data'] is None: mal_url_list = [] matches = scan_meta['processors']['gsb']['data']['matches'] for match in matches: mal_url = match['threat']['url'] mal_url_list.append(mal_url) human_readable['Related Malicious URLs'] = mal_url_list if len(scan_meta['processors']['download']['data']) > 0: meta_data = scan_meta['processors']['download']['data'][0] sha256 = meta_data['sha256'] filename = meta_data['filename'] filesize = meta_data['filesize'] filetype = meta_data['mimeType'] human_readable['File']['Hash'] = sha256 cont['File']['Hash'] = sha256 file_context['SHA256'] = sha256 human_readable['File']['Name'] = filename cont['File']['FileName'] = filename file_context['Name'] = filename human_readable['File']['Size'] = filesize cont['File']['FileSize'] = filesize file_context['Size'] = filesize human_readable['File']['Type'] = filetype cont['File']['FileType'] = filetype file_context['Type'] = filetype file_context['Hostname'] = demisto.args().get('url') ec = { 'URLScan(val.URL && val.URL == obj.URL)': cont, 'DBotScore': dbot_score, 'URL': url_cont, outputPaths['file']: file_context } if 'screenshotURL' in scan_tasks: human_readable['Screenshot'] = scan_tasks['screenshotURL'] screen_path = scan_tasks['screenshotURL'] response_img = requests.request("GET", screen_path) stored_img = fileResult('screenshot.png', response_img.content) demisto.results({ 'Type': entryTypes['note'], 'ContentsFormat': formats['markdown'], 'Contents': response, 'HumanReadable': tableToMarkdown('{} - Scan Results'.format(url_query), human_readable), 'EntryContext': ec }) if len(cert_md) > 0: demisto.results({ 'Type': entryTypes['note'], 'ContentsFormat': formats['markdown'], 'Contents': tableToMarkdown('Certificates', cert_md, CERT_HEADERS), 'HumanReadable': tableToMarkdown('Certificates', cert_md, CERT_HEADERS) }) if 'ips' in scan_lists: demisto.results({ 'Type': entryTypes['note'], 'ContentsFormat': formats['markdown'], 'Contents': tableToMarkdown('Related IPs and ASNs', ip_asn_MD, IP_HEADERS), 'HumanReadable': tableToMarkdown('Related IPs and ASNs', ip_asn_MD, IP_HEADERS) }) if 'screenshotURL' in scan_tasks: demisto.results({ 'Type': entryTypes['image'], 'ContentsFormat': formats['text'], 'File': stored_img['File'], 'FileID': stored_img['FileID'], 'Contents': '' })