diff --git a/.github/workflows/review-release.yml b/.github/workflows/review-release.yml new file mode 100644 index 0000000..6f3bf31 --- /dev/null +++ b/.github/workflows/review-release.yml @@ -0,0 +1,22 @@ +name: Review Release +concurrency: + group: app-release + cancel-in-progress: true +permissions: + contents: read + id-token: write + statuses: write +on: + workflow_dispatch: + inputs: + task_token: + description: 'StepFunction task token' + required: true + +jobs: + review: + uses: 'phantomcyber/dev-cicd-tools/.github/workflows/review-release.yml@main' + with: + task_token: ${{ inputs.task_token }} + secrets: + resume_release_role_arn: ${{ secrets.RESUME_RELEASE_ROLE_ARN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d591a81..0d38655 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,11 @@ repos: - repo: https://github.com/phantomcyber/dev-cicd-tools - rev: v1.11 + rev: v1.13 hooks: - id: org-hook - id: package-app-dependencies - repo: https://github.com/Yelp/detect-secrets - rev: v1.2.0 + rev: v1.3.0 hooks: - id: detect-secrets args: ['--no-verify', '--exclude-files', '^recordedfuture.json$'] diff --git a/README.md b/README.md index 5fd59ae..2260b5e 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ # Recorded Future Publisher: Recorded Future, Inc -Connector Version: 3\.1\.0 +Connector Version: 4\.0\.0 Product Vendor: Recorded Future, Inc Product Name: Recorded Future App for Phantom Product Version Supported (regex): "\.\*" -Minimum Product Version: 5\.1\.0 +Minimum Product Version: 5\.3\.0 This app implements investigative actions to perform lookups for quick reputation information, contextual threat intelligence and external threat alerts @@ -36,37 +36,20 @@ defenses through automation and orchestration. The Recorded Future App provides that enable the creation of Playbooks to do automated enrichment, correlation, threat hunting, and alert handling. -## Recorded Future Demo Playbooks +# Ingest alerts into events -Together with the Recorded Future App for Phantom 3.0, a new demo playbook was created and uploaded -to the community site. The new playbook incorporates the new assessment functionality. +With alerting rules set up in your Recorded Future enterprise, triggered alerts can now be ingested +in Splunk SOAR as events.The ingestion configuration is set per asset under the tabs "Asset +Settings" and "Ingest Settings". -Four demo playbooks were released with the Recorded Future App for Phantom 2.0 to show how the -actions in the app can be used. The playbooks are designed to operate on a Recorded Future App asset -named "recorded-future" and Phantom SMTP asset named "smtp". If the assets are named differently, -the playbooks will be adjusted. The email address used for the alert emails is specified in the -linked SMTP asset. +"Asset Settings" defines a list of rule IDs, what severity to apply to the new events and set the +limits for the number of events created by the ingestion. -**Correlation Playbook** -This playbook shows how to obtain IP reputation and, if its risk score is 90 or more, add the IP -address to a bad IP address list maintained by Phantom plus forward the information to Splunk and in -an email. + -**Enrichment Playbook** -This playbook shows how to obtain intelligence of an IP address and, if its risk score is 90 or -more, to forward this in an email as well as adding the IP to a bad IP address list maintained by -Phantom. +The scheduling of the ingestion is set under "Ingest Settings" -**Threat Hunting Playbook** -The purpose of this playbook is to find out the IP reputation and when its risk score is 90 or -above, to find related entities - IP addresses, domains, files, vulnerabilities, and/or URLs - and -to search for them in Splunk. The results are summarised in an email and the IP address is added to -the bad IP address list maintained by Phantom. - -**Handling of Leaked Credentials** -The purpose of this playbook is to demonstrate how Recorded Future Alerts can be used to monitor -various threats such as leaked credentials. The playbook is designed to be scheduled, polling for -new alerts each time it is run. If an alert is found the information is forwarded via an email. +![](img/recorded_future_asset_ingest.png) ### Configuration Variables @@ -74,14 +57,22 @@ The below configuration variables are required for this Connector to operate. T VARIABLE | REQUIRED | TYPE | DESCRIPTION -------- | -------- | ---- | ----------- -**recordedfuture\_base\_url** | required | string | Recorded Future API Basename -**recordedfuture\_api\_token** | required | password | Recorded Future API Token -**recordedfuture\_verify\_ssl** | optional | boolean | Verify SSL Certificates +**recordedfuture\_base\_url** | required | string | Recorded Future API basename +**recordedfuture\_api\_token** | required | password | Recorded Future API token +**recordedfuture\_verify\_ssl** | optional | boolean | Verify SSL certificates +**ph1** | optional | ph | +**ph2** | optional | ph | +**on\_poll\_alert\_ruleids** | optional | string | Comma\-separated list of alert rule IDs +**on\_poll\_alert\_severity** | optional | string | Severity to apply to the alert event +**max\_count** | optional | numeric | Max events to ingest for scheduled polling +**first\_max\_count** | optional | numeric | Max events to ingest for scheduled polling first time ### Supported Actions [test connectivity](#action-test-connectivity) - Validate the asset configuration for connectivity -[alert data lookup](#action-alert-data-lookup) - Get details on alerts configured and generated by Recorded Future by alert rule ID and/or time range -[alert rule lookup](#action-alert-rule-lookup) - Search for alert rule IDs by name +[alert update](#action-alert-update) - Update status and/or notes for the alert specified with alert\_id +[alert search](#action-alert-search) - Get details on alerts configured and generated by Recorded Future by alert rule ID and time range +[alert lookup](#action-alert-lookup) - Get details on an alert +[alert rule search](#action-alert-rule-search) - Search for alert rule IDs by name [url intelligence](#action-url-intelligence) - Get threat intelligence for a URL [url reputation](#action-url-reputation) - Get a quick indicator of the risk associated with a URL [vulnerability intelligence](#action-vulnerability-intelligence) - Get threat intelligence for a vulnerability @@ -94,6 +85,7 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION [ip reputation](#action-ip-reputation) - Get a quick indicator of the risk associated with an IP address [threat assessment](#action-threat-assessment) - Get an indicator of the risk for a collection of entities based on context [list contexts](#action-list-contexts) - Get a list of possible contexts to use in threat assessment +[on poll](#action-on-poll) - Ingest alerts from Recorded Future ## action: 'test connectivity' Validate the asset configuration for connectivity @@ -107,8 +99,42 @@ No parameters are required for this action #### Action Output No Output -## action: 'alert data lookup' -Get details on alerts configured and generated by Recorded Future by alert rule ID and/or time range +## action: 'alert update' +Update status and/or notes for the alert specified with alert\_id + +Type: **investigate** +Read only: **True** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**alert\_id** | required | Alert ID specifying which alert to update | string | `recordedfuture alert id` +**alert\_status** | required | New alert status | string | +**alert\_note** | required | Text to be added to the alert | string | + +#### Action Output +DATA PATH | TYPE | CONTAINS +--------- | ---- | -------- +action\_result\.status | string | +action\_result\.parameter\.alert\_id | string | `recordedfuture alert id` +action\_result\.parameter\.alert\_status | string | +action\_result\.parameter\.alert\_note | string | +action\_result\.data\.\*\.id | string | +action\_result\.data\.\*\.note\.date | string | +action\_result\.data\.\*\.note\.text | string | +action\_result\.data\.\*\.note\.author | string | +action\_result\.data\.\*\.title | string | +action\_result\.data\.\*\.status | string | +action\_result\.data\.\*\.statusDate | string | +action\_result\.data\.\*\.statusChangeBy | string | +action\_result\.summary\.update | string | +action\_result\.summary\.reason | string | +action\_result\.message | string | +summary\.total\_objects | numeric | `recordedfuture total objects` +summary\.total\_objects\_successful | numeric | `recordedfuture total objects successful` + +## action: 'alert search' +Get details on alerts configured and generated by Recorded Future by alert rule ID and time range Type: **investigate** Read only: **True** @@ -117,58 +143,245 @@ Read only: **True** PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS --------- | -------- | ----------- | ---- | -------- **rule\_id** | required | Alert Rule ID to look up alert data for | string | `recordedfuture alert rule id` -**timeframe** | required | Time range for when rules were triggered | string | `recordedfuture alert timerange` +**timeframe** | required | Time range for when rules were triggered | string | #### Action Output DATA PATH | TYPE | CONTAINS --------- | ---- | -------- -action\_result\.status | string | `recordedfuture result status` +action\_result\.status | string | action\_result\.parameter\.rule\_id | string | `recordedfuture alert rule id` -action\_result\.parameter\.timeframe | string | `recordedfuture alert timerange` -action\_result\.data\.\*\.alerts\.\*\.alert\.alertTitle | string | `recordedfuture alert title` -action\_result\.data\.\*\.alerts\.\*\.alert\.alertUrl | string | `recordedfuture alert url` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.counts\.documents | numeric | `recordedfuture alert content count documents` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.counts\.entities | numeric | `recordedfuture alert content count entities` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.counts\.references | numeric | `recordedfuture alert content count references` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.documents\.\*\.references\.\*\.entities\.\*\.id | string | `recordedfuture alert content entities references id` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.documents\.\*\.references\.\*\.entities\.\*\.name | string | `email` `recordedfuture alert content entities references name` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.documents\.\*\.references\.\*\.entities\.\*\.type | string | `recordedfuture alert content entities references type` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.documents\.\*\.references\.\*\.fragment | string | `recordedfuture alert content entities references fragment` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.documents\.\*\.references\.\*\.language | string | `recordedfuture alert content entities references language` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.documents\.\*\.source\.id | string | `recordedfuture alert content entities source id` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.documents\.\*\.source\.name | string | `recordedfuture alert content entities source name` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.documents\.\*\.source\.type | string | `recordedfuture alert content entities source type` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.documents\.\*\.title | string | `recordedfuture alert content entities type` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.documents\.\*\.url | string | `recordedfuture alert content entities url` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.entities\.\*\.entity | string | `recordedfuture alert content entities entity` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.id | string | `recordedfuture alert content id` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.review\.assignee | string | `recordedfuture alert content review assignee` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.review\.note | string | `recordedfuture alert content review note` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.review\.noteAuthor | string | `recordedfuture alert content review note author` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.review\.noteDate | string | `recordedfuture alert content review note data` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.review\.status | string | `recordedfuture alert content review note status` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.rule\.id | string | `recordedfuture alert content rule id` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.rule\.name | string | `recordedfuture alert content rule name` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.rule\.url | string | `recordedfuture alert content rule url` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.title | string | `recordedfuture alert content rule title` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.triggered | string | `recordedfuture alert content triggered` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.type | string | `recordedfuture alert content type` -action\_result\.data\.\*\.alerts\.\*\.alert\.content\.url | string | `recordedfuture alert content url` -action\_result\.data\.\*\.alerts\.\*\.alert\.entities\.Document | string | `recordedfuture alert content entities document` -action\_result\.data\.\*\.alerts\.\*\.alert\.entities\.EmailAddress | string | `email` `recordedfuture alert content entities email address` -action\_result\.data\.\*\.alerts\.\*\.alert\.triggered | string | `recordedfuture alert triggered` +action\_result\.parameter\.timeframe | string | +action\_result\.data\.\*\.rule\.name | string | action\_result\.data\.\*\.rule\.id | string | `recordedfuture alert rule id` -action\_result\.data\.\*\.rule\.name | string | `recordedfuture alert rule id` -action\_result\.data\.\*\.rule\.url | string | `recordedfuture alert rule url` -action\_result\.summary\.returned\_number\_of\_alerts | numeric | `recordedfuture alert number of alerts` +action\_result\.data\.\*\.rule\.url | string | +action\_result\.data\.\*\.alerts\.\*\.id | string | `recordedfuture alert id` +action\_result\.data\.\*\.alerts\.\*\.review\.assignee | string | +action\_result\.data\.\*\.alerts\.\*\.review\.statusDate | string | +action\_result\.data\.\*\.alerts\.\*\.review\.status | string | +action\_result\.data\.\*\.alerts\.\*\.review\.noteDate | string | +action\_result\.data\.\*\.alerts\.\*\.review\.statusChangeBy | string | +action\_result\.data\.\*\.alerts\.\*\.review\.noteAuthor | string | +action\_result\.data\.\*\.alerts\.\*\.review\.note | string | +action\_result\.data\.\*\.alerts\.\*\.title | string | +action\_result\.data\.\*\.alerts\.\*\.triggered | string | +action\_result\.data\.\*\.alerts\.\*\.type | string | +action\_result\.data\.\*\.alerts\.\*\.url | string | +action\_result\.data\.\*\.alerts\.\*\.entities\.alert\.\* | string | `recordedfuture alert id` +action\_result\.data\.\*\.alerts\.entities\.city\.\*\.entity | string | +action\_result\.data\.\*\.alerts\.entities\.city\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.city\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.city\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.city\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.city\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.country\.\*\.entity | string | +action\_result\.data\.\*\.alerts\.entities\.country\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.country\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.country\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.country\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.country\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.cyberVulnerability\.\*\.entity | string | `cve` +action\_result\.data\.\*\.alerts\.entities\.cyberVulnerability\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.cyberVulnerability\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.cyberVulnerability\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.cyberVulnerability\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.cyberVulnerability\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.email\.\*\.entity | string | `email` +action\_result\.data\.\*\.alerts\.entities\.email\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.email\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.email\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.email\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.email\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.hash\.\*\.entity | string | `file` +action\_result\.data\.\*\.alerts\.entities\.hash\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.hash\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.hash\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.hash\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.hash\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.malwareCategory\.\*\.entity | string | +action\_result\.data\.\*\.alerts\.entities\.malwareCategory\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.malwareCategory\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.malwareCategory\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.malwareCategory\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.malwareCategory\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.malwareCategory\.\*\.entity | string | `domain` +action\_result\.data\.\*\.alerts\.entities\.domain\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.domain\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.domain\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.domain\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.domain\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.ip\.\*\.entity | string | `ip` +action\_result\.data\.\*\.alerts\.entities\.ip\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.ip\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.ip\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.ip\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.ip\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.operatingSystem\.\*\.entity | string | +action\_result\.data\.\*\.alerts\.entities\.operatingSystem\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.operatingSystem\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.operatingSystem\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.operatingSystem\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.operatingSystem\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.product\.\*\.entity | string | +action\_result\.data\.\*\.alerts\.entities\.product\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.product\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.product\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.product\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.product\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.technology\.\*\.entity | string | +action\_result\.data\.\*\.alerts\.entities\.technology\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.technology\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.technology\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.technology\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.technology\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.url\.\*\.entity | string | `url` +action\_result\.data\.\*\.alerts\.entities\.url\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.url\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.url\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.url\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.url\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.entities\.vulnerability\.\*\.entity | string | `cve` +action\_result\.data\.\*\.alerts\.entities\.vulnerability\.\*\.authors | string | +action\_result\.data\.\*\.alerts\.entities\.vulnerability\.\*\.fragment | string | +action\_result\.data\.\*\.alerts\.entities\.vulnerability\.\*\.source | string | +action\_result\.data\.\*\.alerts\.entities\.vulnerability\.\*\.title | string | +action\_result\.data\.\*\.alerts\.entities\.vulnerability\.\*\.sourceUrl | string | +action\_result\.data\.\*\.alerts\.evidence\.\*\.criticality | numeric | `recordedfuture risk criticality` +action\_result\.data\.\*\.alerts\.evidence\.\*\.criticalityLabel | string | `recordedfuture risk criticality label` +action\_result\.data\.\*\.alerts\.evidence\.\*\.evidenceString | string | `recordedfuture evidence string` +action\_result\.data\.\*\.alerts\.evidence\.\*\.mitigationString | string | `recordedfuture mitigation string` +action\_result\.data\.\*\.alerts\.evidence\.\*\.rule | string | `recordedfuture evidence rule` +action\_result\.data\.\*\.alerts\.evidence\.\*\.timestamp | string | `recordedfuture evidence timestamp` +action\_result\.summary\.total\_number\_of\_alerts | string | +action\_result\.summary\.alerts\_returned | string | +action\_result\.summary\.rule\_name | string | action\_result\.summary\.rule\_id | string | `recordedfuture alert rule id` -action\_result\.summary\.rule\_name | string | `recordedfuture rule name` -action\_result\.summary\.total\_number\_of\_alerts | numeric | `recordedfuture alert number of alerts` action\_result\.message | string | `recordedfuture result message` summary\.total\_objects | numeric | `recordedfuture total objects` summary\.total\_objects\_successful | numeric | `recordedfuture total objects successful` -## action: 'alert rule lookup' +## action: 'alert lookup' +Get details on an alert + +Type: **investigate** +Read only: **True** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**alert\_id** | required | Alert ID to use for the lookup | string | `recordedfuture alert id` + +#### Action Output +DATA PATH | TYPE | CONTAINS +--------- | ---- | -------- +action\_result\.status | string | `recordedfuture result status` +action\_result\.parameter\.alert\_id | string | `recordedfuture alert id` +action\_result\.\*\.id | string | `recordedfuture alert id` +action\_result\.\*\.review\.assignee | string | +action\_result\.\*\.review\.statusDate | string | +action\_result\.\*\.review\.status | string | +action\_result\.\*\.review\.noteDate | string | +action\_result\.\*\.review\.statusChangeBy | string | +action\_result\.\*\.review\.noteAuthor | string | +action\_result\.\*\.review\.note | string | +action\_result\.\*\.rule\.name | string | +action\_result\.\*\.rule\.id | string | `recordedfuture alert rule id` +action\_result\.\*\.rule\.url | string | +action\_result\.\*\.title | string | +action\_result\.\*\.triggered | string | +action\_result\.\*\.type | string | +action\_result\.\*\.url | string | +action\_result\.data\.\*\.entities\.alert\.\* | string | `recordedfuture alert id` +action\_result\.data\.\*\.entities\.city\.\*\.entity | string | +action\_result\.data\.\*\.entities\.city\.\*\.authors | string | +action\_result\.data\.\*\.entities\.city\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.city\.\*\.source | string | +action\_result\.data\.\*\.entities\.city\.\*\.title | string | +action\_result\.data\.\*\.entities\.city\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.country\.\*\.entity | string | +action\_result\.data\.\*\.entities\.country\.\*\.authors | string | +action\_result\.data\.\*\.entities\.country\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.country\.\*\.source | string | +action\_result\.data\.\*\.entities\.country\.\*\.title | string | +action\_result\.data\.\*\.entities\.country\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.cyberVulnerability\.\*\.entity | string | `cve` +action\_result\.data\.\*\.entities\.cyberVulnerability\.\*\.authors | string | +action\_result\.data\.\*\.entities\.cyberVulnerability\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.cyberVulnerability\.\*\.source | string | +action\_result\.data\.\*\.entities\.cyberVulnerability\.\*\.title | string | +action\_result\.data\.\*\.entities\.cyberVulnerability\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.email\.\*\.entity | string | `email` +action\_result\.data\.\*\.entities\.email\.\*\.authors | string | +action\_result\.data\.\*\.entities\.email\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.email\.\*\.source | string | +action\_result\.data\.\*\.entities\.email\.\*\.title | string | +action\_result\.data\.\*\.entities\.email\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.hash\.\*\.entity | string | `file` +action\_result\.data\.\*\.entities\.hash\.\*\.authors | string | +action\_result\.data\.\*\.entities\.hash\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.hash\.\*\.source | string | +action\_result\.data\.\*\.entities\.hash\.\*\.title | string | +action\_result\.data\.\*\.entities\.hash\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.malwareCategory\.\*\.entity | string | +action\_result\.data\.\*\.entities\.malwareCategory\.\*\.authors | string | +action\_result\.data\.\*\.entities\.malwareCategory\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.malwareCategory\.\*\.source | string | +action\_result\.data\.\*\.entities\.malwareCategory\.\*\.title | string | +action\_result\.data\.\*\.entities\.malwareCategory\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.domain\.\*\.entity | string | `domain` +action\_result\.data\.\*\.entities\.domain\.\*\.authors | string | +action\_result\.data\.\*\.entities\.domain\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.domain\.\*\.source | string | +action\_result\.data\.\*\.entities\.domain\.\*\.title | string | +action\_result\.data\.\*\.entities\.domain\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.ip\.\*\.entity | string | `ip` +action\_result\.data\.\*\.entities\.ip\.\*\.authors | string | +action\_result\.data\.\*\.entities\.ip\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.ip\.\*\.source | string | +action\_result\.data\.\*\.entities\.ip\.\*\.title | string | +action\_result\.data\.\*\.entities\.ip\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.operatingSystem\.\*\.entity | string | +action\_result\.data\.\*\.entities\.operatingSystem\.\*\.authors | string | +action\_result\.data\.\*\.entities\.operatingSystem\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.operatingSystem\.\*\.source | string | +action\_result\.data\.\*\.entities\.operatingSystem\.\*\.title | string | +action\_result\.data\.\*\.entities\.operatingSystem\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.product\.\*\.entity | string | +action\_result\.data\.\*\.entities\.product\.\*\.authors | string | +action\_result\.data\.\*\.entities\.product\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.product\.\*\.source | string | +action\_result\.data\.\*\.entities\.product\.\*\.title | string | +action\_result\.data\.\*\.entities\.product\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.technology\.\*\.entity | string | +action\_result\.data\.\*\.entities\.technology\.\*\.authors | string | +action\_result\.data\.\*\.entities\.technology\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.technology\.\*\.source | string | +action\_result\.data\.\*\.entities\.technology\.\*\.title | string | +action\_result\.data\.\*\.entities\.technology\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.url\.\*\.entity | string | `url` +action\_result\.data\.\*\.entities\.url\.\*\.authors | string | +action\_result\.data\.\*\.entities\.url\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.url\.\*\.source | string | +action\_result\.data\.\*\.entities\.url\.\*\.title | string | +action\_result\.data\.\*\.entities\.url\.\*\.sourceUrl | string | +action\_result\.data\.\*\.entities\.vulnerability\.\*\.entity | string | `cve` +action\_result\.data\.\*\.entities\.vulnerability\.\*\.authors | string | +action\_result\.data\.\*\.entities\.vulnerability\.\*\.fragment | string | +action\_result\.data\.\*\.entities\.vulnerability\.\*\.source | string | +action\_result\.data\.\*\.entities\.vulnerability\.\*\.title | string | +action\_result\.data\.\*\.entities\.vulnerability\.\*\.sourceUrl | string | +action\_result\.data\.\*\.evidence\.\*\.criticality | numeric | `recordedfuture risk criticality` +action\_result\.data\.\*\.evidence\.\*\.criticalityLabel | string | `recordedfuture risk criticality label` +action\_result\.data\.\*\.evidence\.\*\.evidenceString | string | `recordedfuture evidence string` +action\_result\.data\.\*\.evidence\.\*\.mitigationString | string | `recordedfuture mitigation string` +action\_result\.data\.\*\.evidence\.\*\.rule | string | `recordedfuture evidence rule` +action\_result\.data\.\*\.evidence\.\*\.timestamp | string | `recordedfuture evidence timestamp` +action\_result\.summary\.alert\_title | string | +action\_result\.summary\.triggered | string | +action\_result\.message | string | `recordedfuture result message` +summary\.total\_objects | numeric | `recordedfuture total objects` +summary\.total\_objects\_successful | numeric | `recordedfuture total objects successful` + +## action: 'alert rule search' Search for alert rule IDs by name Type: **investigate** @@ -184,10 +397,10 @@ DATA PATH | TYPE | CONTAINS --------- | ---- | -------- action\_result\.status | string | `recordedfuture result status` action\_result\.parameter\.rule\_search | string | `recordedfuture alert rule search` -action\_result\.data\.\*\.rule\.id | string | `recordedfuture alert rule id` -action\_result\.data\.\*\.rule\.name | string | `recordedfuture alert rule name` -action\_result\.summary\.returned\_number\_of\_rules | numeric | `recordedfuture alerts number of rules` -action\_result\.summary\.rule\_id\_list | string | `recordedfuture alerts rule ids` +action\_result\.data\.\*\.id | string | `recordedfuture alert rule id` +action\_result\.data\.\*\.name | string | `recordedfuture alert rule name` +action\_result\.summary\.rules\_returned | numeric | `recordedfuture alerts number of rules` +action\_result\.summary\.rule\_id\_list | string | `recordedfuture alert rule id` action\_result\.summary\.total\_number\_of\_rules | numeric | `recordedfuture rules count total` action\_result\.message | string | `recordedfuture result message` summary\.total\_objects | numeric | `recordedfuture total objects` @@ -789,4 +1002,23 @@ action\_result\.data\.\*\.name | string | `ip` `ipv6` `domain` `file` `hash action\_result\.message | string | `recordedfuture threat assessment result message` action\_result\.summary\.contexts\_available\_for\_threat\_assessment | string | `recordedfuture threat assessment contexts` summary\.total\_objects | numeric | `recordedfuture threat assessment total objects` -summary\.total\_objects\_successful | numeric | `recordedfuture threat assessment total objects successful` \ No newline at end of file +summary\.total\_objects\_successful | numeric | `recordedfuture threat assessment total objects successful` + +## action: 'on poll' +Ingest alerts from Recorded Future + +Type: **ingest** +Read only: **True** + +This action will fetch alerts for the specified rule IDs and within the specified timeframe\. When limiting the number of events to ingest, it will ingest the most recent events\.

+ +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**start\_time** | optional | Parameter ignored for this app | numeric | +**end\_time** | optional | Parameter ignored for this app | numeric | +**container\_count** | optional | Maximum number of events to query for | numeric | +**artifact\_count** | optional | Parameter ignored in this app | numeric | + +#### Action Output +No Output \ No newline at end of file diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 9c5b60b..a32ea2f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,23 @@ # RELEASE NOTES +## VERSION 4.0 + +This version adds on_poll functionality to the Recorded Future integration app for +Splunk (SOAR) to enable download and processing of Recorded Future alerts. + +There are two new actions: alert lookup and alert update. + +Two actions have changed name to better describe their functionality: +1. from alert rule lookup to alert rule search +2. alert data lookup to alert search + +The Recored Future alert structure has been cleaned up to provide better visibility +of the information included. + +Entities within the alerts have been marked up by type so that the relevant data is +easier to find when writing playbooks. + + ## VERSION 3.1 Recorded Future Links have been added to the intelligence lookups. These are entities diff --git a/alert_lookup_results.html b/alert_lookup_results.html new file mode 100644 index 0000000..9ed0f10 --- /dev/null +++ b/alert_lookup_results.html @@ -0,0 +1,229 @@ +{% extends 'widgets/widget_template.html' %} +{% load custom_template %} + +{% block custom_title_prop %}{% if title_logo %}style="background-size: auto 60%; background-position: 50%; background-repeat: no-repeat; background-image: url('/app_resource/{{ title_logo }}');"{% endif %}{% endblock %} +{% block title1 %}{{ title1 }}{% endblock %} +{% block title2 %}{{ title2 }}{% endblock %} +{% block custom_tools %} +{% endblock %} + +{% block widget_content %} + + + + + + + +
+ + {% for result in results %} + {% if not result.data %} +

No data found

+ {% else %} + {% for alert in result.data %} +
+ + + + + + + + + + + + + + +
+ Alert (Alert ID)
+ {{ alert.title }} + ( + {{ alert.id }})  + +
+ Links to Recorded Future
+ Alert / + Alert Rule +
+ Triggered
+ {{ alert.triggered|slice:"0:10" }} +
+ Status
+ {{ alert.review.status }} +
+ Assignee
+ {{ alert.review.assignee }} +
+ Alerting Rule (Rule ID)
+ {{ alert.rule.name }} + ( + {{ alert.rule.id }})  +
+ Note
+ {{ alert.review.note }} +
+
+ + + {% if result.data.evidence %} +
+ + + {% for rule in result.data.evidence|dictsortreversed:"level" %} + + + + + + + {% endfor %} +
Risk Rules Triggered
Risk Rule
+ {{ rule.rule }} +
Evidence
+ {{ rule.description }} +
+ Timestamp
+ {{ rule.timestamp|slice:"0:10" }} +
+
+ {% endif %} + + {% if alert.entities %} + {% for entity_type, entities in alert.entities.items %} +
+ + + {% for entity in entities %} + + + + {% endfor %} +
{{ entity_type|upper }} Entities
+ Entity: + + {{ entity.entity }} 
+ Source: {{ entity.source }}
+ Authors: {{ entity.authors }}
+ Title: {{ entity.title }}
+ SourceURL: {{ entity.sourceUrl }}
+ Fragment: {{ entity.fragment }}
+
+
+ {% endfor %} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} +
+ +{% endblock %} diff --git a/alert_rule_search_results.html b/alert_rule_search_results.html new file mode 100644 index 0000000..f842048 --- /dev/null +++ b/alert_rule_search_results.html @@ -0,0 +1,159 @@ +{% extends 'widgets/widget_template.html' %} +{% load custom_template %} + +{% block custom_title_prop %}{% if title_logo %}style="background-size: auto 60%; background-position: 50%; background-repeat: no-repeat; background-image: url('/app_resource/{{ title_logo }}');"{% endif %}{% endblock %} +{% block title1 %}{{ title1 }}{% endblock %} +{% block title2 %}{{ title2 }}{% endblock %} +{% block custom_tools %} +{% endblock %} + +{% block widget_content %} + + + + + + + +
+ + {% for result in results %} + + + +
+ + {% if result.data %} + {% for rule in result.data %} + + + + + {% endfor %} + {% else %} + + + + {% endif %} +
+ Rule Id
+ + {{ rule.id }}  +
+ Rule Name
+ {{ rule.name }} +
+ No rules found +
+
+ {% endfor %} +
+ +{% endblock %} diff --git a/alert_search_results.html b/alert_search_results.html new file mode 100644 index 0000000..18dc1af --- /dev/null +++ b/alert_search_results.html @@ -0,0 +1,187 @@ +{% extends 'widgets/widget_template.html' %} +{% load custom_template %} + +{% block custom_title_prop %}{% if title_logo %}style="background-size: auto 60%; background-position: 50%; background-repeat: no-repeat; background-image: url('/app_resource/{{ title_logo }}');"{% endif %}{% endblock %} +{% block title1 %}{{ title1 }}{% endblock %} +{% block title2 %}{{ title2 }}{% endblock %} +{% block custom_tools %} +{% endblock %} + +{% block widget_content %} + + + + + + + +
+ + {% for result in results %} + {% if not result.data %} +

No data found

+ {% else %} + {% for alert in result.data %} +
+ + + + + + {% for triggered in alert.alerts %} + + + + + {% if triggered.entities %} + + + + + {% endif %} + {% endfor %} +
+ Rule (Rule ID)
+ {{ alert.rule.name }} + ( + {{ alert.rule.id }})  +
+ Time Frame
+ {{ result.param.timeframe }} +
+ Alert Title (Alert ID)
+ {{ triggered.title }} + ( + {{ triggered.id }})  +
+ Triggered
+ {{ triggered.triggered|slice:"0:10" }} +
+ {% for entity_type, entities in triggered.entities.items %} +
+ {{ entity_type }}
+
+ {% for entity in entities %} + {{ entity.entity }}
+ {% endfor %} +
+ {% endfor %} +
+ Links to Recorded Future
+ Rule / + Alert +
+
+ {% endfor %} + {% endif %} + {% endfor %} +
+ +{% endblock %} diff --git a/alert_update_results.html b/alert_update_results.html new file mode 100644 index 0000000..398157b --- /dev/null +++ b/alert_update_results.html @@ -0,0 +1,161 @@ +{% extends 'widgets/widget_template.html' %} +{% load custom_template %} + +{% block custom_title_prop %}{% if title_logo %}style="background-size: auto 60%; background-position: 50%; background-repeat: no-repeat; background-image: url('/app_resource/{{ title_logo }}');"{% endif %}{% endblock %} +{% block title1 %}{{ title1 }}{% endblock %} +{% block title2 %}{{ title2 }}{% endblock %} +{% block custom_tools %} +{% endblock %} + +{% block widget_content %} + + + + + + + + +
+ + {% for result in results %} + {% for alert_update in result.data %} + + +
+ + + + + + + + + + +
+ Alert Title (ID)
+ {{ alert_update.title }} + ( + {{ result.param.alert_id }})  + +
+ Status
+ {{ alert_update.status }} +
+ Note
+ {{ alert_update.note.text }} +
+
+ {% endfor %} + {% endfor %} +
+ +{% endblock %} diff --git a/contexts_results.html b/contexts_results.html index 8fae975..935286e 100644 --- a/contexts_results.html +++ b/contexts_results.html @@ -35,6 +35,91 @@ Style elements are defined in a separate file, named below, and will be merged during compilation: recordedfuture_style.css --> +
diff --git a/img/recorded_future_asset_ingest.png b/img/recorded_future_asset_ingest.png new file mode 100644 index 0000000..ae7097a Binary files /dev/null and b/img/recorded_future_asset_ingest.png differ diff --git a/img/recorded_future_asset_settings.png b/img/recorded_future_asset_settings.png new file mode 100644 index 0000000..57cee9f Binary files /dev/null and b/img/recorded_future_asset_settings.png differ diff --git a/intelligence_results.html b/intelligence_results.html index b4996d4..adc922c 100644 --- a/intelligence_results.html +++ b/intelligence_results.html @@ -35,6 +35,91 @@ Style elements are defined in a separate file, named below, and will be merged during compilation: recordedfuture_style.css --> +
@@ -99,8 +184,7 @@ Intelligence Card
{% if result.data.intelCard %} - Open - + Open {% elif result.intelCard %} Open {% endif %} @@ -123,8 +207,7 @@ @@ -274,13 +357,12 @@ {{ entity_type|upper }}
{% for entity in entities|dictsortreversed:"score" %} {% if entity_type == 'other' %} - {{ entity.name }} ({{ entity.type|title }}) + {{ entity.type|title }} : {{ entity.name }}
{% else %} Risk: {{ entity.score }}   |   {{ entity.name }} -  
diff --git a/readme.html b/readme.html index f1b67fd..d16de88 100644 --- a/readme.html +++ b/readme.html @@ -30,41 +30,16 @@ enable the creation of Playbooks to do automated enrichment, correlation, threat hunting, and alert handling.

-

Recorded Future Demo Playbooks

-

Together with the Recorded Future App for Phantom 3.0, a new demo - playbook was created and uploaded to the community site. The new playbook - incorporates the new assessment functionality. -

-

Four demo playbooks were released with the Recorded Future App - for Phantom 2.0 to show how the actions in the app can be used. - The playbooks are designed to operate on a Recorded Future App asset - named "recorded-future" and Phantom SMTP asset named "smtp". If the - assets are named differently, the playbooks will be adjusted. The email - address used for the alert emails is specified in the linked SMTP asset. -

-

Correlation Playbook
- This playbook shows how to obtain IP reputation and, if its risk score is - 90 or more, add the IP address to a bad IP address list maintained by - Phantom plus forward the information to Splunk and in an email. -

-

Enrichment Playbook
- This playbook shows how to obtain intelligence of an IP address and, if - its risk score is 90 or more, to forward this in an email as well as - adding the IP to a bad IP address list maintained by Phantom. -

-

Threat Hunting Playbook
- The purpose of this playbook is to find out the IP reputation and when its - risk score is 90 or above, to find related entities - IP addresses, - domains, files, vulnerabilities, and/or URLs - and to search for them in - Splunk. The results are summarised in an email and the IP address is added - to the bad IP address list maintained by Phantom. -

-

Handling of Leaked Credentials
- The purpose of this - playbook is to demonstrate how Recorded Future Alerts can be used to - monitor various threats such as leaked credentials. The playbook is - designed to be scheduled, polling for new alerts each time it is run. If - an alert is found the information is forwarded via an email. +

Ingest alerts into events

+

With alerting rules set up in your Recorded Future enterprise, triggered alerts + can now be ingested in Splunk SOAR as events.The ingestion configuration is set + per asset under the tabs "Asset Settings" and "Ingest Settings".

+

"Asset Settings" defines a list of rule IDs, what severity to apply + to the new events and set the limits for the number of events created by the ingestion.

+

+

The scheduling of the ingestion is set under "Ingest Settings"

+

diff --git a/recordedfuture.json b/recordedfuture.json index 8080c4b..05d8f24 100644 --- a/recordedfuture.json +++ b/recordedfuture.json @@ -2,50 +2,86 @@ "appid": "6efe0e1b-76ac-4ffd-8fa0-ac58fd6efd77", "name": "Recorded Future", "description": "This app implements investigative actions to perform lookups for quick reputation information, contextual threat intelligence and external threat alerts", + "publisher": "Recorded Future, Inc", "type": "reputation", + "main_module": "recordedfuture_connector.py", + "app_version": "4.0.0", + "utctime_updated": "2022-05-30T07:33:58.826014Z", + "package_name": "phantom_recordedfuture", + "product_name": "Recorded Future App for Phantom", "product_vendor": "Recorded Future, Inc", + "product_version_regex": ".*", + "min_phantom_version": "5.3.0", + "python_version": "3", + "fips_compliant": false, + "latest_tested_versions": [ + "Cloud API v2 on 3/13/2020", + "3.1.0" + ], "logo": "logo_recordedfuture.svg", "logo_dark": "logo_recordedfuture_dark.svg", - "product_name": "Recorded Future App for Phantom", - "product_version_regex": ".*", - "publisher": "Recorded Future, Inc", "license": "Copyright (c) Recorded Future, Inc, 2019-2022", - "app_version": "3.1.0", - "utctime_updated": "2019-04-17T07:33:58.826014Z", - "package_name": "phantom_recordedfuture", - "main_module": "recordedfuture_connector.py", - "python_version": "3", "contributors": [ { "name": "Recorded Future - Premier Integrations", "email": "phantom@recordedfuture.com" } ], - "latest_tested_versions": [ - "Cloud API v2 on 3/13/2020", - "3.1.0" - ], - "min_phantom_version": "5.1.0", - "app_wizard_version": "1.0.0", "configuration": { "recordedfuture_base_url": { - "description": "Recorded Future API Basename", + "description": "Recorded Future API basename", "data_type": "string", "required": true, "default": "https://api.recordedfuture.com/gw/phantom", "order": 0 }, "recordedfuture_api_token": { - "description": "Recorded Future API Token", + "description": "Recorded Future API token", "data_type": "password", "required": true, - "order": 1 + "order": 2 }, "recordedfuture_verify_ssl": { - "description": "Verify SSL Certificates", + "description": "Verify SSL certificates", "data_type": "boolean", "default": true, - "order": 2 + "order": 4 + }, + "ph1": { + "data_type": "ph", + "order": 6 + }, + "ph2": { + "data_type": "ph", + "order": 8 + }, + "on_poll_alert_ruleids": { + "data_type": "string", + "order": 1, + "description": "Comma-separated list of alert rule IDs" + }, + "on_poll_alert_severity": { + "data_type": "string", + "order": 3, + "description": "Severity to apply to the alert event", + "default": "Medium", + "value_list": [ + "High", + "Medium", + "Low" + ] + }, + "max_count": { + "data_type": "numeric", + "order": 5, + "description": "Max events to ingest for scheduled polling", + "default": 100 + }, + "first_max_count": { + "data_type": "numeric", + "order": 7, + "description": "Max events to ingest for scheduled polling first time", + "default": 100 } }, "actions": [ @@ -60,9 +96,146 @@ "versions": "EQ(*)" }, { - "action": "alert data lookup", - "identifier": "alert_data_lookup", - "description": "Get details on alerts configured and generated by Recorded Future by alert rule ID and/or time range", + "action": "alert update", + "identifier": "alert_update", + "description": "Update status and/or notes for the alert specified with alert_id", + "type": "investigate", + "read_only": true, + "parameters": { + "alert_id": { + "description": "Alert ID specifying which alert to update", + "data_type": "string", + "required": true, + "primary": true, + "contains": [ + "recordedfuture alert id" + ], + "allow_list": true, + "order": 0 + }, + "alert_status": { + "description": "New alert status", + "data_type": "string", + "required": true, + "value_list": [ + "New", + "Pending", + "Resolved", + "Dismissed" + ], + "allow_list": true, + "order": 1 + }, + "alert_note": { + "description": "Text to be added to the alert", + "data_type": "string", + "required": true, + "allow_list": true, + "order": 2 + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "example_values": [ + "success", + "failed" + ] + }, + { + "data_path": "action_result.parameter.alert_id", + "data_type": "string", + "contains": [ + "recordedfuture alert id" + ] + }, + { + "data_path": "action_result.parameter.alert_status", + "data_type": "string" + }, + { + "data_path": "action_result.parameter.alert_note", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.id", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.note.date", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.note.text", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.note.author", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.status", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.statusDate", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.statusChangeBy", + "data_type": "string" + }, + { + "data_path": "action_result.summary.update", + "data_type": "string" + }, + { + "data_path": "action_result.summary.reason", + "data_type": "string" + }, + { + "data_path": "action_result.message", + "data_type": "string" + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "contains": [ + "recordedfuture total objects" + ], + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "contains": [ + "recordedfuture total objects successful" + ], + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "custom", + "width": 15, + "height": 8, + "view": "recordedfuture_view.alert_update_results", + "title": "Recorded Future Alert Update" + }, + "versions": "EQ(*)" + }, + { + "action": "alert search", + "identifier": "alert_search", + "description": "Get details on alerts configured and generated by Recorded Future by alert rule ID and time range", "type": "investigate", "read_only": true, "parameters": { @@ -82,11 +255,557 @@ "data_type": "string", "required": true, "default": "-24h to now", - "order": 1, + "order": 1 + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "example_values": [ + "success", + "failed" + ] + }, + { + "data_path": "action_result.parameter.rule_id", + "data_type": "string", + "contains": [ + "recordedfuture alert rule id" + ] + }, + { + "data_path": "action_result.parameter.timeframe", + "data_type": "string", + "example_values": [ + "anytime", + "-24h to now" + ] + }, + { + "data_path": "action_result.data.*.rule.name", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.rule.id", + "data_type": "string", "contains": [ - "recordedfuture alert timerange" + "recordedfuture alert rule id" + ] + }, + { + "data_path": "action_result.data.*.rule.url", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.id", + "data_type": "string", + "contains": [ + "recordedfuture alert id" + ] + }, + { + "data_path": "action_result.data.*.alerts.*.review.assignee", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.review.statusDate", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.review.status", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.review.noteDate", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.review.statusChangeBy", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.review.noteAuthor", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.review.note", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.triggered", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.type", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.url", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.*.entities.alert.*", + "data_type": "string", + "contains": [ + "recordedfuture alert id" + ] + }, + { + "data_path": "action_result.data.*.alerts.entities.city.*.entity", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.city.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.city.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.city.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.city.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.city.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.country.*.entity", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.country.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.country.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.country.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.country.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.country.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.cyberVulnerability.*.entity", + "data_type": "string", + "contains": [ + "cve" + ] + }, + { + "data_path": "action_result.data.*.alerts.entities.cyberVulnerability.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.cyberVulnerability.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.cyberVulnerability.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.cyberVulnerability.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.cyberVulnerability.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.email.*.entity", + "data_type": "string", + "contains": [ + "email" + ] + }, + { + "data_path": "action_result.data.*.alerts.entities.email.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.email.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.email.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.email.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.email.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.hash.*.entity", + "data_type": "string", + "contains": [ + "file" + ] + }, + { + "data_path": "action_result.data.*.alerts.entities.hash.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.hash.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.hash.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.hash.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.hash.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.malwareCategory.*.entity", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.malwareCategory.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.malwareCategory.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.malwareCategory.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.malwareCategory.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.malwareCategory.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.malwareCategory.*.entity", + "data_type": "string", + "contains": [ + "domain" + ] + }, + { + "data_path": "action_result.data.*.alerts.entities.domain.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.domain.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.domain.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.domain.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.domain.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.ip.*.entity", + "data_type": "string", + "contains": [ + "ip" + ] + }, + { + "data_path": "action_result.data.*.alerts.entities.ip.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.ip.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.ip.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.ip.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.ip.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.operatingSystem.*.entity", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.operatingSystem.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.operatingSystem.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.operatingSystem.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.operatingSystem.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.operatingSystem.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.product.*.entity", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.product.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.product.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.product.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.product.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.product.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.technology.*.entity", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.technology.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.technology.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.technology.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.technology.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.technology.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.url.*.entity", + "data_type": "string", + "contains": [ + "url" + ] + }, + { + "data_path": "action_result.data.*.alerts.entities.url.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.url.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.url.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.url.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.url.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.vulnerability.*.entity", + "data_type": "string", + "contains": [ + "cve" + ] + }, + { + "data_path": "action_result.data.*.alerts.entities.vulnerability.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.vulnerability.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.vulnerability.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.vulnerability.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.entities.vulnerability.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.alerts.evidence.*.criticality", + "data_type": "numeric", + "contains": [ + "recordedfuture risk criticality" + ] + }, + { + "data_path": "action_result.data.*.alerts.evidence.*.criticalityLabel", + "data_type": "string", + "example_values": [ + "Unusual" ], - "primary": true + "contains": [ + "recordedfuture risk criticality label" + ] + }, + { + "data_path": "action_result.data.*.alerts.evidence.*.evidenceString", + "data_type": "string", + "contains": [ + "recordedfuture evidence string" + ] + }, + { + "data_path": "action_result.data.*.alerts.evidence.*.mitigationString", + "data_type": "string", + "contains": [ + "recordedfuture mitigation string" + ] + }, + { + "data_path": "action_result.data.*.alerts.evidence.*.rule", + "data_type": "string", + "contains": [ + "recordedfuture evidence rule" + ] + }, + { + "data_path": "action_result.data.*.alerts.evidence.*.timestamp", + "data_type": "string", + "contains": [ + "recordedfuture evidence timestamp" + ] + }, + { + "data_path": "action_result.summary.total_number_of_alerts", + "data_type": "string" + }, + { + "data_path": "action_result.summary.alerts_returned", + "data_type": "string" + }, + { + "data_path": "action_result.summary.rule_name", + "data_type": "string" + }, + { + "data_path": "action_result.summary.rule_id", + "data_type": "string", + "contains": [ + "recordedfuture alert rule id" + ] + }, + { + "data_path": "action_result.message", + "data_type": "string", + "contains": [ + "recordedfuture result message" + ] + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "contains": [ + "recordedfuture total objects" + ], + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "contains": [ + "recordedfuture total objects successful" + ], + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "custom", + "width": 15, + "height": 8, + "view": "recordedfuture_view.alert_search_results", + "title": "Recorded Future Alert Data" + }, + "versions": "EQ(*)" + }, + { + "action": "alert lookup", + "identifier": "alert_lookup", + "description": "Get details on an alert", + "type": "investigate", + "read_only": true, + "parameters": { + "alert_id": { + "description": "Alert ID to use for the lookup", + "data_type": "string", + "required": true, + "primary": true, + "contains": [ + "recordedfuture alert id" + ], + "allow_list": true, + "order": 0 } }, "output": [ @@ -102,297 +821,470 @@ ] }, { - "data_path": "action_result.parameter.rule_id", + "data_path": "action_result.parameter.alert_id", + "data_type": "string", + "contains": [ + "recordedfuture alert id" + ] + }, + { + "data_path": "action_result.*.id", + "data_type": "string", + "contains": [ + "recordedfuture alert id" + ] + }, + { + "data_path": "action_result.*.review.assignee", + "data_type": "string" + }, + { + "data_path": "action_result.*.review.statusDate", + "data_type": "string" + }, + { + "data_path": "action_result.*.review.status", + "data_type": "string" + }, + { + "data_path": "action_result.*.review.noteDate", + "data_type": "string" + }, + { + "data_path": "action_result.*.review.statusChangeBy", + "data_type": "string" + }, + { + "data_path": "action_result.*.review.noteAuthor", + "data_type": "string" + }, + { + "data_path": "action_result.*.review.note", + "data_type": "string" + }, + { + "data_path": "action_result.*.rule.name", + "data_type": "string" + }, + { + "data_path": "action_result.*.rule.id", "data_type": "string", "contains": [ "recordedfuture alert rule id" ] }, { - "data_path": "action_result.parameter.timeframe", - "data_type": "string", - "example_values": [ - "anytime", - "-24h to now" - ], - "contains": [ - "recordedfuture alert timerange" - ] + "data_path": "action_result.*.rule.url", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.alertTitle", - "data_type": "string", - "contains": [ - "recordedfuture alert title" - ] + "data_path": "action_result.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.*.triggered", + "data_type": "string" + }, + { + "data_path": "action_result.*.type", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.alertUrl", + "data_path": "action_result.*.url", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.alert.*", "data_type": "string", "contains": [ - "recordedfuture alert url" + "recordedfuture alert id" ] }, { - "data_path": "action_result.data.*.alerts.*.alert.content.counts.documents", - "data_type": "numeric", - "contains": [ - "recordedfuture alert content count documents" - ] + "data_path": "action_result.data.*.entities.city.*.entity", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.counts.entities", - "data_type": "numeric", - "contains": [ - "recordedfuture alert content count entities" - ] + "data_path": "action_result.data.*.entities.city.*.authors", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.counts.references", - "data_type": "numeric", - "contains": [ - "recordedfuture alert content count references" - ] + "data_path": "action_result.data.*.entities.city.*.fragment", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.documents.*.references.*.entities.*.id", - "data_type": "string", - "contains": [ - "recordedfuture alert content entities references id" - ] + "data_path": "action_result.data.*.entities.city.*.source", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.documents.*.references.*.entities.*.name", - "data_type": "string", - "contains": [ - "email", - "recordedfuture alert content entities references name" - ] + "data_path": "action_result.data.*.entities.city.*.title", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.documents.*.references.*.entities.*.type", - "data_type": "string", - "contains": [ - "recordedfuture alert content entities references type" - ] + "data_path": "action_result.data.*.entities.city.*.sourceUrl", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.documents.*.references.*.fragment", - "data_type": "string", - "contains": [ - "recordedfuture alert content entities references fragment" - ] + "data_path": "action_result.data.*.entities.country.*.entity", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.documents.*.references.*.language", - "data_type": "string", - "contains": [ - "recordedfuture alert content entities references language" - ] + "data_path": "action_result.data.*.entities.country.*.authors", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.documents.*.source.id", - "data_type": "string", - "contains": [ - "recordedfuture alert content entities source id" - ] + "data_path": "action_result.data.*.entities.country.*.fragment", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.documents.*.source.name", - "data_type": "string", - "contains": [ - "recordedfuture alert content entities source name" - ] + "data_path": "action_result.data.*.entities.country.*.source", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.documents.*.source.type", - "data_type": "string", - "contains": [ - "recordedfuture alert content entities source type" - ] + "data_path": "action_result.data.*.entities.country.*.title", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.documents.*.title", - "data_type": "string", - "contains": [ - "recordedfuture alert content entities type" - ] + "data_path": "action_result.data.*.entities.country.*.sourceUrl", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.documents.*.url", + "data_path": "action_result.data.*.entities.cyberVulnerability.*.entity", "data_type": "string", "contains": [ - "recordedfuture alert content entities url" + "cve" ] }, { - "data_path": "action_result.data.*.alerts.*.alert.content.entities.*.entity", - "data_type": "string", - "contains": [ - "recordedfuture alert content entities entity" - ] + "data_path": "action_result.data.*.entities.cyberVulnerability.*.authors", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.id", - "data_type": "string", - "contains": [ - "recordedfuture alert content id" - ] + "data_path": "action_result.data.*.entities.cyberVulnerability.*.fragment", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.review.assignee", - "data_type": "string", - "contains": [ - "recordedfuture alert content review assignee" - ] + "data_path": "action_result.data.*.entities.cyberVulnerability.*.source", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.review.note", - "data_type": "string", - "contains": [ - "recordedfuture alert content review note" - ] + "data_path": "action_result.data.*.entities.cyberVulnerability.*.title", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.review.noteAuthor", - "data_type": "string", - "contains": [ - "recordedfuture alert content review note author" - ] + "data_path": "action_result.data.*.entities.cyberVulnerability.*.sourceUrl", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.review.noteDate", + "data_path": "action_result.data.*.entities.email.*.entity", "data_type": "string", "contains": [ - "recordedfuture alert content review note data" + "email" ] }, { - "data_path": "action_result.data.*.alerts.*.alert.content.review.status", - "data_type": "string", - "contains": [ - "recordedfuture alert content review note status" - ] + "data_path": "action_result.data.*.entities.email.*.authors", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.rule.id", - "data_type": "string", - "contains": [ - "recordedfuture alert content rule id" - ] + "data_path": "action_result.data.*.entities.email.*.fragment", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.rule.name", - "data_type": "string", - "contains": [ - "recordedfuture alert content rule name" - ] + "data_path": "action_result.data.*.entities.email.*.source", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.rule.url", - "data_type": "string", - "contains": [ - "recordedfuture alert content rule url" - ] + "data_path": "action_result.data.*.entities.email.*.title", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.title", - "data_type": "string", - "contains": [ - "recordedfuture alert content rule title" - ] + "data_path": "action_result.data.*.entities.email.*.sourceUrl", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.triggered", + "data_path": "action_result.data.*.entities.hash.*.entity", "data_type": "string", "contains": [ - "recordedfuture alert content triggered" + "file" ] }, { - "data_path": "action_result.data.*.alerts.*.alert.content.type", - "data_type": "string", - "contains": [ - "recordedfuture alert content type" - ] + "data_path": "action_result.data.*.entities.hash.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.hash.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.hash.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.hash.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.hash.*.sourceUrl", + "data_type": "string" }, { - "data_path": "action_result.data.*.alerts.*.alert.content.url", + "data_path": "action_result.data.*.entities.malwareCategory.*.entity", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.malwareCategory.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.malwareCategory.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.malwareCategory.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.malwareCategory.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.malwareCategory.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.domain.*.entity", "data_type": "string", "contains": [ - "recordedfuture alert content url" + "domain" ] }, { - "data_path": "action_result.data.*.alerts.*.alert.entities.Document", + "data_path": "action_result.data.*.entities.domain.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.domain.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.domain.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.domain.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.domain.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.ip.*.entity", "data_type": "string", "contains": [ - "recordedfuture alert content entities document" + "ip" ] }, { - "data_path": "action_result.data.*.alerts.*.alert.entities.EmailAddress", + "data_path": "action_result.data.*.entities.ip.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.ip.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.ip.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.ip.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.ip.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.operatingSystem.*.entity", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.operatingSystem.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.operatingSystem.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.operatingSystem.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.operatingSystem.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.operatingSystem.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.product.*.entity", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.product.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.product.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.product.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.product.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.product.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.technology.*.entity", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.technology.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.technology.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.technology.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.technology.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.technology.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.url.*.entity", "data_type": "string", "contains": [ - "email", - "recordedfuture alert content entities email address" + "url" ] }, { - "data_path": "action_result.data.*.alerts.*.alert.triggered", + "data_path": "action_result.data.*.entities.url.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.url.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.url.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.url.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.url.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.vulnerability.*.entity", "data_type": "string", "contains": [ - "recordedfuture alert triggered" + "cve" ] }, { - "data_path": "action_result.data.*.rule.id", - "data_type": "string", + "data_path": "action_result.data.*.entities.vulnerability.*.authors", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.vulnerability.*.fragment", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.vulnerability.*.source", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.vulnerability.*.title", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.entities.vulnerability.*.sourceUrl", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.evidence.*.criticality", + "data_type": "numeric", "contains": [ - "recordedfuture alert rule id" + "recordedfuture risk criticality" ] }, { - "data_path": "action_result.data.*.rule.name", + "data_path": "action_result.data.*.evidence.*.criticalityLabel", "data_type": "string", + "example_values": [ + "Unusual" + ], "contains": [ - "recordedfuture alert rule id" + "recordedfuture risk criticality label" ] }, { - "data_path": "action_result.data.*.rule.url", + "data_path": "action_result.data.*.evidence.*.evidenceString", "data_type": "string", "contains": [ - "recordedfuture alert rule url" + "recordedfuture evidence string" ] }, { - "data_path": "action_result.summary.returned_number_of_alerts", - "data_type": "numeric", + "data_path": "action_result.data.*.evidence.*.mitigationString", + "data_type": "string", "contains": [ - "recordedfuture alert number of alerts" + "recordedfuture mitigation string" ] }, { - "data_path": "action_result.summary.rule_id", + "data_path": "action_result.data.*.evidence.*.rule", "data_type": "string", "contains": [ - "recordedfuture alert rule id" + "recordedfuture evidence rule" ] }, { - "data_path": "action_result.summary.rule_name", + "data_path": "action_result.data.*.evidence.*.timestamp", "data_type": "string", "contains": [ - "recordedfuture rule name" + "recordedfuture evidence timestamp" ] }, { - "data_path": "action_result.summary.total_number_of_alerts", - "data_type": "numeric", - "contains": [ - "recordedfuture alert number of alerts" - ] + "data_path": "action_result.summary.alert_title", + "data_type": "string" + }, + { + "data_path": "action_result.summary.triggered", + "data_type": "string" }, { "data_path": "action_result.message", @@ -424,14 +1316,16 @@ ], "render": { "type": "custom", - "view": "recordedfuture_view.alert_data_results", - "title": "Recorded Future Alert Data" + "width": 15, + "height": 8, + "view": "recordedfuture_view.alert_lookup_results", + "title": "Recorded Future Alert Lookup" }, "versions": "EQ(*)" }, { - "action": "alert rule lookup", - "identifier": "rule_id_lookup", + "action": "alert rule search", + "identifier": "alert_rule_search", "description": "Search for alert rule IDs by name", "type": "investigate", "read_only": true, @@ -466,7 +1360,7 @@ ] }, { - "data_path": "action_result.data.*.rule.id", + "data_path": "action_result.data.*.id", "data_type": "string", "column_name": "Rule ID", "column_order": 0, @@ -475,7 +1369,7 @@ ] }, { - "data_path": "action_result.data.*.rule.name", + "data_path": "action_result.data.*.name", "data_type": "string", "column_name": "Rule Name", "column_order": 1, @@ -484,7 +1378,7 @@ ] }, { - "data_path": "action_result.summary.returned_number_of_rules", + "data_path": "action_result.summary.rules_returned", "data_type": "numeric", "contains": [ "recordedfuture alerts number of rules" @@ -494,7 +1388,7 @@ "data_path": "action_result.summary.rule_id_list", "data_type": "string", "contains": [ - "recordedfuture alerts rule ids" + "recordedfuture alert rule id" ] }, { @@ -534,7 +1428,9 @@ ], "render": { "type": "custom", - "view": "recordedfuture_view.alert_rules_results", + "width": 15, + "height": 8, + "view": "recordedfuture_view.alert_rule_search_results", "title": "Recorded Future Alert Rules" }, "versions": "EQ(*)" @@ -910,6 +1806,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.intelligence_results", "title": "Threat Intelligence for URL" }, @@ -1087,6 +1985,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.reputation_results", "title": "Threat Reputation of a URL" }, @@ -1577,6 +2477,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.intelligence_results", "title": "Threat Intelligence for Vulnerability" }, @@ -1777,6 +2679,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.reputation_results", "title": "Threat Reputation of a Vulnerability" }, @@ -2211,6 +3115,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.intelligence_results", "title": "Threat Intelligence for File Hash" }, @@ -2413,6 +3319,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.reputation_results", "title": "Threat Reputation of a File Hash" }, @@ -2853,6 +3761,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.intelligence_results", "title": "Threat Intelligence for Domain" }, @@ -3043,6 +3953,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.reputation_results", "title": "Threat Reputation of a Domain" }, @@ -3511,6 +4423,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.intelligence_results", "title": "Threat Intelligence for IP Address" }, @@ -3704,6 +4618,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.reputation_results", "title": "Threat Reputation of an IP Address" }, @@ -3720,11 +4636,11 @@ "description": "Context to use", "data_type": "string", "required": true, - "primary": true, "order": 0, "contains": [ "recordedfuture threat assessment context" - ] + ], + "primary": true }, "ip": { "description": "IP to query", @@ -3881,11 +4797,7 @@ "data_path": "action_result.data.*.entities.*.evidence.*.level", "data_type": "numeric", "example_values": [ - 1, - 2, - 3, - 4, - 5 + 1 ], "contains": [ "recordedfuture risk rule level" @@ -4042,6 +4954,8 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.threat_assessment_results", "title": "Threat Summary for a collection of entities" }, @@ -4126,6 +5040,48 @@ ], "render": { "type": "custom", + "width": 15, + "height": 8, + "view": "recordedfuture_view.contexts_results", + "title": "List of available contexts" + }, + "versions": "EQ(*)" + }, + { + "action": "on poll", + "description": "Ingest alerts from Recorded Future", + "verbose": "This action will fetch alerts for the specified rule IDs and within the specified timeframe. When limiting the number of events to ingest, it will ingest the most recent events.

", + "type": "ingest", + "identifier": "on_poll", + "read_only": true, + "parameters": { + "start_time": { + "data_type": "numeric", + "description": "Parameter ignored for this app", + "order": 0 + }, + "end_time": { + "data_type": "numeric", + "description": "Parameter ignored for this app", + "order": 1 + }, + "container_count": { + "description": "Maximum number of events to query for", + "data_type": "numeric", + "default": 100, + "order": 2 + }, + "artifact_count": { + "description": "Parameter ignored in this app", + "data_type": "numeric", + "order": 3 + } + }, + "output": [], + "render": { + "type": "custom", + "width": 15, + "height": 8, "view": "recordedfuture_view.contexts_results", "title": "List of available contexts" }, @@ -4140,7 +5096,7 @@ }, { "module": "certifi", - "input_file": "wheels/shared/certifi-2021.10.8-py2.py3-none-any.whl" + "input_file": "wheels/py3/certifi-2022.6.15-py3-none-any.whl" }, { "module": "chardet", @@ -4156,11 +5112,11 @@ }, { "module": "soupsieve", - "input_file": "wheels/py3/soupsieve-2.3.1-py3-none-any.whl" + "input_file": "wheels/py3/soupsieve-2.3.2.post1-py3-none-any.whl" }, { "module": "urllib3", - "input_file": "wheels/shared/urllib3-1.26.9-py2.py3-none-any.whl" + "input_file": "wheels/shared/urllib3-1.26.12-py2.py3-none-any.whl" } ] } diff --git a/recordedfuture_connector.py b/recordedfuture_connector.py index e2afe03..668eec4 100644 --- a/recordedfuture_connector.py +++ b/recordedfuture_connector.py @@ -31,6 +31,8 @@ import os import platform import sys +import time +from math import ceil # Phantom App imports # noinspection PyUnresolvedReferences @@ -44,7 +46,7 @@ from phantom.base_connector import BaseConnector # Usage of the consts file is recommended -from recordedfuture_consts import INTELLIGENCE_MAP, timeout, version +from recordedfuture_consts import * class RetVal(tuple): @@ -70,7 +72,7 @@ def __init__(self): @staticmethod def _process_empty_response(response, action_result): """Process an empty result.""" - if response.status_code == 200: + if response.status_code == 200 or response.status_code == 204: return RetVal(phantom.APP_SUCCESS, {}) return RetVal( @@ -397,8 +399,6 @@ def _make_rest_call( None, ) else: - # XXXX _process_response is not able to handle the abort response message, can't do get on the response - # message = resp.get('message', '') return RetVal( action_result.set_status( phantom.APP_ERROR, @@ -679,21 +679,106 @@ def _handle_list_contexts(self, param): # dictionary return action_result.set_status(phantom.APP_SUCCESS) - def _parse_rule_data(self, res): - """Reformat entities returned by the alert verb.""" - from collections import defaultdict - - entities = defaultdict(list) - for ent in res.get('entities', []): - if ent['entity'] is not None: - entities[ent['entity']['type']].append(ent['entity']['name']) - for doc in ent.get('documents'): - for ref in doc.get('references'): - for entity in ref.get('entities'): - entities[entity['type']].append(entity['name']) - return entities - - def _handle_alert_data_lookup(self, param): + def _on_poll(self, param): + """Entry point for obtaining alerts and rules.""" + # new containers and artifacts will be stored in containers[] + + self.save_progress( + "In action handler for: {0}".format(self.get_action_identifier()) + ) + action_result = self.add_action_result(ActionResult(dict(param))) + config = self.get_config() + + containers = self._on_poll_alerts(param, config, action_result) + + for container in containers: + + ret_val, msg, cid = self.save_container(container) + + if phantom.is_fail(ret_val): + self.save_progress("Error saving containers: {}".format(msg)) + self.debug_print("Error saving containers: {} -- CID: {}".format(msg, cid)) + return action_result.set_status(phantom.APP_ERROR, "Error while trying to add the containers") + + # Always update the alerts with new status to ensure that they are not left in limbo + # description has string in the format -> "Container created from alert {alert_id}" + # we get alert_id from it. + params = [{ + 'id': container['description'].split(' ')[4], + 'status': 'Pending' + }] + my_ret_val, response = self._make_rest_call( + '/alert/update', action_result, json=params, method='post' + ) + + # Something went wrong + if phantom.is_fail(my_ret_val): + return action_result.get_status() + + self._state['start_time'] = time.time() + + return action_result.set_status(phantom.APP_SUCCESS) + + def _on_poll_alerts(self, param, config, action_result): + """Polling for triggered alerts given a list of rule IDs.""" + + # obtain the list of rule ids to use to obtain alerts + list_of_rules = config.get('on_poll_alert_ruleids') + if not list_of_rules: + self.save_progress("Need to specify Alert Rule IDs use for polling") + return action_result.set_status(phantom.APP_ERROR) + rule_list = [x.strip() for x in list_of_rules.split(',')] + + if self.is_poll_now(): + param['max_count'] = param.get('container_count', MAX_CONTAINERS) + timeframe = "" + else: + # Different number of max containers if first run + if self._state.get('first_run', True): + # set the config to _not_ first run hereafter + self._state['first_run'] = False + param['max_count'] = config.get('first_max_count', MAX_CONTAINERS) + self.save_progress("First time Ingestion detected.") + timeframe = "" + else: + param['max_count'] = config.get('max_count', MAX_CONTAINERS) + # calculate time since last fetch + interval = ceil((time.time() - self._state.get('start_time')) / 3600) + 3 + timeframe = f'-{interval}h to now' + + # Asset Settings in Asset Configuration allows a negative number + if int(param['max_count']) <= 0: + param['max_count'] = MAX_CONTAINERS + + # Prepare the REST call to get all alerts within the timeframe and with status New + params = { + 'triggered': timeframe, + 'rules': rule_list, + 'severity': config.get('on_poll_alert_severity'), + 'limit': param.get('max_count', 100) + } + + # Make the rest call + my_ret_val, containers = self._make_rest_call( + '/alert/on_poll', + action_result, + json=params, + method='post', + ) + # Something went wrong + if phantom.is_fail(my_ret_val): + return action_result.get_status() + + # sort the containers to get the oldest first + containers.sort(key=lambda k: k['triggered'], reverse=False) + + # if necessary truncate the list of containers TODO need to fix other issue first + # if len(containers) > param['max_count'] + 1: + # containers = containers[0:param['max_count'] + 1] + + return containers + + def _handle_alert_search(self, param): """Implement lookup of alerts issued for an alert rule.""" self.save_progress( "In action handler for: {0}".format(self.get_action_identifier()) @@ -718,7 +803,7 @@ def _handle_alert_data_lookup(self, param): ) self.debug_print( - '_handle_alert_data_lookup', + '_handle_alert_search', { 'path_info': f'/alert/rule/{rule_id}', 'action_result': action_result, @@ -735,7 +820,7 @@ def _handle_alert_data_lookup(self, param): # Setup summary summary = action_result.get_summary() summary['total_number_of_alerts'] = response['counts'].get('total', 0) - summary['returned_number_of_alerts'] = response['counts'].get('returned', 0) + summary['alerts_returned'] = response['counts'].get('returned', 0) # No results can be non existing rule id or just that, no results... if response['counts']['total'] == 0: @@ -756,10 +841,10 @@ def _handle_alert_data_lookup(self, param): alerts = [] for alert in response['data']['results']: self.save_progress('In alert loop: %s' % alert) - url2 = '/alert/%s' % alert['id'] + url2 = '/alert/lookup/%s' % alert['id'] ret_val2, response2 = self._make_rest_call(url2, action_result) self.debug_print( - '_handle_alert_data_lookup', + '_handle_alert_search', { 'path_info': url2, 'action_result': action_result, @@ -768,22 +853,15 @@ def _handle_alert_data_lookup(self, param): 'response': response2, }, ) - - entities = self._parse_rule_data(response2['data']) - self.save_progress('ENTITIES: %s' % entities) + # Something went wrong + if phantom.is_fail(ret_val2): + return action_result.get_status() # Add the response into the data section - current_alert = { - 'alertTitle': response2['data']['title'], - 'triggered': response2['data']['triggered'], - 'alertUrl': response2['data']['url'], - 'content': response2['data'], - 'entities': entities, - } - alerts.append({'alert': current_alert}) + alerts.append(response2) self.save_progress( 'Alert: "%s" triggered "%s"' - % (response2['data']['title'], response2['data']['triggered']) + % (response2['title'], response2['triggered']) ) action_result.add_data( @@ -793,7 +871,103 @@ def _handle_alert_data_lookup(self, param): # Return success, no need to set the message, only the status return action_result.set_status(phantom.APP_SUCCESS) - def _handle_rule_id_lookup(self, param): + def _handle_alert_lookup(self, param): + """Implement lookup of alerts issued for an alert rule.""" + self.save_progress( + "In action handler for: {0}".format(self.get_action_identifier()) + ) + + # Add an action result object to self (BaseConnector) to represent + # the action for this param + action_result = self.add_action_result(ActionResult(dict(param))) + + # Required values can be accessed directly + alert_id = UnicodeDammit(param['alert_id']).unicode_markup + + # Make rest call + my_ret_val, response = self._make_rest_call( + f'/alert/lookup/{alert_id}', action_result + ) + + self.debug_print( + '_handle_alert_lookup', + { + 'path_info': f'/alert/lookup/{alert_id}', + 'action_result': action_result, + 'my_ret_val': my_ret_val, + 'response': response, + }, + ) + + # Something went wrong + if phantom.is_fail(my_ret_val): + return action_result.get_status() + + # Setup summary + action_result.add_data(response) + summary = action_result.get_summary() + + # Add info about the rule to summary and action_result['data'] TODO format date + summary['alert_title'] = response.get('title', '') + summary['triggered'] = response.get('triggered', '') + action_result.set_summary(summary) + + # Return success, no need to set the message, only the status + return action_result.set_status(phantom.APP_SUCCESS) + + def _handle_alert_update(self, param): + """Implement lookup of alerts issued for an alert rule.""" + + self.save_progress( + "In action handler for: {0}".format(self.get_action_identifier()) + ) + + # Add an action result object to self (BaseConnector) to represent + # the action for this param + action_result = self.add_action_result(ActionResult(dict(param))) + + params = [{ + 'id': UnicodeDammit(param.get('alert_id', '')).unicode_markup, + 'status': UnicodeDammit(param.get('alert_status', '')).unicode_markup, + 'note': UnicodeDammit(param.get('alert_note', '')).unicode_markup + }] + + # Make rest call + my_ret_val, response = self._make_rest_call( + '/alert/update', action_result, json=params, method='post' + ) + + self.debug_print( + '_handle_alert_update', + { + 'path_info': 'alert/update', + 'action_result': action_result, + 'params': params, + 'my_ret_val': my_ret_val, + 'response': response, + }, + ) + + # Something went wrong + if phantom.is_fail(my_ret_val): + return action_result.get_status() + + # Setup response including summary + res = response.get('success', '') + action_result.add_data(res[0]) + summary = action_result.get_summary() + + if response.get('success', ''): + summary['update'] = 'Successful' + else: + summary['update'] = 'Not successful' + summary['reason'] = response['error'].get('reason', '') + action_result.set_summary(summary) + + # Return success, no need to set the message, only the status + return action_result.set_status(phantom.APP_SUCCESS) + + def _handle_alert_rule_search(self, param): """Make a freetext search for alert rules.""" self.save_progress( "In action handler for: {0}".format(self.get_action_identifier()) @@ -820,7 +994,7 @@ def _handle_rule_id_lookup(self, param): ) self.debug_print( - '_handle_rule_id_lookup', + '_handle_alert_rule_search', { 'path_info': 'config/alert/rules', 'action_result': action_result, @@ -842,7 +1016,7 @@ def _handle_rule_id_lookup(self, param): # Summary summary = action_result.get_summary() - summary['returned_number_of_rules'] = response['counts']['returned'] + summary['rules_returned'] = response['counts']['returned'] summary['total_number_of_rules'] = response['counts']['total'] summary['rule_id_list'] = ','.join(rule_ids) action_result.set_summary(summary) @@ -895,12 +1069,21 @@ def handle_action(self, param): # todo: need to check the in-parameters my_ret_val = self._handle_list_contexts(param) - elif action_id == 'rule_id_lookup': + elif action_id == 'alert_rule_search': self.debug_print('DEBUG: started fetching rules') - my_ret_val = self._handle_rule_id_lookup(param) + my_ret_val = self._handle_alert_rule_search(param) + + elif action_id == 'alert_search': + my_ret_val = self._handle_alert_search(param) + + elif action_id == 'alert_lookup': + my_ret_val = self._handle_alert_lookup(param) + + elif action_id == 'alert_update': + my_ret_val = self._handle_alert_update(param) - elif action_id == 'alert_data_lookup': - my_ret_val = self._handle_alert_data_lookup(param) + elif action_id == 'on_poll': + my_ret_val = self._on_poll(param) return my_ret_val @@ -915,7 +1098,7 @@ def _is_ip(self, input_ip_address): try: ipaddress.ip_address(ip_address_input) - except: + except ValueError: return False return True @@ -925,6 +1108,10 @@ def initialize(self): # Load the state in initialize, use it to store data # that needs to be accessed across actions self._state = self.load_state() + if not isinstance(self._state, dict): + self.debug_print("Resetting the state file with the default format") + self._state = {"app_version": self.get_app_json().get("app_version")} + return self.set_status(phantom.APP_ERROR, RF_STATE_FILE_CORRUPT_ERR) # get the asset config config = self.get_config() @@ -982,7 +1169,7 @@ def finalize(self): login_url = BaseConnector._get_phantom_base_url() + 'login' try: print('Accessing the Login page') - r = requests.get(login_url, verify=True, timeout=33) + r = requests.get(login_url, verify=True, timeout=timeout) csrftoken = r.cookies['csrftoken'] data = dict() @@ -996,7 +1183,7 @@ def finalize(self): print('Logging into Platform to get the session id') r2 = requests.post( - login_url, verify=True, data=data, headers=headers, timeout=33 + login_url, verify=True, data=data, headers=headers, timeout=timeout ) session_id = r2.cookies['sessionid'] except Exception as e: diff --git a/recordedfuture_consts.py b/recordedfuture_consts.py index 21f009b..9a28ebf 100644 --- a/recordedfuture_consts.py +++ b/recordedfuture_consts.py @@ -21,11 +21,12 @@ # and limitations under the License. # Define your constants here -version = '3.1.0' -buildid = '264' +version = '4.0.0' +buildid = '305' # timeout for our http requests to bfi_phantom -timeout = 33 +timeout = 63 +MAX_CONTAINERS = 100 # These dicts map which path_info, which fields, what the Recorded Future # category is called and whether to quote the entity or not. @@ -100,3 +101,7 @@ True, ), } +RF_STATE_FILE_CORRUPT_ERR = ( + "Error occurred while loading the state file due to its unexpected format. " + "Resetting the state file with the default format. Please try again." +) diff --git a/recordedfuture_style.css b/recordedfuture_style.css index 12511eb..7ce0afe 100644 --- a/recordedfuture_style.css +++ b/recordedfuture_style.css @@ -15,15 +15,15 @@ .rf-widget { overflow: auto; - width: 120%; + width: 100%; height: 100%; padding-left:10px; padding-right:10px; } .rf-box { - width: 600px; - padding: 5px 10px 5px 10px; + width: 750px; + padding: 5px; margin: 0 5px; font-size: 12px; } diff --git a/recordedfuture_view.py b/recordedfuture_view.py index ff31f92..4bf29de 100644 --- a/recordedfuture_view.py +++ b/recordedfuture_view.py @@ -32,6 +32,7 @@ def format_result(result, all_data=False): retval['data'] = data[0] try: + # assemble the string needed for an URL to Recorded Future portal if ( data and 'risk' in retval['data'] and retval['data']['risk']['score'] is not None ): @@ -49,6 +50,7 @@ def format_result(result, all_data=False): for rule in retval['data']['risk']['evidenceDetails']: rule['timestampShort'] = rule['timestamp'][:10] + # add cvss info only if present (should only be applicable by vulnerabilities) if data and 'cvss' in retval['data'] and 'published' in retval['data']['cvss']: retval['data']['cvss']['publishedShort'] = retval['data']['cvss'][ 'published' @@ -57,6 +59,7 @@ def format_result(result, all_data=False): 'lastModified' ][:10] + # format date and time to be shorter and easier to read retval['data']['timestamps']['firstSeenShort'] = retval['data']['timestamps'][ 'firstSeen' ][:10] @@ -66,6 +69,7 @@ def format_result(result, all_data=False): except Exception: retval['data'] = None + # set summary, status and message for the action summary = result.get_summary() if summary: retval['summary'] = summary @@ -186,7 +190,37 @@ def format_alert_result(result): return format_result(result) -def alert_data_results(provides, all_app_runs, context): +def alert_lookup_results(provides, all_app_runs, context): + """Setup the view for an alert.""" + context['results'] = results = [] + + for summary, action_results in all_app_runs: + + for result in action_results: + formatted = {'param': result.get_param(), 'data': result.get_data()} + if not formatted: + continue + results.append(formatted) + + return 'alert_lookup_results.html' + + +def alert_update_results(provides, all_app_runs, context): + """Setup the view for an alert.""" + context['results'] = results = [] + + for summary, action_results in all_app_runs: + + for result in action_results: + formatted = {'param': result.get_param(), 'data': result.get_data()} + if not formatted: + continue + results.append(formatted) + + return 'alert_update_results.html' + + +def alert_search_results(provides, all_app_runs, context): """Setup the view for alert results.""" context['results'] = results = [] @@ -198,10 +232,10 @@ def alert_data_results(provides, all_app_runs, context): continue results.append(formatted) - return 'alert_data_results.html' + return 'alert_search_results.html' -def alert_rules_results(provides, all_app_runs, context): +def alert_rule_search_results(provides, all_app_runs, context): """Render the list of Alert Rules that match the search.""" context['results'] = results = [] @@ -213,7 +247,7 @@ def alert_rules_results(provides, all_app_runs, context): continue results.append(formatted) - return 'alert_rules_results.html' + return 'alert_rule_search_results.html' def format_threat_assessment_result(result, all_data=False): diff --git a/release_notes/4.0.0.md b/release_notes/4.0.0.md new file mode 100644 index 0000000..63b19bd --- /dev/null +++ b/release_notes/4.0.0.md @@ -0,0 +1,5 @@ +* Added two new actions: alert_lookup and alert_update +* On_poll functionality to download alerts +* alert_rule_lookup renamed to alert_rule_search to better describe the action +* alert_data_lookup renamed to alert_search to better describe the action +* Improved tagging of entities in alert widgets to find the related actions \ No newline at end of file diff --git a/reputation_results.html b/reputation_results.html index 39b14fc..2081119 100644 --- a/reputation_results.html +++ b/reputation_results.html @@ -35,6 +35,91 @@ Style elements are defined in a separate file, named below, and will be merged during compilation: recordedfuture_style.css --> +
diff --git a/threat_assessment_results.html b/threat_assessment_results.html index 45c25fb..6a9df9f 100644 --- a/threat_assessment_results.html +++ b/threat_assessment_results.html @@ -35,6 +35,91 @@ Style elements are defined in a separate file, named below, and will be merged during compilation: recordedfuture_style.css --> +
diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..c4644ad --- /dev/null +++ b/tox.ini @@ -0,0 +1,7 @@ +[flake8] +max-line-length = 145 +max-complexity = 28 +extend-ignore = F403,E128,E126,E111,E121,E127,E731,E201,E202,F405,E722,D,W292 + +[isort] +line_length = 145 diff --git a/wheels/py3/certifi-2022.6.15-py3-none-any.whl b/wheels/py3/certifi-2022.6.15-py3-none-any.whl new file mode 100644 index 0000000..6e70631 Binary files /dev/null and b/wheels/py3/certifi-2022.6.15-py3-none-any.whl differ diff --git a/wheels/py3/soupsieve-2.3.1-py3-none-any.whl b/wheels/py3/soupsieve-2.3.1-py3-none-any.whl deleted file mode 100644 index 85d33de..0000000 Binary files a/wheels/py3/soupsieve-2.3.1-py3-none-any.whl and /dev/null differ diff --git a/wheels/py3/soupsieve-2.3.2.post1-py3-none-any.whl b/wheels/py3/soupsieve-2.3.2.post1-py3-none-any.whl new file mode 100644 index 0000000..b363a9b Binary files /dev/null and b/wheels/py3/soupsieve-2.3.2.post1-py3-none-any.whl differ diff --git a/wheels/shared/certifi-2021.10.8-py2.py3-none-any.whl b/wheels/shared/certifi-2021.10.8-py2.py3-none-any.whl deleted file mode 100644 index fbcb86b..0000000 Binary files a/wheels/shared/certifi-2021.10.8-py2.py3-none-any.whl and /dev/null differ diff --git a/wheels/shared/urllib3-1.26.9-py2.py3-none-any.whl b/wheels/shared/urllib3-1.26.12-py2.py3-none-any.whl similarity index 57% rename from wheels/shared/urllib3-1.26.9-py2.py3-none-any.whl rename to wheels/shared/urllib3-1.26.12-py2.py3-none-any.whl index 5019453..6590a02 100644 Binary files a/wheels/shared/urllib3-1.26.9-py2.py3-none-any.whl and b/wheels/shared/urllib3-1.26.12-py2.py3-none-any.whl differ
- NVD Vulnerability - Description
+ NVD Vulnerability Description
{{ result.data.nvdDescription }}