Details
| ID | OpenCVE |
|---|---|
| Provider | Amber Security SAS |
| Category | Vulnerability Management |
| From Version | 6.9.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Ingests CVEs from an instance of OpenCVE.
Configure OpenCVE in Cortex
| Parameter | Description | Required |
|---|---|---|
| Server URL | True | |
| Username | True | |
| Password | True | |
| Source Reliability | Reliability of the source providing the intelligence data. | True |
| Trust any certificate (not secure) | 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.
opencve-latest
Returns the latest updated CVEs from your reports.
Base Command
opencve-latest
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of CVEs to display. | Optional |
| lastRun | Last run. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| CVE.ID | String | The ID of the CVE. |
| CVE.CVSS | number | The CVSS score of the CVE. |
| CVE.Published | Date | The date the CVE was published. |
| CVE.Modified | Date | The date that the CVE was last modified. |
| CVE.Description | String | The description of the CVE. |
| DBotScore.Indicator | String | The indicator value. |
| DBotScore.Score | Number | The actual score. |
| DBotScore.Type | String | The indicator type. |
| DBotScore.Vendor | String | The vendor reporting the score of the indicator. |
cve
Returns CVE information by CVE ID.
Base Command
cve
Input
| Argument Name | Description | Required |
|---|---|---|
| cve | The CVE ID. For example: CVE-2014-1234. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| CVE.ID | String | The ID of the CVE. |
| CVE.CVSS | number | The CVSS score of the CVE. |
| CVE.Published | Date | The date the CVE was published. |
| CVE.Modified | Date | The date that the CVE was last modified. |
| CVE.Description | String | The description of the CVE. |
| DBotScore.Indicator | String | The indicator that was tested. |
| DBotScore.Score | Number | The indicator score. |
| DBotScore.Type | String | The indicator type. |
| DBotScore.Vendor | String | The vendor used to calculate the score. |
opencve-get-my-vendors
List the vendors subscriptions of the authenticated user.
Base Command
opencve-get-my-vendors
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| OpenCVE.Vendors | unknown | Vendors. |
opencve-get-my-products
List the products subscriptions of the authenticated user.
Base Command
opencve-get-my-products
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| OpenCVE.Products | unknown | Products. |
opencve-get-vendor-cves
Get vendor CVEs.
Base Command
opencve-get-vendor-cves
Input
| Argument Name | Description | Required |
|---|---|---|
| vendor_name | Vendor name. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| vendor_cves | unknown | CVEs for the vendor. |
opencve-get-product-cves
Get product CVEs.
Base Command
opencve-get-product-cves
Input
| Argument Name | Description | Required |
|---|---|---|
| vendor_name | Vendor name. | Required |
| product_name | Product name. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| product_cves | unknown | Product CVEs. |
opencve-get-reports
List the reports of the authenticated user or get a specific report.
Base Command
opencve-get-reports
Input
| Argument Name | Description | Required |
|---|---|---|
| report_id | Report ID. | Optional |
| page | Specific page to start from. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| reports | unknown | Reports. |
opencve-get-alerts
List the alerts of a report or get the details of a specific alert.
Base Command
opencve-get-alerts
Input
| Argument Name | Description | Required |
|---|---|---|
| report_id | The report ID. | Optional |
| page | Specific page to start from. | Optional |
| alert_id | The Alert ID. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| alerts | unknown | The Alerts from the provided Report ID. |
opencve-get-products
List the products associated to a vendor or get a specific one.
Base Command
opencve-get-products
Input
| Argument Name | Description | Required |
|---|---|---|
| vendor_name | Vendor name. | Required |
| product_name | Product name. | Optional |
| search | Filter the search by a keyword. | Optional |
| page | Specific page to start from. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| products | unknown | Products. |
opencve-get-vendors
List the products associated to a vendor or get a specific product of a vendor by specifying its name.
Base Command
opencve-get-vendors
Input
| Argument Name | Description | Required |
|---|---|---|
| vendor_name | Vendor name. | Optional |
| search | Filter the search by a keyword. | Optional |
| page | Specific page to start from. | Optional |
| letter | Filter by the first letter. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| vendors | unknown | Vendors. |
Configuration parameters
url— Server URL (required)credentials— Username (required)integration_reliability— Source Reliability (required)insecure— Trust any certificate (not secure)
Commands (10)
-
cveReturns CVE information by CVE ID.
-
opencve-get-alertsList the alerts of a report or get the details of a specific alert.
-
opencve-get-my-productsList the products subscriptions of the authenticated user.
-
opencve-get-my-vendorsList the vendors subscriptions of the authenticated user.
-
opencve-get-product-cvesGet product CVEs.
-
opencve-get-productsList the products associated to a vendor or get a specific one.
-
opencve-get-reportsList the reports of the authenticated user or get a specific report.
-
opencve-get-vendor-cvesGet vendor CVEs.
-
opencve-get-vendorsList the products associated to a vendor or get a specific product of a vendor by specifying its name.
-
opencve-latestReturns the latest updated CVEs from your reports.
import pytest from CommonServerPython import * from OpenCVE import * OPEN_CVE = OpenCVE(tlp="red") CLIENT = Client(server_url="https://www.opencve.io/api/", verify=False, proxy=False, auth=False) def util_load_json(path: str): with open(path, encoding="utf-8") as f: return json.loads(f.read()) def assert_nested_dicts_equal(input, expected): """Asserts a complex indicator structure from XSOAR (after `to_context()`) Args: input (dict): Input expected (dict): Expected output """ if isinstance(input, dict) and isinstance(expected, dict): assert set(input.keys()) == set(expected.keys()), "Keys in dictionaries are not equal." for key in input: assert_nested_dicts_equal(input[key], expected[key]) elif isinstance(input, list) and isinstance(expected, list): try: for node1, node2 in zip(sorted(input), sorted(expected)): assert_nested_dicts_equal(node1, node2) except TypeError: sorted_list1 = sorted(input, key=lambda x: sorted(x.items())) sorted_list2 = sorted(expected, key=lambda x: sorted(x.items())) for node1, node2 in zip(sorted_list1, sorted_list2): assert_nested_dicts_equal(node1, node2) else: assert input == expected, "Values in dictionaries are not equal." test_cases = [ # Test case 1: Empty input nodes list ([], []), # Test case 2: One node with no CPE matches ([{"children": [], "cpe_match": []}], []), # Test case 3: One node with a vulnerable CPE match ( [{"children": [], "cpe_match": [{"cpe23Uri": "cpe:2.3:a:vendor:product:version:*:*:*:*:*:*:*", "vulnerable": True}]}], ["cpe:2.3:a:vendor:product:version:*:*:*:*:*:*:*"], ), # Test case 4: Multiple nodes with multiple CPE matches ( [ {"children": [], "cpe_match": [{"cpe23Uri": "cpe:2.3:a:vendor1:product1:1.0:*:*:*:*:*:*", "vulnerable": True}]}, {"children": [], "cpe_match": [{"cpe23Uri": "cpe:2.3:a:vendor1:product1:2.0:*:*:*:*:*:*", "vulnerable": True}]}, {"children": [], "cpe_match": [{"cpe23Uri": "cpe:2.3:a:vendor2:product2:3.0:*:*:*:*:*:*", "vulnerable": True}]}, ], [ "cpe:2.3:a:vendor1:product1:1.0:*:*:*:*:*:*", "cpe:2.3:a:vendor1:product1:2.0:*:*:*:*:*:*", "cpe:2.3:a:vendor2:product2:3.0:*:*:*:*:*:*", ], ), # Node with children ( [ { "children": [ { "children": [], "operator": "OR", "cpe_match": [ { "cpe23Uri": "cpe:2.3:o:siemens:sppa-t3000_ses3000_firmware:*:*:*:*:*:*:*:*", "cpe_name": [], "vulnerable": True, } ], }, { "children": [], "operator": "OR", "cpe_match": [ { "cpe23Uri": "cpe:2.3:h:siemens:sppa-t3000_ses3000:-:*:*:*:*:*:*:*", "cpe_name": [], "vulnerable": False, } ], }, ], "operator": "AND", "cpe_match": [], } ], ["cpe:2.3:o:siemens:sppa-t3000_ses3000_firmware:*:*:*:*:*:*:*:*"], ), # Real CVE test (CVE-2019-0708) ( [ { "children": [], "operator": "OR", "cpe_match": [ {"cpe23Uri": "cpe:2.3:o:microsoft:windows_vista:-:sp2:*:*:*:*:*:*", "cpe_name": [], "vulnerable": True}, { "cpe23Uri": "cpe:2.3:o:microsoft:windows_server_2008:r2:sp1:*:*:*:*:x64:*", "cpe_name": [], "vulnerable": True, }, {"cpe23Uri": "cpe:2.3:o:microsoft:windows_server_2008:r2:sp1:*:*:*:*:itanium:*", "vulnerable": True}, {"cpe23Uri": "cpe:2.3:o:microsoft:windows_server_2008:-:sp2:*:*:*:*:*:*", "cpe_name": [], "vulnerable": True}, { "cpe23Uri": "cpe:2.3:o:microsoft:windows_xp:-:sp2:*:*:professional:*:x64:*", "cpe_name": [], "vulnerable": True, }, {"cpe23Uri": "cpe:2.3:o:microsoft:windows_xp:-:sp3:*:*:*:*:x86:*", "cpe_name": [], "vulnerable": True}, { "cpe23Uri": "cpe:2.3:o:microsoft:windows_server_2003:-:sp2:*:*:*:*:x86:*", "cpe_name": [], "vulnerable": True, }, { "cpe23Uri": "cpe:2.3:o:microsoft:windows_server_2003:-:sp2:*:*:*:*:x64:*", "cpe_name": [], "vulnerable": True, }, { "cpe23Uri": "cpe:2.3:o:microsoft:windows_server_2003:r2:sp2:*:*:*:*:*:*", "cpe_name": [], "vulnerable": True, }, {"cpe23Uri": "cpe:2.3:o:microsoft:windows_7:-:sp1:*:*:*:*:*:*", "cpe_name": [], "vulnerable": True}, ], } ], [ "cpe:2.3:o:microsoft:windows_server_2008:-:sp2:*:*:*:*:*:*", "cpe:2.3:o:microsoft:windows_server_2003:-:sp2:*:*:*:*:x86:*", "cpe:2.3:o:microsoft:windows_server_2008:r2:sp1:*:*:*:*:x64:*", "cpe:2.3:o:microsoft:windows_xp:-:sp3:*:*:*:*:x86:*", "cpe:2.3:o:microsoft:windows_7:-:sp1:*:*:*:*:*:*", "cpe:2.3:o:microsoft:windows_server_2003:-:sp2:*:*:*:*:x64:*", "cpe:2.3:o:microsoft:windows_server_2008:r2:sp1:*:*:*:*:itanium:*", "cpe:2.3:o:microsoft:windows_xp:-:sp2:*:*:professional:*:x64:*", "cpe:2.3:o:microsoft:windows_server_2003:r2:sp2:*:*:*:*:*:*", "cpe:2.3:o:microsoft:windows_vista:-:sp2:*:*:*:*:*:*", ], ), ] @pytest.mark.parametrize("nodes, expected", test_cases) def test_parse_cpes(nodes, expected): cpes = [cpe.cpe for cpe in parse_cpes(nodes)] assert sorted(cpes) == sorted(expected) @pytest.mark.parametrize( "response, expected", [ ( util_load_json("test_data/CVE-2019-0708.json"), { "ID": "CVE-2019-0708", "CVSS Score": 9.8, "Published": "2019-05-16T19:29:00Z", "Modified": "2021-06-03T18:15:00Z", "Description": "A remote code execution vulnerability exists in Remote Desktop Services formerly known as Terminal Services when an unauthenticated attacker connects to the target system using RDP and sends specially crafted requests, aka 'Remote Desktop Services Remote Code Execution Vulnerability'.", # noqa: E501 }, ), ( util_load_json("test_data/CVE-2023-3421.json"), { "ID": "CVE-2023-3421", "CVSS Score": 8.8, "Published": "2023-06-26T21:15:00Z", "Modified": "2024-01-31T17:15:12Z", "Description": "Dummy description", }, ), ], ) def test_cve_to_warroom(response, expected): # Regarding the "CVE-2023-3421" case, the API response will hold the CVSS score under the "metrics" key, # and we don't parse the data under that key, so in order to extract the CVSS score, we do so by accessing # the scores under the key "cvss", and give precedence to v3 over v2 _, parsed_cve = parse_cve(OPEN_CVE, response) warroom_output = cve_to_warroom(parsed_cve) assert warroom_output == expected @pytest.mark.parametrize("input, expected", [("CVE-2021-44228", True), ("CVEM-2021-44228", False)]) def test_valid_cve_format(input, expected): assert valid_cve_format(input) == expected @pytest.mark.parametrize( "response, expected", [(util_load_json("test_data/CVE-2019-0708.json"), (util_load_json("test_data/parsed_Cve.json")))] ) def test_parse_cve(response, expected): relationships, parsed_cve = parse_cve(OPEN_CVE, response) parsed_cve_relationships = [json.dumps(relationship.to_context()) for relationship in relationships] expected_relationships = [json.dumps(relationship) for relationship in expected["fields"]["relationships"]] assert sorted(parsed_cve_relationships) == sorted(expected_relationships) assert parsed_cve["fields"]["cvssvector"] == expected["fields"]["cvssvector"] assert parsed_cve["fields"]["cvssscore"] == expected["fields"]["cvssscore"] @pytest.mark.parametrize( "input, expected", [ ( util_load_json("test_data/CVE-2019-0708.json"), ["Windows vista", "Windows 7", "Windows server 2008", "Windows server 2003", "Windows xp", "Microsoft", "CWE-416"], ) ], ) def test_parse_tags(input, expected): relationships, tags = parse_tags(vendors=input["vendors"], cve_id=input["id"], cwes=input["cwes"]) assert sorted(tags) == sorted(expected) @pytest.mark.parametrize( "input, expected", [([{"value": "CVE-2019-0708"}, {"value": "CVE-2019-0708"}], [{"value": "CVE-2019-0708"}])] ) def test_dedupe_cves(input, expected): assert dedupe_cves(input) == expected @pytest.mark.parametrize( "input, expected", [(util_load_json("test_data/CVE-2019-0708.json"), util_load_json("test_data/indicator.json"))] ) def test_cve_to_indicator(input, expected): relationships, parsed_cve = parse_cve(OPEN_CVE, input) indicator = cve_to_indicator(ocve=OPEN_CVE, cve=parsed_cve, relationships=relationships) assert_nested_dicts_equal(indicator.to_context(), expected) @pytest.mark.parametrize( "response, expected, args, mock_url", [ ( util_load_json("test_data/reports_response.json"), CommandResults( outputs=[ {"id": "KLMHU9EB4N8C", "created_at": "2023-08-02T09:52:47Z", "details": ["microsoft"]}, {"id": "NZSBGGBLW4TH", "created_at": "2023-08-02T07:11:31Z", "details": ["microsoft"]}, ], outputs_prefix="OpenCVE.Reports", ), {}, "https://www.opencve.io/api/reports", ), ( util_load_json("test_data/single_report_response.json"), CommandResults( outputs=util_load_json("test_data/single_report_response.json"), outputs_prefix="OpenCVE.Reports.KLMHU9EB4N8C" ), {"report_id": "KLMHU9EB4N8C"}, "https://www.opencve.io/api/reports/KLMHU9EB4N8C", ), ], ) def test_get_reports_command(response, expected, args, mock_url, requests_mock): requests_mock.get(mock_url, json=response) result = get_reports_command(CLIENT, args=args) assert result.outputs == expected.outputs assert result.outputs_prefix == expected.outputs_prefix @pytest.mark.parametrize( "response, args, expected, mock_url", [ ( util_load_json("test_data/vendors_specific_vendor.json"), {"vendor_name": "paloaltonetworks"}, CommandResults( outputs=util_load_json("test_data/vendors_specific_vendor.json"), outputs_prefix="OpenCVE.paloaltonetworks" ), "https://www.opencve.io/api/vendors/paloaltonetworks", ), ( util_load_json("test_data/vendors.json"), {"search": "search", "letter": "a", "page": 1}, CommandResults(outputs=util_load_json("test_data/vendors.json"), outputs_prefix="OpenCVE.Vendors"), "https://www.opencve.io/api/vendors", ), ], ) def test_get_vendors_command(response, args, expected, mock_url, requests_mock): requests_mock.get(mock_url, json=response) result = get_vendors_command(CLIENT, args=args) assert result.outputs == expected.outputs assert result.outputs_prefix == expected.outputs_prefix @pytest.mark.parametrize( "response, expected, mock_url", [ ( util_load_json("test_data/my_vendors.json"), CommandResults(outputs=util_load_json("test_data/my_vendors.json"), outputs_prefix="OpenCVE.myVendors"), "https://www.opencve.io/api/account/subscriptions/vendors", ) ], ) def test_get_my_vendors_command(response, expected, mock_url, requests_mock): requests_mock.get(mock_url, json=response) result = get_my_vendors_command(CLIENT) assert result.outputs == expected.outputs assert result.outputs_prefix == expected.outputs_prefix @pytest.mark.parametrize( "response, expected, mock_url", [ ( util_load_json("test_data/my_products.json"), CommandResults(outputs=util_load_json("test_data/my_products.json"), outputs_prefix="OpenCVE.myProducts"), "https://www.opencve.io/api/account/subscriptions/products", ) ], ) def test_get_my_products_command(response, expected, mock_url, requests_mock): requests_mock.get(mock_url, json=response) result = get_my_products_command(CLIENT) assert result.outputs == expected.outputs assert result.outputs_prefix == expected.outputs_prefix # Tests that the method returns the correct value when the input needle is a key in self.maps @pytest.mark.parametrize( "input, expected", [("HIGH", "High (H)"), ("REQUIRED", "Required (R)"), ("TEMPORARY_FIX", "Temporary Fix (T)"), ("Unknown_key", "Unknown_key")], ) def test_existing_key(input, expected): obj = OpenCVE("white") assert obj._map(input) == expected @pytest.mark.parametrize("expected", [(["CVE-2021-28478", "CVE-2021-26418"])]) def test_cve_latest_command(expected, requests_mock): requests_mock.get("https://www.opencve.io/api/reports", json=util_load_json("test_data/reports_response.json")) requests_mock.get( "https://www.opencve.io/api/reports/KLMHU9EB4N8C/alerts", json=util_load_json("test_data/KLMHU9EB4N8C_alerts.json") ) requests_mock.get( "https://www.opencve.io/api/reports/NZSBGGBLW4TH/alerts", json=util_load_json("test_data/NZSBGGBLW4TH_alerts.json") ) requests_mock.get("https://www.opencve.io/api/cve/CVE-2021-28478", json=util_load_json("test_data/CVE-2021-28478.json")) requests_mock.get("https://www.opencve.io/api/cve/CVE-2021-26418", json=util_load_json("test_data/CVE-2021-26418.json")) result = cve_latest_command(CLIENT, OPEN_CVE, {"last_run": "2023-08-01T02:00:00"}) cves = [cve["value"] for cve in result.outputs] assert all(cve in expected for cve in cves) @pytest.mark.parametrize( "args, mock_url, mock_json", [ ( {"report_id": "KLMHU9EB4N8C", "alert_id": "475fde88-00dc-4024-9499-8197e334dfe7"}, "https://www.opencve.io/api/reports/KLMHU9EB4N8C/alerts/475fde88-00dc-4024-9499-8197e334dfe7", util_load_json("test_data/alert_475fde88-00dc-4024-9499-8197e334dfe7.json"), ), ( {"report_id": "KLMHU9EB4N8C"}, "https://www.opencve.io/api/reports/KLMHU9EB4N8C/alerts", util_load_json("test_data/alerts_KLMHU9EB4N8C.json"), ), ], ) def test_get_alerts_command(args, mock_url, mock_json, requests_mock): requests_mock.get(mock_url, json=mock_json) alerts = get_alerts_command(CLIENT, args) assert alerts.outputs == mock_json def test_get_alert_failed_commad(): with pytest.raises(SystemExit): get_alerts_command(CLIENT, {}) @pytest.mark.parametrize( "args, mock_url, mock_json, expected", [ ( {"cve": "CVE-2021-26418"}, "https://www.opencve.io/api/cve/CVE-2021-26418", util_load_json("test_data/CVE-2021-26418.json"), util_load_json("test_data/get_cve_command_outputs.json"), ) ], ) def test_get_cve_command(args, mock_url, mock_json, expected, requests_mock): requests_mock.get(mock_url, json=mock_json) cve = get_cve_command(CLIENT, OPEN_CVE, args) assert cve[0].outputs == expected @pytest.mark.parametrize("response, expected", [({}, "ok")]) def test_invalid_command_raises_error(mocker, requests_mock, response, expected): mocker.patch.object( demisto, "params", return_value={ "url": "https://www.opencve.io", "insecure": False, "proxy": False, "tlp_color": "RED", "credentials": {"identifier": "user", "password": "pass"}, }, ) mocker.patch.object(demisto, "command", return_value="test-module") mocker.patch.object(demisto, "results") requests_mock.get("https://www.opencve.io/api/account/subscriptions/vendors", json=response) main() results = demisto.results.call_args[0] assert results[0] == expected def test_failed_request(mocker): mocker.patch.object(demisto, "error") with pytest.raises(Exception): module_test_command(CLIENT) def test_get_product_cves_command(mocker): args = {"vendor_name": "vendor_name", "product_name": "product_name"} mocker.patch.object( CLIENT, "get_cves_by_product_request", return_value=[{"id": "CVE", "summary": "summary", "created_at": "created_at", "updated_at": "updated_at"}], ) mocker.patch.object( CLIENT, "get_cve_request", return_value={ "id": "CVE", "summary": "summary", "created_at": "created_at", "updated_at": "updated_at", "cvss": {"v2": None, "v3": 8.8}, "vendors": {"vendor": ["vendor"]}, "cwes": ["CWE"], }, ) results = get_product_cves_command(CLIENT, OPEN_CVE, args) assert results[0].relationships