ACTI Vulnerability Query
ACTI provides intelligence regarding security threats and vulnerabilities.
Vulnerability Management · Accenture CTI v2
Details
| ID | ACTI Vulnerability Query |
|---|---|
| Provider | Accenture |
| Category | Vulnerability Management |
| From Version | 5.5.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Accenture CTI provides intelligence regarding security threats and vulnerabilities.
This integration was integrated and tested with version v2.93.0 of ACTI
Configure ACTI Vulnerability Query in Cortex
| Parameter | Description | Required |
|---|---|---|
| url | URL | True |
| api_token | API Token | True |
| Source Reliability | Reliability of the source providing the intelligence data. | B - Usually reliable |
| insecure | Trust any certificate (not secure) | False |
| use_proxy | Use system proxy settings | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
acti-vuln
Checks the reputation of the given common vulnerabilities and exposures ID.
Base Command
acti-vuln
Input
| Argument Name | Description | Required |
|---|---|---|
| cve | CVE ID to check. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| CVE.ID | String | The ID of the CVE, for example: CVE-2022-1653 |
| CVE.CVSS2 | String | The CVSS2 temporal score of the CVE based on exploitability, remediation level & report confidence, for example: 10.0 |
| CVE.CVSS3 | String | The CVSS3 temporal score of the CVE based on exploitability, remediation level & report confidence, for example: 10.0 |
| CVE.Published | String | The timestamp of when the CVE was published. |
| CVE.Modified | String | The timestamp of when the CVE was last modified. |
| CVE.Description | String | A description of the CVE. |
| DBotScore.Indicator | String | The indicator that was tested. |
| DBotScore.Reliability | String | Reliability of the source providing the intelligence data. |
| DBotScore.Type | String | The indicator type. |
| DBotScore.Vendor | String | The vendor that was used to calculate the score. |
| DBotScore.Score | String | The actual score. |
Command Example
!acti-vuln cve=CVE-2022-1653
Context Example
{
"DBotScore": {
"Indicator": "CVE-2022-1653",
"Reliability": "B - Usually reliable",
"Score": 2,
"Type": "cve",
"Vendor": "ACTI Vulnerability Query"
},
"CVE": {
"CVSS2": "10.0",
"CVSS3": "10.0",
"Description": "Description of the vulnerability",
"ID": "CVE-2022-1653",
"Modified": "2022-01-27 03:40:00",
"Published": "2022-01-22 04:01:42",
}
}
Human Readable Output
Results
CPEs CVSS2 CVSS3 DbotReputation Description LastModified LastPublished Name UUID cpe:/a:f5:big-ip:16.1.1 10 10 2 Description of the vulnerability 2022-01-27 03:40:00 2022-01-22 04:01:42 CVE-2022-1653 cbc55efe-aa5c-4114-b532-e44f9b824fe1
Configuration parameters
url— URL (required)api_token— (required)integrationReliability— Source Reliability (required)insecure— Trust any certificate (not secure)use_proxy— Use system proxy settings
Commands (1)
-
acti-vulnChecks reputation of the vulnerability.
import demistomock as demisto from CommonServerPython import * # noqa # pylint: disable=unused-wildcard-import import urllib3 import traceback # Disable insecure warnings urllib3.disable_warnings() # pylint: disable=no-member """ CONSTANTS """ DATE_FORMAT = "%Y-%m-%d %H:%M:%S" ENDPOINTS = {"vulnerability": "/rest/vulnerability"} """ CLIENT CLASS """ class Client(BaseClient): def __init__(self, input_url: str, api_key: str, verify_certificate: bool, proxy: bool, endpoint="/rest/vulnerability"): base_url = urljoin(input_url, endpoint) PACK_VERSION = get_pack_version() DEMISTO_VERSION = demisto.demistoVersion() DEMISTO_VERSION = f'{DEMISTO_VERSION["version"]}.{DEMISTO_VERSION["buildNumber"]}' headers = { "Content-Type": "application/json", "auth-token": api_key, "User-Agent": f"AccentureCTI Pack/{PACK_VERSION} Palo Alto XSOAR/{DEMISTO_VERSION}", } super().__init__(base_url=base_url, verify=verify_certificate, headers=headers, proxy=proxy) def vulnerability_search(self, url_suffix: str, data: dict = {}) -> dict: return self._http_request(method="GET", url_suffix=url_suffix, params=data) class CustomCVE(Common.CVE): def __init__(self, id, cvss3, cvss2, published, modified, description, dbot, relationships=None): # type (str, str, str, str, str, str, str) -> None super().__init__( id=id, cvss="", published=published, modified=modified, description=description, relationships=relationships ) self.cvss3 = cvss3 self.cvss2 = cvss2 self.dbot_score = dbot def to_context(self): context_values = super().to_context() context_values[self.CONTEXT_PATH]["CVSS2"] = self.cvss2 context_values[self.CONTEXT_PATH]["CVSS3"] = self.cvss3 context_values[self.CONTEXT_PATH]["CVSS"]["CVSS2"] = self.cvss2 context_values[self.CONTEXT_PATH]["CVSS"]["CVSS3"] = self.cvss3 if self.dbot_score: context_values.update(self.dbot_score.to_context()) return context_values """ HELPER FUNCTIONS """ def _calculate_dbot_score(severity: int) -> int: """ Calculates Dbot score according to table: Dbot Score | severity 0 | 0 1 | 1,2 2 | 3,4 3 | 5,6,7 Args: severity: value from 1 to 5, determined by iDefense threat indicator Returns: Calculated score """ dbot_score = Common.DBotScore.NONE if severity > 4: dbot_score = Common.DBotScore.BAD elif severity > 2: dbot_score = Common.DBotScore.SUSPICIOUS elif severity > 0: dbot_score = Common.DBotScore.GOOD return dbot_score def _extract_result(res: dict, dbot_score_type: str, reliability: DBotScoreReliability) -> list[dict]: analysis_results = [] if res.get("total_size"): results_array = res.get("results", []) if len(results_array): for result in results_array: cpes = [] indicator_value = result.get("key", "") dbot_score: int = _calculate_dbot_score(result.get("severity", 0)) desc = "Match found in AccentureCTI database" dbot = Common.DBotScore(indicator_value, dbot_score_type, "ACTIVulnerabilityQuery", dbot_score, desc, reliability) vuln_techs = result.get("affects", "").get("vuln_techs", "") for vuln in vuln_techs: cpes.append(vuln.get("display_text", "")) last_published = result.get("last_published", "") if last_published: last_published_format = parse_date_string(last_published, DATE_FORMAT) else: last_published_format = "NA" last_modified = result.get("last_modified", "") if last_modified: last_modified_format = parse_date_string(last_modified, DATE_FORMAT) else: last_modified_format = "NA" display_text = result.get("display_text", "NA") analysis_info = { "Name": result.get("key", "NA"), "DbotReputation": dbot_score, "CVSS2": result.get("cvss2_temporal_score", "NA"), "CVSS3": result.get("cvss3_temporal_score", "NA"), "UUID": result.get("uuid", "NA"), "CPEs": cpes, "LastPublished": str(last_published_format), "LastModified": str(last_modified_format), "Description": result.get("description", ""), } analysis_results.append({"analysis_info": analysis_info, "dbot": dbot, "display_text": display_text}) return analysis_results def _returned_response(res: dict) -> list[str]: """ Checks which indicator value found on AccentureCTI database. Args: res: api response Returns: list of indicator values that returned from api request """ returned_res = [] if res.get("total_size"): results_array = res.get("results", []) if len(results_array): for result_content in results_array: returned_res.append(result_content.get("key", "")) return returned_res def _match_not_found(all_inputs: list, res: list) -> list[str]: """ Args: all_inputs: all indicator values received from the user res: list of all indicator values that returned from api request Returns: Which indicator has no match on AccentureCTI database """ value_not_found = [] for val in all_inputs: if val not in res: value_not_found.append(val) return value_not_found """ COMMAND FUNCTIONS """ def test_module(client: Client) -> str: # type: ignore """Tests API connectivity and authentication' Returning 'ok' indicates that the integration works like it is supposed to. Connection to the service is successful. Raises exceptions if something goes wrong. :type client: ``Client`` :param Client: client to use :return: 'ok' if test passed, anything else will fail the test. :rtype: ``str`` """ try: client.vulnerability_search(url_suffix="/v0") return "ok" except Exception as e: if "Error in API call [403]" in e.args[0]: return_results(f"This API token doesn't have permission for accessing vulnerability API!.\n Error: {str(e)}") demisto.debug(e.args[0]) else: raise DemistoException(f"Error in API call - check the input parameters and the API Key. Error: {e}.") def vuln_command(client: Client, args: dict, reliability: DBotScoreReliability) -> list[CommandResults]: vulns: list = argToList(args.get("cve", None)) if not vulns: raise ValueError("vuln not specified") result = client.vulnerability_search(url_suffix="/v0", data={"key.values": vulns}) analysis_results = _extract_result(result, DBotScoreType.CVE, reliability) returned_cves = _returned_response(result) cves_not_found = _match_not_found(vulns, returned_cves) command_results = [] for analysis_result in analysis_results: analysis_info: dict = analysis_result.get("analysis_info", {}) dbot = analysis_result.get("dbot") cve_name = analysis_info.get("Name", "") display_name = analysis_result.get("display_text", "") readable_output = tableToMarkdown(f"{display_name}", analysis_info) indicator = CustomCVE( cve_name, analysis_info.get("CVSS3"), analysis_info.get("CVSS2"), analysis_info.get("LastPublished"), analysis_info.get("LastModified"), analysis_info.get("Description"), dbot, ) # noqa: E501 command_results.append(CommandResults(indicator=indicator, raw_response=result, readable_output=readable_output)) # type: ignore # noqa: E501 for cve in cves_not_found: desc = "No results were found on AccentureCTI database" dbot = Common.DBotScore(cve, DBotScoreType.CVE, "ACTIVulnerabilityQuery", 0, desc) indicator = CustomCVE(cve, None, None, None, None, None, dbot) readable_output = f"No results were found for cve {cve}" command_results.append(CommandResults(indicator=indicator, readable_output=readable_output)) # type: ignore # noqa: E501 return command_results """ MAIN FUNCTION """ def main(): params = demisto.params() api_key = params.get("api_token") if isinstance(api_key, dict): api_key = api_key.get("password") base_url = urljoin(params.get("url", "")) reliability = params.get("integrationReliability", "B - Usually reliable") if DBotScoreReliability.is_valid_type(reliability): reliability = DBotScoreReliability.get_dbot_score_reliability_from_str(reliability) else: Exception("Accenture CTI error: Please provide a valid value for the Source Reliability parameter") commands = { "acti-vuln": vuln_command, } verify_certificate = not params.get("insecure", False) proxy = params.get("use_proxy", False) try: command = demisto.command() client = Client(base_url, api_key, verify_certificate, proxy, endpoint=ENDPOINTS["vulnerability"]) demisto.debug(f"Command being called is {command}") if command == "test-module": return_results(test_module(client)) elif command in commands: return_results(commands[command](client, demisto.args(), reliability)) # Log exceptions and return errors # noqa: E303 except Exception as e: if "Error in API call [403]" in e.args[0]: return_error(f"This API token doesn't have permission for accessing vulnerability API!.\n Error: {str(e)}") else: demisto.error(traceback.format_exc()) return_error(f"Failed to execute {demisto.command()} command.\nError:\n{str(e)}") if __name__ in ("__main__", "__builtin__", "builtins"): main()