From cedd926fc16b836c715f3519640f05b668991ed5 Mon Sep 17 00:00:00 2001 From: Israel Lappe <79846863+ilappe@users.noreply.github.com> Date: Mon, 18 Dec 2023 15:37:12 +0200 Subject: [PATCH] Added new pack: Email Hippo (#31167) * new pack * Apply suggestions from code review - part 1 Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Apply suggestions from code review - part 2 Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Apply suggestions from code review - part 3 Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/EmailHippo/Integrations/EmailHippo/README.md Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/EmailHippo/Integrations/EmailHippo/README.md Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * A stricter test * RN for CommonDashboards * test playbook * pack readme * update pack_metadata * Update Packs/EmailHippo/README.md Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * fix test fail * compare dict * Update Packs/EmailHippo/Integrations/EmailHippo/EmailHippo.yml Co-authored-by: Dean Arbel * Update EmailHippo.yml * Update EmailHippo.yml * Revert "compare dict" This reverts commit 3c7713300bc38af0b60f4241add5df6ce9d10ea4. * update docker * add no cover * fix CR * update the image * fix pre commit --------- Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> Co-authored-by: Dean Arbel --- .../dashboard-APIExecutionMetrics.json | 110 +++- Packs/CommonDashboards/ReleaseNotes/1_3_8.md | 6 + Packs/CommonDashboards/pack_metadata.json | 2 +- Packs/EmailHippo/.pack-ignore | 0 Packs/EmailHippo/.secrets-ignore | 2 + .../Integrations/EmailHippo/EmailHippo.py | 406 ++++++++++++++ .../Integrations/EmailHippo/EmailHippo.yml | 200 +++++++ .../EmailHippo/EmailHippo_description.md | 13 + .../EmailHippo/EmailHippo_image.png | Bin 0 -> 2963 bytes .../EmailHippo/EmailHippo_test.py | 110 ++++ .../Integrations/EmailHippo/README.md | 505 ++++++++++++++++++ .../Integrations/EmailHippo/commands.txt | 3 + .../test_data/get_domain_output.json | 369 +++++++++++++ .../test_data/get_email_output.json | 179 +++++++ .../test_data/get_quota_output.json | 9 + Packs/EmailHippo/README.md | 6 + .../TestPlaybooks/HippoEmailTest.yml | 354 ++++++++++++ Packs/EmailHippo/pack_metadata.json | 21 + 18 files changed, 2293 insertions(+), 2 deletions(-) create mode 100644 Packs/CommonDashboards/ReleaseNotes/1_3_8.md create mode 100644 Packs/EmailHippo/.pack-ignore create mode 100644 Packs/EmailHippo/.secrets-ignore create mode 100644 Packs/EmailHippo/Integrations/EmailHippo/EmailHippo.py create mode 100644 Packs/EmailHippo/Integrations/EmailHippo/EmailHippo.yml create mode 100644 Packs/EmailHippo/Integrations/EmailHippo/EmailHippo_description.md create mode 100644 Packs/EmailHippo/Integrations/EmailHippo/EmailHippo_image.png create mode 100644 Packs/EmailHippo/Integrations/EmailHippo/EmailHippo_test.py create mode 100644 Packs/EmailHippo/Integrations/EmailHippo/README.md create mode 100644 Packs/EmailHippo/Integrations/EmailHippo/commands.txt create mode 100644 Packs/EmailHippo/Integrations/EmailHippo/test_data/get_domain_output.json create mode 100644 Packs/EmailHippo/Integrations/EmailHippo/test_data/get_email_output.json create mode 100644 Packs/EmailHippo/Integrations/EmailHippo/test_data/get_quota_output.json create mode 100644 Packs/EmailHippo/README.md create mode 100644 Packs/EmailHippo/TestPlaybooks/HippoEmailTest.yml create mode 100644 Packs/EmailHippo/pack_metadata.json diff --git a/Packs/CommonDashboards/Dashboards/dashboard-APIExecutionMetrics.json b/Packs/CommonDashboards/Dashboards/dashboard-APIExecutionMetrics.json index 93ea3f02ecf3..15041314d3c9 100644 --- a/Packs/CommonDashboards/Dashboards/dashboard-APIExecutionMetrics.json +++ b/Packs/CommonDashboards/Dashboards/dashboard-APIExecutionMetrics.json @@ -1026,7 +1026,115 @@ }, "x": 0, "y": 8 - } + }, + { + "id": "9e8acc20-8d3a-11ee-a736-df621984533b", + "forceRange": false, + "x": 8, + "y": 9, + "i": "9e8acc20-8d3a-11ee-a736-df621984533b", + "w": 4, + "h": 3, + "widget": { + "id": "API Call Results for Email Hippo", + "version": 1, + "cacheVersn": 0, + "modified": "2022-10-30T12:01:15.237569307+02:00", + "packID": "", + "packName": "", + "itemVersion": "", + "fromServerVersion": "", + "toServerVersion": "", + "propagationLabels": [ + "all" + ], + "definitionId": "", + "vcShouldIgnore": false, + "vcShouldKeepItemLegacyProdMachine": false, + "commitMessage": "", + "shouldCommit": false, + "Cache": null, + "name": "API Call Results for Email Hippo", + "prevName": "API Call Results for Email Hippo", + "dataType": "metrics", + "widgetType": "line", + "query": "type:integration and instance:\"Email Hippo_instance_1\"", + "isPredefined": false, + "dateRange": { + "fromDate": "0001-01-01T00:00:00Z", + "toDate": "0001-01-01T00:00:00Z", + "period": { + "by": "", + "byTo": "days", + "byFrom": "hours", + "toValue": 0, + "fromValue": 3, + "field": "" + }, + "fromDateLicense": "0001-01-01T00:00:00Z" + }, + "params": { + "customGroupBy": [ + null, + { + " Success": { + "conditions": [ + [ + { + "field": "apiResponseType", + "operator": "isEqualCaseString", + "right": "Successful", + "type": "string" + } + ] + ], + "name": " Success" + }, + "General Error": { + "conditions": [ + [ + { + "field": "apiResponseType", + "operator": "isEqualCaseString", + "right": "GeneralError", + "type": "string" + } + ] + ], + "name": "General Error" + }, + "Quota Error": { + "conditions": [ + [ + { + "field": "apiResponseType", + "operator": "isEqualCaseString", + "right": "QuotaError", + "type": "string" + } + ] + ], + "name": "Quota Error" + } + } + ], + "groupBy": [ + "modified(h)", + "apiResponseType" + ], + "keys": [ + "sum|totalAPICalls" + ], + "referenceLine": {}, + "timeFrame": "hours", + "valuesFormat": "abbreviated", + "xAxisLabel": "Time", + "yAxisLabel": "Request Counts" + }, + "category": "" + }, + "reflectDimensions": true + } ], "fromVersion": "6.8.0", "description": "", diff --git a/Packs/CommonDashboards/ReleaseNotes/1_3_8.md b/Packs/CommonDashboards/ReleaseNotes/1_3_8.md new file mode 100644 index 000000000000..a2c6761f938d --- /dev/null +++ b/Packs/CommonDashboards/ReleaseNotes/1_3_8.md @@ -0,0 +1,6 @@ + +#### Dashboards + +##### API Execution Metrics + +- Added the Email Hippo widget. diff --git a/Packs/CommonDashboards/pack_metadata.json b/Packs/CommonDashboards/pack_metadata.json index 49a043279145..e26b76125452 100644 --- a/Packs/CommonDashboards/pack_metadata.json +++ b/Packs/CommonDashboards/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Common Dashboards", "description": "Frequently used dashboards pack.", "support": "xsoar", - "currentVersion": "1.3.7", + "currentVersion": "1.3.8", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/EmailHippo/.pack-ignore b/Packs/EmailHippo/.pack-ignore new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Packs/EmailHippo/.secrets-ignore b/Packs/EmailHippo/.secrets-ignore new file mode 100644 index 000000000000..a69ab933d172 --- /dev/null +++ b/Packs/EmailHippo/.secrets-ignore @@ -0,0 +1,2 @@ +https://api.hippoapi.com +https://api.whoishippo.com \ No newline at end of file diff --git a/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo.py b/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo.py new file mode 100644 index 000000000000..57a5e567c39d --- /dev/null +++ b/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo.py @@ -0,0 +1,406 @@ +import demistomock as demisto # noqa: F401 +from CommonServerPython import * # noqa: F401 + +import urllib3 +import dateparser +from requests import Response +from functools import partial +from typing import Any + + +# Disable insecure warnings +urllib3.disable_warnings() + +DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ' +TRUST_LEVEL_TO_DBOT_SCORE_MAPPING = { + 'None': Common.DBotScore.NONE, + 'High': Common.DBotScore.GOOD, + 'Medium': Common.DBotScore.SUSPICIOUS, + 'Low': Common.DBotScore.BAD +} + + +class Client(BaseClient): + """Client class to interact with the service API + + This Client implements API calls, and does not contain any Demisto logic. + Should only do requests and return data. + It inherits from BaseClient defined in CommonServer Python. + Most calls use _http_request() that handles proxy, SSL verification, etc. + """ + + def __init__(self, more_api_key, whois_api_key, more_server_url, whois_server_url, **kwargs): + self._more_api_key = more_api_key + self._whois_api_key = whois_api_key + self._more_server_url = more_server_url.rstrip("/") + self._whois_server_url = f'{whois_server_url.rstrip("/")}/v1/{whois_api_key}' + self.execution_metrics = ExecutionMetrics() + + super().__init__(base_url='', **kwargs) + + def get_email_reputation(self, email: str) -> dict[str, Any]: + """Gets the Email reputation using the hippoapi '/email' API endpoint + + Args: + email (str): Email address to get the reputation for. + + Returns: + dict: dict containing the Email reputation as returned from the API + """ + + return self._http_request(method='GET', + full_url=f'{self._more_server_url}/v3/more/json/{self._more_api_key}/{email}') + + def get_domain_reputation(self, domain: str) -> dict[str, Any]: + """ + Gets the Domain reputation using the whoishippo '/domain' API endpoint. + + Args: + domain (str): Domain name to get the reputation for. + + Returns: + dict: dict containing the domain reputation as returned from the API. + """ + + return self._http_request(method='GET', full_url=f'{self._whois_server_url}/{domain}') + + def get_email_quota(self) -> dict[str, Any]: + """ + Get the email quota remaining for the API key + """ + return self._http_request(method='GET', + full_url=f'{self._more_server_url}/customer/reports/v3/quota/{self._more_api_key}') + + def error_handler(self, res: Response): + """ + Error handling for http responses, to support the API Execution Metrics. + + Args: + res (Response): The response object from the http request. + """ + if res.status_code == 429 or 'Insufficient quota' in res.text: + self.execution_metrics.quota_error += 1 + elif res.status_code == 401: + self.execution_metrics.auth_error += 1 + else: + self.execution_metrics.general_error += 1 + + self.client_error_handler(res) + + def _http_request(self, **kwargs): + """ + Wrapper for BaseClient._http_request for supporting API Execution Metrics. + """ + try: + return super()._http_request(error_handler=self.error_handler, **kwargs) + finally: + self.execution_metrics.success += 1 + + +def parse_domain_date(domain_date: list[str] | str, date_format: str = '%Y-%m-%dT%H:%M:%S.000Z') -> str | None: + """ + Converts whois date format to an ISO8601 string. + Converts the domain WHOIS date (YYYY-mm-dd HH:MM:SS) format + in a datetime. If a list is returned with multiple elements, takes only + the first one. + + Args: + domain_date (str/list): a string or list of strings with the format 'YYYY-mm-DD HH:MM:SS' + date_format (int): The format date to which the function will convert the given date. + + Returns: + str: Parsed time, default in ISO8601 format. + """ + + if isinstance(domain_date, str): + # if str parse the value + domain_date_dt = dateparser.parse(domain_date) + if domain_date_dt: + return domain_date_dt.strftime(date_format) + elif isinstance(domain_date, list) and len(domain_date) > 0 and isinstance(domain_date[0], str): + # if list with at least one element, parse the first element + domain_date_dt = dateparser.parse(domain_date[0]) + if domain_date_dt: + return domain_date_dt.strftime(date_format) + # in any other case return nothing + return None + + +''' COMMAND FUNCTIONS ''' + + +def test_module(client: Client) -> str: + """ + Tests API connectivity and authentication for both, EmailHippo and WHOIS. + When 'ok' is returned it indicates the integration works like it is supposed to and connection to the service is + successful. + Raises exceptions if something goes wrong. + + Args: + client (Client): EmailHippo client to use. + + Returns: + str: 'ok' if test passed, anything else will raise an exception and will fail the test. + """ + test_methods: dict[str, Any] = { + 'MORE': partial(client.get_email_reputation, 'test@test.com'), + 'WHOIS': partial(client.get_domain_reputation, 'google.com') + } + + for key_vendor in test_methods: + try: + test_methods[key_vendor]() + except DemistoException as e: + if 'Unauthorized' in str(e): + return f'Authorization Error: make sure {key_vendor} API Key is correctly set' + else: + raise e + return 'ok' + + +def get_email_quota_command(client: Client) -> CommandResults: + """ + email-hippo-email-quota-get command: Returns the email quota. + + Args: + client (Client): EmailHippo client to use. + + Returns: + CommandResults: A ``CommandResults`` object that is then passed to ``return_results``. + """ + + quota = client.get_email_quota() + quota.pop('licenseKey', None) # delete the licenseKey as this are secret + + readable_output = tableToMarkdown('Email quota', + { + 'Email Quota used': quota.get('quotaUsed'), + 'Email Quota remaining': quota.get('quotaRemaining') + }) + return CommandResults( + readable_output=readable_output, + outputs_prefix='EmailHippo.Quota', + outputs_key_field='accountId', + outputs=quota + ) + + +def email_reputation_command(client: Client, args: dict[str, Any], + reliability: DBotScoreReliability, create_relationships: bool = False) -> list[CommandResults]: + """ + email command: Returns Email reputation for a list of Emails + + Args: + client (Client): EmailHippo client to use. + args (dict): all command arguments, usually passed from ``demisto.args()``. + reliability (DBotScoreReliability): reliability of the source providing the intelligence data. + create_relationships (bool): whether to create relationships between the email and domain. + + Returns: + CommandResults: A ``CommandResults`` object that is then passed to ``return_results``, that contains Emails. + """ + + emails = argToList(args.get('email')) + if len(emails) == 0: + raise ValueError('Email(s) not specified') + + command_results: list[CommandResults] = [] + + for email in emails: + email_data = client.get_email_reputation(email) + email_data['Address'] = email + + domain = demisto.get(email_data, 'meta.domain') + level = demisto.get(email_data, 'hippoTrust.level') + reputation = TRUST_LEVEL_TO_DBOT_SCORE_MAPPING.get(level, Common.DBotScore.NONE) + + dbot_score = Common.DBotScore( + indicator=email, + indicator_type=DBotScoreType.EMAIL, + integration_name='Email Hippo', + score=reputation, + malicious_description=f'Email Hippo returned reputation {reputation}', + reliability=reliability + ) + relationships = [] + if create_relationships: + relationships.append( + EntityRelationship( + entity_a=email, + entity_a_type=FeedIndicatorType.Email, + name='related-to', + entity_b=domain, + entity_b_type=FeedIndicatorType.Domain, + brand='Email Hippo' + ) + ) + + email_indicator = Common.EMAIL( + address=email, + dbot_score=dbot_score, + domain=domain, + relationships=relationships + ) + + email_readable = { + 'Result': demisto.get(email_data, 'emailVerification.mailboxVerification'), + 'Hippo Trust Score': demisto.get(email_data, 'hippoTrust.level'), + 'Inbox quality score': demisto.get(email_data, 'sendAssess.sendRecommendation'), + 'Spam risk score': demisto.get(email_data, 'spamAssess.actionRecomendation'), + } + readable_output = tableToMarkdown(f'Email {email}', email_readable) + + command_results.append(CommandResults( + readable_output=readable_output, + outputs_prefix='EmailHippo.Email', + outputs_key_field='Address', + outputs=email_data, + indicator=email_indicator, + relationships=relationships + )) + return command_results + + +def domain_reputation_command(client: Client, args: dict[str, Any], + reliability: DBotScoreReliability) -> list[CommandResults]: + """ + domain command: Returns domain reputation for a list of domains. + + Args: + client (Client): EmailHippo client to use. + args (dict): all command arguments, usually passed from ``demisto.args()``. + reliability (DBotScoreReliability): reliability of the source providing the intelligence data. + + Returns: + CommandResults: A ``CommandResults`` object that is then passed to ``return_results``, that contains Domains. + """ + + domains = argToList(args.get('domain')) + if len(domains) == 0: + raise ValueError('domain(s) not specified') + + command_results: list[CommandResults] = [] + + for domain in domains: + domain_data = client.get_domain_reputation(domain) + domain_data['domain'] = domain + + # convert the dates to ISO8601 as Cortex XSOAR customers use this format by default + if creation_date := demisto.get(domain_data, 'meta.recordCreatedDate'): + domain_data['creation_date'] = parse_domain_date(creation_date) + if updated_date := demisto.get(domain_data, 'meta.recordUpdatedDate'): + domain_data['updated_date'] = parse_domain_date(updated_date) + + dbot_score = Common.DBotScore( + indicator=domain, + integration_name='Email Hippo', + indicator_type=DBotScoreType.DOMAIN, + score=Common.DBotScore.NONE, + reliability=reliability + ) + + domain_indicator = Common.Domain( + domain=domain, + creation_date=domain_data.get('creation_date', None), + updated_date=domain_data.get('updated_date', None), + # organization=domain_data.get('org', None), + name_servers=demisto.get(domain_data, 'whoisServerRecord.nameServers'), + registrar_name=demisto.get(domain_data, 'whoisServerRecord.registrar.name'), + registrar_abuse_phone=demisto.get(domain_data, 'whoisServerRecord.registrar.abusePhone'), + registrar_abuse_email=demisto.get(domain_data, 'whoisServerRecord.registrar.abuseEmail'), + admin_name=demisto.get(domain_data, 'whoisServerRecord.adminContact.name'), + admin_country=demisto.get(domain_data, 'whoisServerRecord.adminContact.country'), + admin_email=demisto.get(domain_data, 'whoisServerRecord.adminContact.email'), + admin_phone=demisto.get(domain_data, 'whoisServerRecord.adminContact.phoneNumber'), + tech_country=demisto.get(domain_data, 'whoisServerRecord.techContact.country'), + tech_name=demisto.get(domain_data, 'whoisServerRecord.techContact.name'), + tech_organization=demisto.get(domain_data, 'whoisServerRecord.techContact.organization'), + tech_email=demisto.get(domain_data, 'whoisServerRecord.techContact.email'), + dbot_score=dbot_score + ) + + domain_readable = { + 'Registrar': demisto.get(domain_data, 'whoisServerRecord.registrar.name'), + 'Registered On': demisto.get(domain_data, 'whoisServerRecord.created'), + 'Domain Age': demisto.get(domain_data, 'meta.domainAge'), + 'Expires On': demisto.get(domain_data, 'whoisServerRecord.expiry'), + 'Time To Expiry': demisto.get(domain_data, 'meta.timeToExpiry'), + 'Updated On': demisto.get(domain_data, 'whoisServerRecord.changed'), + 'Status': demisto.get(domain_data, 'whoisServerRecord.domainStati'), + 'Name servers': demisto.get(domain_data, 'whoisServerRecord.nameServers') + } + readable_output = tableToMarkdown(f'Domain {domain}', domain_readable) + # delete the rawResponse key from the output + domain_data.get('whoisServerRecord', {}).pop('rawResponse', None) + command_results.append(CommandResults( + readable_output=readable_output, + outputs_prefix='EmailHippo.Domain', + outputs_key_field='domain', + outputs=domain_data, + indicator=domain_indicator + )) + return command_results + + +''' MAIN FUNCTION ''' + + +def main() -> None: # pragma: no cover + """ + main function, parses params and runs command functions + """ + + params = demisto.params() + args = demisto.args() + command = demisto.command() + + more_api_key = params.get('more_credentials', {}).get('password') + whois_api_key = params.get('whois_credentials', {}).get('password') + more_server_url = params.get('more_server_url', 'https://api.hippoapi.com') + whois_server_url = params.get('whois_server_url', 'https://api.whoishippo.com') + + reliability = params.get('integrationReliability', DBotScoreReliability.C) + + verify_certificate = not params.get('insecure', False) + proxy = params.get('proxy', False) + + demisto.debug(f'Command being called is {command}') + res: list[CommandResults] = [] + client = None + try: + client = Client( + more_api_key=more_api_key, + whois_api_key=whois_api_key, + more_server_url=more_server_url, + whois_server_url=whois_server_url, + verify=verify_certificate, + proxy=proxy) + + if command == 'test-module': + return_results(test_module(client)) + + elif command == 'email': + res = email_reputation_command(client, args, reliability) + + elif command == 'domain': + res = domain_reputation_command(client, args, reliability) + + elif command == 'email-hippo-email-quota-get': + res = [get_email_quota_command(client)] + + else: + raise NotImplementedError(f'Command {command} is not implemented') + if res: + return_results(append_metrics(client.execution_metrics, res)) + + # Log exceptions and return errors + except Exception as e: + if client: + return_results(client.execution_metrics.metrics) + return_error(f'Failed to execute {command} command.\nError:\n{str(e)}') + + +''' ENTRY POINT ''' + +if __name__ in ('__main__', '__builtin__', 'builtins'): + main() diff --git a/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo.yml b/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo.yml new file mode 100644 index 000000000000..3a6720c13e44 --- /dev/null +++ b/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo.yml @@ -0,0 +1,200 @@ +commonfields: + id: Email Hippo + version: -1 +name: Email Hippo +display: Email Hippo +category: Data Enrichment & Threat Intelligence +description: "This is the Email Hippo integration used to verify email sources as fake emails that were used as part of phishing attacks." +configuration: +- section: Connect + display: MORE Server URL (e.g., https://api.hippoapi.com) + name: more_server_url + defaultvalue: https://api.hippoapi.com + type: 0 + required: true +- section: Connect + display: Email Hippo WHOIS Server URL (e.g., https://api.whoishippo.com) + name: whois_server_url + defaultvalue: https://api.whoishippo.com + type: 0 + required: true +- section: Connect + display: '' + displaypassword: MORE API Key + name: more_credentials + type: 9 + required: true + hiddenusername: true +- section: Connect + display: '' + displaypassword: WHOIS API Key + name: whois_credentials + type: 9 + required: true + hiddenusername: true +- section: Collect + display: Source Reliability + name: integrationReliability + defaultvalue: C - Fairly reliable + type: 15 + required: false + options: + - A+ - 3rd party enrichment + - A - Completely reliable + - B - Usually reliable + - C - Fairly reliable + - D - Not usually reliable + - E - Unreliable + - F - Reliability cannot be judged + additionalinfo: Reliability of the source providing the intelligence data. +- section: Collect + display: Create relationships + name: create_relationships + defaultvalue: 'true' + type: 8 + required: false + additionalinfo: Create relationships between indicators as part of enrichment. +- section: Connect + advanced: true + display: Trust any certificate (not secure) + name: insecure + type: 8 + required: false +- section: Connect + advanced: true + display: Use system proxy settings + name: proxy + type: 8 + required: false +script: + script: '' + type: python + commands: + - name: email-hippo-email-quota-get + outputs: + - contextPath: EmailHippo.Quota.quotaUsed + description: Total quota used. + type: String + - contextPath: EmailHippo.Quota.quotaRemaining + description: The remaining quota. + type: String + description: Get the email quota from the API. + - name: email + arguments: + - name: email + required: true + isArray: true + description: A comma-separated list of email addresses to validate. + default: true + outputs: + - contextPath: DBotScore.Indicator + description: The indicator that was tested. + type: String + - contextPath: DBotScore.Reliability + description: Reliability of the source providing the intelligence data. + type: String + - contextPath: DBotScore.Score + description: The actual score. + type: Number + - contextPath: DBotScore.Type + description: The indicator type. + type: String + - contextPath: DBotScore.Vendor + description: The vendor used to calculate the score. + type: String + - contextPath: Email.Address + description: The email address of the indicator. + type: String + - contextPath: Email.Domain + description: The email domain. + type: string + - contextPath: EmailHippo.Email.Address + description: The email address of the indicator. + type: String + description: Return email information and reputation. + - name: domain + arguments: + - name: domain + required: true + isArray: true + description: The domain to query (CSV). + outputs: + - contextPath: DBotScore.Indicator + description: The indicator that was tested. + type: String + - contextPath: DBotScore.Reliability + description: The reliability score of the vendor. + type: String + - contextPath: DBotScore.Score + description: The actual score. + type: Number + - contextPath: DBotScore.Type + description: The indicator type. + type: String + - contextPath: DBotScore.Vendor + description: The vendor used to calculate the score. + type: String + - contextPath: Domain.Name + description: The name of the domain that was checked. + type: String + - contextPath: Domain.NameServers + description: Name of the servers of the domain. + type: String + - contextPath: Domain.UpdatedDate + description: The date that the domain was last updated. + type: Date + - contextPath: Domain.CreationDate + description: The creation date of the domain. Format is ISO8601 (i.e., '2020-04-30T10:35:00.000Z'). + type: Date + - contextPath: Domain.Registrar.Name + description: The name of the registrar. + type: String + - contextPath: Domain.Registrar.AbuseEmail + description: The email address of the contact for reporting abuse. + type: String + - contextPath: Domain.Registrar.AbusePhone + description: The phone number of the contact for reporting abuse. + type: String + - contextPath: Domain.Admin.Country + description: The country of the domain administrator. + type: String + - contextPath: Domain.Admin.Email + description: The email address of the domain administrator. + type: String + - contextPath: Domain.Admin.Name + description: The name of the domain administrator. + type: String + - contextPath: Domain.Admin.Phone + description: The phone number of the domain administrator. + type: String + - contextPath: Domain.Tech.Country + description: The country of the tech administrator. + type: String + - contextPath: Domain.Tech.Name + description: The name of the tech administrator. + type: String + - contextPath: Domain.Tech.Email + description: The email of the tech administrator. + type: String + - contextPath: Domain.Tech.Organization + description: The organization of the tech administrator. + type: String + - contextPath: Domain.WHOIS.NameServers + description: A CSV string of name servers, for example 'ns1.bla.com, ns2.bla.com'. + type: String + - contextPath: Domain.WHOIS.CreationDate + description: The creation date of the domain. Format is ISO8601 (i.e., '2020-04-30T10:35:00.000Z'). + type: Date + - contextPath: Domain.WHOIS.UpdatedDate + description: The date when the domain was last updated. Format is ISO8601 (i.e., '2020-04-30T10:35:00.000Z'). + type: Date + - contextPath: Domain.WHOIS.ExpirationDate + description: The expiration date of the domain. + type: Date + description: Returns domain information and reputation. + dockerimage: demisto/python3:3.10.13.83255 + runonce: false + subtype: python3 +fromversion: 6.9.0 +tests: +- No tests (auto formatted) diff --git a/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo_description.md b/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo_description.md new file mode 100644 index 000000000000..155f912b336e --- /dev/null +++ b/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo_description.md @@ -0,0 +1,13 @@ +## Email Hippo +- You can obtain your MORE API key by signing in to the [Email Hippo portal](https://app.emailhippo.com/). + - MORE API Key: MORE -> API Keys. + - WHOIS API Key: WHOIS -> API Keys. + +### Limitation +- Allowed throughput is 220 MORE email validation requests per second. Throughput exceeding these limits will receive HTTP response code 429 (too many requests) for subsequent requests for a duration of one minute. +- There is a quota for both MORE and WHOIS: + - MORE - 100 Free Trial for 1 month. + - WHOIS - 15 Free Trial for 1 month. + +--- +[View Integration Documentation](https://xsoar.pan.dev/docs/reference/integrations/email-hippo) \ No newline at end of file diff --git a/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo_image.png b/Packs/EmailHippo/Integrations/EmailHippo/EmailHippo_image.png new file mode 100644 index 0000000000000000000000000000000000000000..29a324b0835f50f99f1271ac6c06af4515653a10 GIT binary patch literal 2963 zcmV;E3vBd>P)b(B6@D|bhonX5K->lbF`y7AVGhTRZLSnJ2&!xlfih5`I1<3(5G0O?LqHaXjXA{` zEOCV52w0GWiopU5g!>R6KnMe(xItPW(6Ku9nCX1I(r&b?U2(_=e)OlB>Q?vb*E8?y z_xerG5(x+h2nYxW2nYxW2nYxW2nYxW2nYzgSV&J2ShHqLa8XgwV8&P%TpeUtj?gr% z6kXR)PsjDINs}gJlE5nozXY#aw=UrER?RNX#MT-`FK>{xgimQU8s!?fa>6XfEKLTVp^Sgcf_O+#^rXC@IT8G<%A3b_B z5@hJ<1wd8R>5CUH{uv3>I@|;!s=h-n4nbHvACo|>qcXvrsD^-!TqIW8P^wiXlI3@H z?b>A|fm(%|V1&_zR72nu>72vih=I2{y!&wa6_S~mX<4#lNpBLUHB`=`9aKXgYwiYe zd6HJeQ$cVm=Y+CsCV^Umn_xvzZcxn;P+ceHSdVk-^CVDfa1#vAJ5A3B?6o=GZ6NU! zy!4)TJHq!q$p1V(K0b&9Y7Lb`^gen9@Y5;~dC5mt0NSg3T|!$Sh6IO&g}v?FmzI{M z=Lr};03$!Z!qDMWD-@+ilvuiSsS(GkVXIfK*88|eY3k21e+#aI z{4*xTb$88cGMN${Ja~|WML<{#6QQ>ax&m;I40;KrhH@{io#V!hvxDHin9_jz`8Noj z6&DxxS6|Nxg6n7G@BN0?W11!Qi)!?KapnHc&ql_mDovCn{o(q?=9_cMuCFr40hZ~V z)BA(q-Ha&ETc<=iiz3l~HH$7;4rcuvnsrPS8AhsJHeQtijLYQ`?UGfpal<#&k@j0v zb9{iOZVV|M9zGumujr+KO%229>~cIRE*;zDj8lisr3@bj3Sg9Y7$LdhsPRcqVN*+$ zn*w0i9FXBbFxqY*(P{@`a`N)>q|ngNsrWx4JUo2fh!G?5xXkk9%j;qOLHO7)7i#{1 zegno0LYoQW{*3+GvT@_ay1BWzNmi@%BMjM&uU;cSsK&p5f$;f|k3qYJ@%OPUtivZv z_dRm`Aao@3@^|t?=xv2(aFWHpb^CizMKJ_P6${CznB-%3rg-%4$==(mWvDlVzF%9lk^y%gm#u3+fny^3~>Q|M$|VEFLig^7uY$1raxJTJvHaLkx7Sqm2~%!`VO;?dwfK5}eduwVfX zz5Jf2V$D7pGGxf&l$4ass3+2M;6}l@pdh{7>pfq__MlZeE-bM5z+bid>J+aR-QBC~ zH~)Q@o!OF9rv65e`85VLs)jg1ktkWBnyf9j1X?S=N6a zq-#9%lc+t;HeNtp9G2hu+hXpMiuq z)s2JqU1G$__g4_5$of)=17GLL!rc*OfdFHjt_T#&j<(F76FmZbdx_vgejP}IquWffecR?8(?wea(T}ve6QO1*i-bGq2lDz>^KaBIO=?EpHMSbaD);Tt<_)A67wWIP^Tb{Tzk(APL8mZik zbBt7Hy=#Xq3*&+?jHl-|4fknIf$8#e-A+JHF^p_UWcUV0T#rc zFowIY0aqsGGQ+SuO7Q*ibzH7QPxYZj-{gJ(#`?I7QVH*&Eu1IKe6=I=9fg6++zb5agh8_r4R~@z{HM137n>_q ztZ0Y1T7Z~f?B{vtKMNw92PIfgMYv}9xVKd3%J*)E?8+7`THKF`iMfSj@j4b}d*}@V z;rs`I-!*B{#OrFKJ?bKgQZKZs|zfCQ6AE+dF{@2ZkPxdH-u@cO=p z^kVOMv88^)9FD`XqQ8R-*TQA>0kW;!c+?m1SuTt)ULb#VQKgL-lgbSCn^X-ZMenwv zSpHQ;j})sduf3)^8q1_NV1Kqq`ru5h!~2(}N%0=(yx-Jd{`~n}k(>;I0ow9cTa^8M zy&t1#C&>B`vJ8fc25Dd8Y77t4P(DV#y+ZB>kT-q8gbBwx$5J(u-ie zSDnIj4<0uK2PMuuGbt(Qwfy}2HXySMVf;$drcG6NrWPF?T}T48j;A7+pB|ab<^ib2 z!Yd;{>J1S18NBf%2?z)X2nYxW2nYxW2nYxW2nYxW2nbY<{{f%$n* **Integrations** > **Servers & Services**. +2. Search for Email Hippo. +3. Click **Add instance** to create and configure a new integration instance. + + | **Parameter** | **Description** | **Required** | + | --- | --- | --- | + | MORE Server URL (e.g., https://api.hippoapi.com) | | True | + | Email Hippo WHOIS Server URL (e.g., https://api.whoishippo.com) | | True | + | MORE API Key | | True | + | WHOIS API Key | | True | + | Source Reliability | Reliability of the source providing the intelligence data. | False | + | Create relationships | Create relationships between indicators as part of enrichment. | False | + | Trust any certificate (not secure) | | False | + | Use system proxy settings | | False | + +4. Click **Test** to validate the URLs, token, and connection. + +## Commands + +You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook. +After you successfully execute a command, a DBot message appears in the War Room with the command details. + +### email-hippo-email-quota-get + +*** +Get the email quota from the API. + +#### Base Command + +`email-hippo-email-quota-get` + +#### Input + +There are no input arguments for this command. + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| EmailHippo.Quota.quotaUsed | String | Total quota used. | +| EmailHippo.Quota.quotaRemaining | String | The remaining quota. | + +#### Command example +```!email-hippo-email-quota-get``` +#### Context Example +```json +{ + "EmailHippo": { + "Quota": { + "accountId": 7031, + "errorSummary": "Valid", + "nextQuotaResetDate": "2023-12-28T00:00:00", + "quotaRemaining": 99, + "quotaUsed": 1, + "reportedDate": "2023-11-28T12:49:16.0260781Z" + } + } +} +``` + +#### Human Readable Output + +>### Email quota +>|Email Quota remaining|Email Quota used| +>|---|---| +>| 99 | 1 | + + +### email + +*** +Return email information and reputation. + +#### Base Command + +`email` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| email | A comma-separated list of email addresses to validate. | Required | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| DBotScore.Indicator | String | The indicator that was tested. | +| DBotScore.Reliability | String | Reliability of the source providing the intelligence data. | +| DBotScore.Score | Number | The actual score. | +| DBotScore.Type | String | The indicator type. | +| DBotScore.Vendor | String | The vendor used to calculate the score. | +| Email.Address | String | The email address of the indicator. | +| Email.Domain | string | The email domain. | +| EmailHippo.Email.Address | String | The email address of the indicator. | + +#### Command example +```!email email=test@example.com``` +#### Context Example +```json +{ + "DBotScore": { + "Indicator": "test@example.com", + "Reliability": "C - Fairly reliable", + "Score": 1, + "Type": "email", + "Vendor": "Email Hippo" + }, + "Email": { + "Address": "test@example.com", + "Domain": "example.com" + }, + "EmailHippo": { + "Email": { + "Address": "test@example.com", + "diagnostic": { + "key": "e4ddf797-f25b-410b-a753-58234759a67a" + }, + "disposition": { + "isFreeMail": false, + "isRole": true + }, + "domain": null, + "emailVerification": { + "dnsVerification": { + "isDomainHasDnsRecord": true, + "isDomainHasMxRecords": true, + "mxRecords": [ + { + "exchange": ".", + "ipAddresses": null, + "preference": 0 + } + ], + "recordRoot": { + "ipAddresses": [ + "93.184.216.34" + ] + }, + "recordWww": { + "ipAddresses": [ + "93.184.216.34" + ] + }, + "txtRecords": [ + "\"wgyf8z8cgvm2qmxpnbnldrcltvk4xqfn\"", + "\"v=spf1 -all\"" + ] + }, + "mailboxVerification": { + "reason": "DomainIsWellKnownDea", + "result": "Unverifiable" + }, + "syntaxVerification": { + "isSyntaxValid": true, + "reason": "Success" + } + }, + "hippoTrust": { + "level": "Low", + "score": 0 + }, + "infrastructure": { + "mail": { + "mailServerLocation": null, + "serviceTypeId": "Other", + "smtpBanner": null + }, + "web": { + "hasAliveWebServer": true + } + }, + "meta": { + "domain": "example.com", + "email": "test@example.com", + "emailHashMd5": "55502f40dc8b7c769880b10874abc9d0", + "emailHashSha1": "567159d622ffbb50b11b0efd307be358624a26ee", + "emailHashSha256": "973dfe463ec85785f5f95af5ba3906eedb2d931c24e69824a89ea65dba4e813b", + "expires": "Sat, 24 Feb 2024 23:31:57 GMT", + "lastModified": "Mon, 28 Aug 2023 23:31:57 GMT", + "subDomain": null, + "tld": "com", + "user": "test" + }, + "performance": { + "dnsLookup": 740, + "mailboxVerification": 0, + "other": 0, + "overallExecutionTime": 818, + "spamAssessment": 0, + "syntaxCheck": 0, + "webInfrastructurePing": 78 + }, + "sendAssess": { + "inboxQualityScore": 0.1, + "sendRecommendation": "DoNotSend" + }, + "social": { + "gravatar": { + "imageUrl": "//www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0", + "profileUrl": "//www.gravatar.com/55502f40dc8b7c769880b10874abc9d0" + } + }, + "spamAssess": { + "actionRecomendation": "Block", + "blockLists": [ + { + "blockListName": "spamhaus", + "isListed": false, + "listedMoreInfo": null, + "listedReason": null + } + ], + "domainRiskScore": 10, + "formatRiskScore": 0, + "isDarkWebEmailAddress": false, + "isDisposableEmailAddress": true, + "isGibberishDomain": false, + "isGibberishUser": false, + "overallRiskScore": 10, + "profanityRiskScore": 0 + }, + "spamTrapAssess": { + "isSpamTrap": false, + "spamTrapDescriptor": null + }, + "version": { + "doc": "https://api-docs.emailhippo.com/en/latest/", + "v": "More-(1.2.1091)" + } + } + } +} +``` + +#### Human Readable Output + +>### Email test@example.com +>|Hippo Trust Score|Inbox quality score|Result|Spam risk score| +>|---|---|---|---| +>| Low | DoNotSend | result: Unverifiable
reason: DomainIsWellKnownDea | Block | + + +### domain + +*** +Returns domain information and reputation. + +#### Base Command + +`domain` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| domain | The domain to query (CSV). | Required | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| DBotScore.Indicator | String | The indicator that was tested. | +| DBotScore.Reliability | String | The reliability score of the vendor. | +| DBotScore.Score | Number | The actual score. | +| DBotScore.Type | String | The indicator type. | +| DBotScore.Vendor | String | The vendor used to calculate the score. | +| Domain.Name | String | The name of the domain that was checked. | +| Domain.NameServers | String | Name of the servers of the domain. | +| Domain.UpdatedDate | Date | The date that the domain was last updated. | +| Domain.CreationDate | Date | The creation date of the domain. Format is ISO8601 \(i.e.,'2020-04-30T10:35:00.000Z'\). | +| Domain.Registrar.Name | String | The name of the registrar. | +| Domain.Registrar.AbuseEmail | String | The email address of the contact for reporting abuse. | +| Domain.Registrar.AbusePhone | String | The phone number of the contact for reporting abuse. | +| Domain.Admin.Country | String | The country of the domain administrator. | +| Domain.Admin.Email | String | The email address of the domain administrator. | +| Domain.Admin.Name | String | The name of the domain administrator. | +| Domain.Admin.Phone | String | The phone number of the domain administrator. | +| Domain.Tech.Country | String | The country of tech administrator. | +| Domain.Tech.Name | String | The name of the tech administrator. | +| Domain.Tech.Email | String | The email of the tech administrator. | +| Domain.Tech.Organization | String | The organization of the tech administrator. | +| Domain.WHOIS.NameServers | String | A CSV string of name servers, for example 'ns1.bla.com, ns2.bla.com'. | +| Domain.WHOIS.CreationDate | Date | The creation date of the domain. Format is ISO8601 \(i.e., '2020-04-30T10:35:00.000Z'\). | +| Domain.WHOIS.UpdatedDate | Date | The date when the domain was last updated. Format is ISO8601 \(i.e., '2020-04-30T10:35:00.000Z'\). | +| Domain.WHOIS.ExpirationDate | Date | The expiration date of the domain. | + +#### Command example +```!domain domain=example.com``` +#### Context Example +```json +{ + "DBotScore": { + "Indicator": "example.com", + "Reliability": "C - Fairly reliable", + "Score": 0, + "Type": "domain", + "Vendor": "Email Hippo" + }, + "Domain": { + "CreationDate": "2018-08-21T14:02:43.000Z", + "Name": "example.com", + "NameServers": [ + { + "Address": "A.example.NET" + }, + { + "Address": "B.example.NET" + } + ], + "UpdatedDate": "2018-08-21T14:02:43.000Z", + "WHOIS": { + "CreationDate": "2018-08-21T14:02:43.000Z", + "NameServers": [ + { + "Address": "A.example.NET" + }, + { + "Address": "B.example.NET" + } + ], + "UpdatedDate": "2018-08-21T14:02:43.000Z" + } + }, + "EmailHippo": { + "Domain": { + "creation_date": "2018-08-21T14:02:43.000Z", + "domain": "example.com", + "meta": { + "domain": "example.com", + "domainAge": "0 year(s), 0 month(s), 0 week(s), 0 day(s)", + "domainAgeIso8601": "P0D", + "domainAgeSeconds": 0, + "executionTime": 2092, + "parseCode": "Success", + "recordAge": "5 year(s), 3 months, 0 week(s), 6 day(s), 22 hour(s), 46 minute(s)", + "recordAgeIso8601": "P5Y3M6DT22H46M23.4811208S", + "recordCreatedDate": "2018-08-21T14:02:43Z", + "recordUpdatedDate": "2018-08-21T14:02:43Z", + "timeToExpiry": "0 year(s), 0 months, 0 week(s), 0 day(s)", + "timeToExpiryIso8601": "P0D", + "timeToExpirySeconds": 0, + "tld": "com" + }, + "updated_date": "2018-08-21T14:02:43.000Z", + "version": { + "doc": "https://emailhippo.github.io/whois-developers", + "v": "1.0.511" + }, + "whoisServerRecord": { + "adminContact": { + "city": "", + "country": "", + "email": "", + "faxNumber": "", + "faxNumberExt": "", + "name": "", + "organization": "", + "phoneNumber": "", + "phoneNumberExt": "", + "postalCode": "", + "state": "", + "street1": "", + "street2": null, + "street3": null, + "street4": null, + "userId": "" + }, + "billingContact": { + "city": null, + "country": null, + "email": null, + "faxNumber": null, + "faxNumberExt": null, + "name": null, + "organization": null, + "phoneNumber": null, + "phoneNumberExt": null, + "postalCode": null, + "state": null, + "street1": null, + "street2": null, + "street3": null, + "street4": null, + "userId": null + }, + "changed": null, + "created": null, + "customFields": null, + "dnsSec": "", + "domainHandle": "", + "domainName": "example.com", + "domainOwnerContact": { + "city": "", + "country": "", + "email": "", + "faxNumber": "", + "faxNumberExt": "", + "name": "", + "organization": "", + "phoneNumber": "", + "phoneNumberExt": "", + "postalCode": "", + "state": "", + "street1": "", + "street2": null, + "street3": null, + "street4": null, + "userId": "" + }, + "domainStati": null, + "expiry": null, + "nameServers": [ + { + "Address": "A.example.NET" + }, + { + "Address": "B.example.NET" + } + ], + "recordFound": true, + "registrar": { + "abuseEmail": "", + "abusePhone": "", + "name": "", + "registrarId": "", + "url": "", + "whois": "--UNSPECIFIED--" + }, + "registrarContact": { + "city": null, + "country": null, + "email": null, + "faxNumber": null, + "faxNumberExt": null, + "name": null, + "organization": null, + "phoneNumber": null, + "phoneNumberExt": null, + "postalCode": null, + "state": null, + "street1": null, + "street2": null, + "street3": null, + "street4": null, + "userId": null + }, + "remarks": null, + "reseller": "", + "techContact": { + "city": "", + "country": "", + "email": "", + "faxNumber": "", + "faxNumberExt": "", + "name": "", + "organization": "", + "phoneNumber": "", + "phoneNumberExt": "", + "postalCode": "", + "state": "", + "street1": "", + "street2": null, + "street3": null, + "street4": null, + "userId": "" + }, + "tld": "com", + "zoneContact": { + "city": null, + "country": null, + "email": null, + "faxNumber": null, + "faxNumberExt": null, + "name": null, + "organization": null, + "phoneNumber": null, + "phoneNumberExt": null, + "postalCode": null, + "state": null, + "street1": null, + "street2": null, + "street3": null, + "street4": null, + "userId": null + } + } + } + } +} +``` + +#### Human Readable Output + +>### Domain example.com +>|Domain Age|Expires On|Name servers|Registered On|Registrar|Status|Time To Expiry|Updated On| +>|---|---|---|---|---|---|---|---| +>| 0 year(s), 0 month(s), 0 week(s), 0 day(s) | | {'Address': 'A.example.NET'},
{'Address': 'B.example.NET'} | | | | 0 year(s), 0 months, 0 week(s), 0 day(s) | | + diff --git a/Packs/EmailHippo/Integrations/EmailHippo/commands.txt b/Packs/EmailHippo/Integrations/EmailHippo/commands.txt new file mode 100644 index 000000000000..45206121be54 --- /dev/null +++ b/Packs/EmailHippo/Integrations/EmailHippo/commands.txt @@ -0,0 +1,3 @@ +!domain domain=example.com +!email email=test@example.com +!email-hippo-email-quota-get \ No newline at end of file diff --git a/Packs/EmailHippo/Integrations/EmailHippo/test_data/get_domain_output.json b/Packs/EmailHippo/Integrations/EmailHippo/test_data/get_domain_output.json new file mode 100644 index 000000000000..2d63c0e0f323 --- /dev/null +++ b/Packs/EmailHippo/Integrations/EmailHippo/test_data/get_domain_output.json @@ -0,0 +1,369 @@ +{ + "api_result": { + "meta": { + "recordCreatedDate": "2018-07-20T13:27:00Z", + "recordUpdatedDate": "2023-11-05T14:28:35Z", + "recordAge": "0 year(s), 0 months, 3 week(s), 0 day(s), 18 hour(s), 37 minute(s)", + "recordAgeIso8601": "P21DT18H37M20.4673999S", + "timeToExpiry": "4 year(s), 9 months, 2 week(s), 3 day(s)", + "timeToExpirySeconds": 151365244, + "timeToExpiryIso8601": "P4Y9M17D", + "tld": "com", + "domain": "example.com", + "domainAge": "26 year(s), 2 month(s), 1 week(s), 5 day(s)", + "domainAgeSeconds": 826769155, + "domainAgeIso8601": "P26Y2M12D", + "parseCode": "Success", + "executionTime": 354 + }, + "whoisServerRecord": { + "recordFound": true, + "registrar": { + "registrarId": "000", + "name": "example", + "whois": "whois.example.com", + "url": "http://www.example.com", + "abuseEmail": "test@example.com", + "abusePhone": "+1.00000000" + }, + "dnsSec": "unsigned", + "domainName": "example.com", + "tld": "com", + "domainHandle": "XXXXX", + "domainOwnerContact": { + "userId": "", + "name": "", + "organization": "example", + "street1": "", + "street2": null, + "street3": null, + "street4": null, + "city": "", + "state": "CA", + "postalCode": "", + "country": "US", + "phoneNumber": "", + "phoneNumberExt": "", + "faxNumber": "", + "faxNumberExt": "", + "email": "" + }, + "adminContact": { + "userId": "", + "name": "", + "organization": "example", + "street1": "", + "street2": null, + "street3": null, + "street4": null, + "city": "", + "state": "CA", + "postalCode": "", + "country": "US", + "phoneNumber": "", + "phoneNumberExt": "", + "faxNumber": "", + "faxNumberExt": "", + "email": "test@example.com" + }, + "billingContact": { + "userId": null, + "name": null, + "organization": null, + "street1": null, + "street2": null, + "street3": null, + "street4": null, + "city": null, + "state": null, + "postalCode": null, + "country": null, + "phoneNumber": null, + "phoneNumberExt": null, + "faxNumber": null, + "faxNumberExt": null, + "email": null + }, + "techContact": { + "userId": "", + "name": "", + "organization": "example", + "street1": "", + "street2": null, + "street3": null, + "street4": null, + "city": "", + "state": "CA", + "postalCode": "", + "country": "US", + "phoneNumber": "", + "phoneNumberExt": "", + "faxNumber": "", + "faxNumberExt": "", + "email": "test@example.com" + }, + "registrarContact": { + "userId": null, + "name": null, + "organization": null, + "street1": null, + "street2": null, + "street3": null, + "street4": null, + "city": null, + "state": null, + "postalCode": null, + "country": null, + "phoneNumber": null, + "phoneNumberExt": null, + "faxNumber": null, + "faxNumberExt": null, + "email": null + }, + "zoneContact": { + "userId": null, + "name": null, + "organization": null, + "street1": null, + "street2": null, + "street3": null, + "street4": null, + "city": null, + "state": null, + "postalCode": null, + "country": null, + "phoneNumber": null, + "phoneNumberExt": null, + "faxNumber": null, + "faxNumberExt": null, + "email": null + }, + "nameServers": [ + { + "Address": "example.com" + } + ], + "domainStati": [], + "remarks": null, + "reseller": "", + "created": "1997-09-15T07:00:00Z", + "changed": "2019-09-09T15:39:04Z", + "expiry": "2028-09-13T07:00:00Z", + "customFields": null + } + }, + "expected_context": { + "Domain(val.Name && val.Name == obj.Name)": [ + { + "Name": "example.com", + "Registrar": { + "Name": "example", + "AbuseEmail": "test@example.com", + "AbusePhone": "+1.00000000" + }, + "Admin": { + "Name": "", + "Email": "test@example.com", + "Phone": "", + "Country": "US" + }, + "CreationDate": "2018-07-20T13:27:00.000Z", + "UpdatedDate": "2023-11-05T14:28:35.000Z", + "NameServers": [ + { + "Address": "example.com" + } + ], + "Tech": { + "Country": "US", + "Organization": "example", + "Email": "test@example.com" + }, + "WHOIS": { + "Registrar": { + "Name": "example", + "AbuseEmail": "test@example.com", + "AbusePhone": "+1.00000000" + }, + "Admin": { + "Name": "", + "Email": "test@example.com", + "Phone": "", + "Country": "US" + }, + "CreationDate": "2018-07-20T13:27:00.000Z", + "UpdatedDate": "2023-11-05T14:28:35.000Z", + "NameServers": [ + { + "Address": "example.com" + } + ] + } + } + ], + "DBotScore(val.Indicator && val.Indicator == obj.Indicator && val.Vendor == obj.Vendor && val.Type == obj.Type)": [ + { + "Indicator": "example.com", + "Type": "domain", + "Vendor": "Email Hippo", + "Score": 0 + } + ], + "EmailHippo.Domain(val.domain && val.domain == obj.domain)": { + "meta": { + "recordCreatedDate": "2018-07-20T13:27:00Z", + "recordUpdatedDate": "2023-11-05T14:28:35Z", + "recordAge": "0 year(s), 0 months, 3 week(s), 0 day(s), 18 hour(s), 37 minute(s)", + "recordAgeIso8601": "P21DT18H37M20.4673999S", + "timeToExpiry": "4 year(s), 9 months, 2 week(s), 3 day(s)", + "timeToExpirySeconds": 151365244, + "timeToExpiryIso8601": "P4Y9M17D", + "tld": "com", + "domain": "example.com", + "domainAge": "26 year(s), 2 month(s), 1 week(s), 5 day(s)", + "domainAgeSeconds": 826769155, + "domainAgeIso8601": "P26Y2M12D", + "parseCode": "Success", + "executionTime": 354 + }, + "whoisServerRecord": { + "recordFound": true, + "registrar": { + "registrarId": "000", + "name": "example", + "whois": "whois.example.com", + "url": "http://www.example.com", + "abuseEmail": "test@example.com", + "abusePhone": "+1.00000000" + }, + "dnsSec": "unsigned", + "domainName": "example.com", + "tld": "com", + "domainHandle": "XXXXX", + "domainOwnerContact": { + "userId": "", + "name": "", + "organization": "example", + "street1": "", + "street2": null, + "street3": null, + "street4": null, + "city": "", + "state": "CA", + "postalCode": "", + "country": "US", + "phoneNumber": "", + "phoneNumberExt": "", + "faxNumber": "", + "faxNumberExt": "", + "email": "" + }, + "adminContact": { + "userId": "", + "name": "", + "organization": "example", + "street1": "", + "street2": null, + "street3": null, + "street4": null, + "city": "", + "state": "CA", + "postalCode": "", + "country": "US", + "phoneNumber": "", + "phoneNumberExt": "", + "faxNumber": "", + "faxNumberExt": "", + "email": "test@example.com" + }, + "billingContact": { + "userId": null, + "name": null, + "organization": null, + "street1": null, + "street2": null, + "street3": null, + "street4": null, + "city": null, + "state": null, + "postalCode": null, + "country": null, + "phoneNumber": null, + "phoneNumberExt": null, + "faxNumber": null, + "faxNumberExt": null, + "email": null + }, + "techContact": { + "userId": "", + "name": "", + "organization": "example", + "street1": "", + "street2": null, + "street3": null, + "street4": null, + "city": "", + "state": "CA", + "postalCode": "", + "country": "US", + "phoneNumber": "", + "phoneNumberExt": "", + "faxNumber": "", + "faxNumberExt": "", + "email": "test@example.com" + }, + "registrarContact": { + "userId": null, + "name": null, + "organization": null, + "street1": null, + "street2": null, + "street3": null, + "street4": null, + "city": null, + "state": null, + "postalCode": null, + "country": null, + "phoneNumber": null, + "phoneNumberExt": null, + "faxNumber": null, + "faxNumberExt": null, + "email": null + }, + "zoneContact": { + "userId": null, + "name": null, + "organization": null, + "street1": null, + "street2": null, + "street3": null, + "street4": null, + "city": null, + "state": null, + "postalCode": null, + "country": null, + "phoneNumber": null, + "phoneNumberExt": null, + "faxNumber": null, + "faxNumberExt": null, + "email": null + }, + "nameServers": [ + { + "Address": "example.com" + } + ], + "domainStati": [], + "remarks": null, + "reseller": "", + "created": "1997-09-15T07:00:00Z", + "changed": "2019-09-09T15:39:04Z", + "expiry": "2028-09-13T07:00:00Z", + "customFields": null + }, + "domain": "example.com", + "creation_date": "2018-07-20T13:27:00.000Z", + "updated_date": "2023-11-05T14:28:35.000Z" + } + } +} \ No newline at end of file diff --git a/Packs/EmailHippo/Integrations/EmailHippo/test_data/get_email_output.json b/Packs/EmailHippo/Integrations/EmailHippo/test_data/get_email_output.json new file mode 100644 index 000000000000..59fa0fbe6a36 --- /dev/null +++ b/Packs/EmailHippo/Integrations/EmailHippo/test_data/get_email_output.json @@ -0,0 +1,179 @@ +{ + "api_result": { + "meta": { + "lastModified": "Mon, 27 Nov 2023 08:56:58 GMT", + "expires": "Thu, 07 Dec 2023 08:56:58 GMT", + "email": "test@example.com", + "tld": null, + "domain": "example.com", + "subDomain": null, + "user": "test" + }, + "disposition": { + "isRole": false, + "isFreeMail": false + }, + "emailVerification": { + "syntaxVerification": { + "isSyntaxValid": true, + "reason": "Success" + }, + "dnsVerification": { + "isDomainHasDnsRecord": false, + "isDomainHasMxRecords": false, + "recordRoot": null, + "recordWww": null, + "mxRecords": null, + "txtRecords": null + }, + "mailboxVerification": { + "result": "Bad", + "reason": "DomainIsInexistent" + } + }, + "infrastructure": { + "mail": { + "serviceTypeId": "Other", + "mailServerLocation": null, + "smtpBanner": null + }, + "web": { + "hasAliveWebServer": false + } + }, + "sendAssess": { + "inboxQualityScore": 0, + "sendRecommendation": "None" + }, + "spamAssess": { + "isDisposableEmailAddress": false, + "isDarkWebEmailAddress": false, + "isGibberishDomain": false, + "isGibberishUser": false, + "domainRiskScore": 0, + "formatRiskScore": 0, + "profanityRiskScore": 0, + "overallRiskScore": 0, + "actionRecomendation": "None", + "blockLists": [] + }, + "spamTrapAssess": { + "isSpamTrap": false, + "spamTrapDescriptor": null + }, + "hippoTrust": { + "score": 0, + "level": "None" + }, + "social": { + "gravatar": null + }, + "domain": null, + "performance": { + "syntaxCheck": 0, + "dnsLookup": 10, + "spamAssessment": 0, + "mailboxVerification": 0, + "webInfrastructurePing": 0, + "other": 0, + "overallExecutionTime": 0 + } + }, + "expected_context": { + "Email(val.Address && val.Address == obj.Address)": [ + { + "Address": "test@example.com", + "Domain": "example.com" + } + ], + "DBotScore(val.Indicator && val.Indicator == obj.Indicator && val.Vendor == obj.Vendor && val.Type == obj.Type)": [ + { + "Indicator": "test@example.com", + "Type": "email", + "Vendor": "Email Hippo", + "Score": 0 + } + ], + "EmailHippo.Email(val.Address && val.Address == obj.Address)": { + "meta": { + "lastModified": "Mon, 27 Nov 2023 08:56:58 GMT", + "expires": "Thu, 07 Dec 2023 08:56:58 GMT", + "email": "test@example.com", + "tld": null, + "domain": "example.com", + "subDomain": null, + "user": "test" + }, + "disposition": { + "isRole": false, + "isFreeMail": false + }, + "emailVerification": { + "syntaxVerification": { + "isSyntaxValid": true, + "reason": "Success" + }, + "dnsVerification": { + "isDomainHasDnsRecord": false, + "isDomainHasMxRecords": false, + "recordRoot": null, + "recordWww": null, + "mxRecords": null, + "txtRecords": null + }, + "mailboxVerification": { + "result": "Bad", + "reason": "DomainIsInexistent" + } + }, + "infrastructure": { + "mail": { + "serviceTypeId": "Other", + "mailServerLocation": null, + "smtpBanner": null + }, + "web": { + "hasAliveWebServer": false + } + }, + "sendAssess": { + "inboxQualityScore": 0, + "sendRecommendation": "None" + }, + "spamAssess": { + "isDisposableEmailAddress": false, + "isDarkWebEmailAddress": false, + "isGibberishDomain": false, + "isGibberishUser": false, + "domainRiskScore": 0, + "formatRiskScore": 0, + "profanityRiskScore": 0, + "overallRiskScore": 0, + "actionRecomendation": "None", + "blockLists": [] + }, + "spamTrapAssess": { + "isSpamTrap": false, + "spamTrapDescriptor": null + }, + "hippoTrust": { + "score": 0, + "level": "None" + }, + "social": { + "gravatar": null + }, + "domain": null, + "performance": { + "syntaxCheck": 0, + "dnsLookup": 10, + "spamAssessment": 0, + "mailboxVerification": 0, + "webInfrastructurePing": 0, + "other": 0, + "overallExecutionTime": 0 + }, + "Address": "test@example.com" + } + } +} \ No newline at end of file diff --git a/Packs/EmailHippo/Integrations/EmailHippo/test_data/get_quota_output.json b/Packs/EmailHippo/Integrations/EmailHippo/test_data/get_quota_output.json new file mode 100644 index 000000000000..29a2e12cb227 --- /dev/null +++ b/Packs/EmailHippo/Integrations/EmailHippo/test_data/get_quota_output.json @@ -0,0 +1,9 @@ +{ + "licenseKey": "abc123", + "accountId": 1000, + "quotaUsed": 4, + "quotaRemaining": 96, + "nextQuotaResetDate": "2023-12-26T00:00:00", + "reportedDate": "2023-11-27T13:35:09.519314Z", + "errorSummary": "Valid" +} \ No newline at end of file diff --git a/Packs/EmailHippo/README.md b/Packs/EmailHippo/README.md new file mode 100644 index 000000000000..d4bad15dfb04 --- /dev/null +++ b/Packs/EmailHippo/README.md @@ -0,0 +1,6 @@ +Email Hippo is an email intelligence and data services provider that delivers accurate cloud-based email validation and domain profiling. + + +## What does this pack do? +- Checks the reputation of a given domain name or email address. +- Returns enrichment data for a domain or email address for available indicators (observables). \ No newline at end of file diff --git a/Packs/EmailHippo/TestPlaybooks/HippoEmailTest.yml b/Packs/EmailHippo/TestPlaybooks/HippoEmailTest.yml new file mode 100644 index 000000000000..7343330be37a --- /dev/null +++ b/Packs/EmailHippo/TestPlaybooks/HippoEmailTest.yml @@ -0,0 +1,354 @@ +id: HippoEmailTest +version: -1 +name: HippoEmailTest +starttaskid: "0" +tasks: + "0": + id: "0" + taskid: f19ef288-f056-4d2a-89e1-dbe3b2cbe927 + type: start + task: + id: f19ef288-f056-4d2a-89e1-dbe3b2cbe927 + version: -1 + name: "" + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "1" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 265, + "y": 50 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "1": + id: "1" + taskid: 9b2f7ab9-ddd3-4777-825b-b971b044ba7f + type: regular + task: + id: 9b2f7ab9-ddd3-4777-825b-b971b044ba7f + version: -1 + name: Delete Context + description: |- + Delete field from context. + + This automation runs using the default Limited User role, unless you explicitly change the permissions. + For more information, see the section about permissions here: + https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/6.10/Cortex-XSOAR-Administrator-Guide/Automations + scriptName: DeleteContext + type: regular + iscommand: false + brand: "" + nexttasks: + '#none#': + - "2" + - "3" + scriptarguments: + all: + simple: "yes" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 265, + "y": 195 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "2": + id: "2" + taskid: ef8fc6c7-b748-45d9-8004-557005fadaa2 + type: regular + task: + id: ef8fc6c7-b748-45d9-8004-557005fadaa2 + version: -1 + name: Domain reputation + description: Returns Domain information and reputation. + script: Email Hippo|||domain + type: regular + iscommand: true + brand: Email Hippo + nexttasks: + '#none#': + - "4" + scriptarguments: + domain: + simple: ${inputs.first_domain},${inputs.second_doman} + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 370 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "3": + id: "3" + taskid: f0c1c160-51ad-4256-80d9-34f9e93b744f + type: regular + task: + id: f0c1c160-51ad-4256-80d9-34f9e93b744f + version: -1 + name: Email reputation + description: Return Email information and reputation. + script: Email Hippo|||email + type: regular + iscommand: true + brand: Email Hippo + nexttasks: + '#none#': + - "4" + scriptarguments: + email: + simple: ${inputs.first_email},${inputs.second_email} + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 370 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "4": + id: "4" + taskid: 025935b9-6282-480e-898a-a41758ea16c2 + type: condition + task: + id: 025935b9-6282-480e-898a-a41758ea16c2 + version: -1 + name: Check response + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "6" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: containsGeneral + left: + value: + simple: Domain.Name + iscontext: true + right: + value: + simple: inputs.first_domain + iscontext: true + - - operator: containsGeneral + left: + value: + simple: Domain.Name + iscontext: true + right: + value: + simple: inputs.second_doman + iscontext: true + - - operator: containsGeneral + left: + value: + simple: Email.Address + iscontext: true + right: + value: + simple: inputs.first_email + iscontext: true + - - operator: containsGeneral + left: + value: + simple: Email.Address + iscontext: true + right: + value: + simple: inputs.second_email + iscontext: true + continueonerrortype: "" + view: |- + { + "position": { + "x": 265, + "y": 545 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "5": + id: "5" + taskid: 47f514ec-837a-408d-8380-b671802b1bfc + type: title + task: + id: 47f514ec-837a-408d-8380-b671802b1bfc + version: -1 + name: Done + type: title + iscommand: false + brand: "" + description: '' + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 265, + "y": 1070 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "6": + id: "6" + taskid: 21370938-6637-4d72-8177-8d5a8457f4b0 + type: regular + task: + id: 21370938-6637-4d72-8177-8d5a8457f4b0 + version: -1 + name: Get quota + description: Get the Email quota from the API. + script: Email Hippo|||email-hippo-email-quota-get + type: regular + iscommand: true + brand: Email Hippo + nexttasks: + '#none#': + - "7" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 265, + "y": 720 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "7": + id: "7" + taskid: c89af4cb-141f-49d6-86b0-6414ebbf786f + type: condition + task: + id: c89af4cb-141f-49d6-86b0-6414ebbf786f + version: -1 + name: Check response + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "5" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isNotEmpty + left: + value: + simple: EmailHippo.Quota.quotaUsed + iscontext: true + continueonerrortype: "" + view: |- + { + "position": { + "x": 265, + "y": 895 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false +view: |- + { + "linkLabelsPosition": {}, + "paper": { + "dimensions": { + "height": 1085, + "width": 810, + "x": 50, + "y": 50 + } + } + } +inputs: +- key: first_domain + value: + simple: google.com + required: false + description: "" + playbookInputQuery: +- key: second_doman + value: + simple: bing.com + required: false + description: "" + playbookInputQuery: +- key: first_email + value: + simple: test@example.com + required: false + description: "" + playbookInputQuery: +- key: second_email + value: + simple: test@example_1.com + required: false + description: "" + playbookInputQuery: +outputs: [] +quiet: true +fromversion: 6.10.0 +description: '' diff --git a/Packs/EmailHippo/pack_metadata.json b/Packs/EmailHippo/pack_metadata.json new file mode 100644 index 000000000000..67235a1e3ff9 --- /dev/null +++ b/Packs/EmailHippo/pack_metadata.json @@ -0,0 +1,21 @@ +{ + "name": "Email Hippo", + "description": "Use this tool to verify email sources as fake emails that were used as part of phishing attacks.", + "support": "xsoar", + "currentVersion": "1.0.0", + "author": "Cortex XSOAR", + "url": "https://www.paloaltonetworks.com/cortex", + "email": "", + "categories": [ + "Data Enrichment & Threat Intelligence" + ], + "tags": [], + "useCases": [ + "Phishing" + ], + "keywords": [], + "marketplaces": [ + "xsoar", + "marketplacev2" + ] +} \ No newline at end of file