FeedCyCognito
The CyCognito Feed integration retrieves the discovered assets from the CyCognito platform based on user-specified filters. A comprehensive dashboard and layout are also included.
Data Enrichment & Threat Intelligence · CyCognito Feed · Feed
Details
| ID | FeedCyCognito |
|---|---|
| Provider | CyCognito |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 6.2.0 |
| Docker Image | demisto/pycountry:1.0.0.10120494 |
| Supported Modules | Agentix XSIAM |
README
The CyCognito Feed integration retrieves the discovered assets from the CyCognito platform based on user-specified filters. A comprehensive dashboard and layout are also included.
This integration was integrated and tested with CyCognito V1 API.
Configure CyCognito Feed in Cortex
- Navigate to Settings > Integrations > Servers & Services.
- Search for CyCognito Feed.
- Click Add instance to create and configure a new integration instance.
| Parameter | Description | Required |
|---|---|---|
| API Key | The API Key required to authenticate to the service. | True |
| Region | Select the region based on the location of the CyCognito instance. If the region is not listed in the dropdown, choose the “Other” option and specify the region in the “Other Region” text field. | False |
| Other Region | Specify the region based on the location of the CyCognito instance. Only applicable if the “Other” option is selected in the Region dropdown. | False |
| Asset Type | The type of assets to be retrieved. | True |
| First Fetch Time | The date or relative timestamp from where to start fetching assets. Supported formats: 2 minutes, 2 hours, 2 days, 2 weeks, 2 months, 2 years, yyyy-mm-dd, yyyy-mm-ddTHH:MM:SSZ For example: 01 Mar 2021, 01 Feb 2021 04:45:33, 2022-04-17T14:05:44Z |
False |
| Max Fetch | The maximum number of assets to fetch every time. The maximum value is ‘1000’. | False |
| Organizations | Retrieves the assets attributed to a specific organization, subsidiary, or assignee. Supports comma-separated values. | False |
| Security Grade | Filters the assets according to security grade. Supported values: A: Very strong, B: Strong, C: Less vulnerable, D: Vulnerable, F: Highly vulnerable |
False |
| Hosting Type | Filters the assets based on their hosting type. Supported values: ‘owned’, ‘cloud’, ‘undetermined’ |
False |
| Locations | Filters the assets based on the geographic locations to which they belong. Multiple selection is supported. Locations are available only for IP, Domain, and Certificate asset types. |
False |
| Fetch indicators | Indicates whether to fetch indicators from the instance. | False |
| Indicator Reputation | Indicators from this integration instance will be marked with this reputation. | False |
| Source Reliability | Reliability of the source providing the intelligence data. | True |
| Feed Fetch Interval | Time interval for fetching indicators. | False |
| Bypass exclusion list | When selected, the exclusion list is ignored for indicators from this feed. This means that if an indicator from this feed is on the exclusion list, the indicator might still be added to the system. | False |
| Tags | Supports CSV values. | False |
| Traffic Light Protocol Color | The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed | False |
| Default Indicator Mapping | When selected, all the incoming indicators will map to a CyCognito Asset indicator type. | False |
| Fetch only Live Assets | When selected, Fetches only live assets. Note: This filter supports only IP and IP Range type of assets. |
False |
| Trust any certificate (not secure) | Indicates whether to allow connections without verifying the SSL certificate’s validity. | False |
| Use system proxy settings | Indicates whether to use XSOAR’s system proxy settings to connect to the API. | False |
- Click Test to validate the URLs, token, and connection.
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.
cycognito-get-indicators
Fetches a given limit of indicators from the CyCognito platform and displays them in human-readable format in the war room.
Base Command
cycognito-get-indicators
Input
| Argument Name | Description | Required |
|---|---|---|
| asset_type | The type of asset to be retrieved. Supported values: ‘ip’, ‘domain’, ‘cert’, ‘webapp’, ‘iprange’ |
Required |
| count | The number of results to retrieve. Maximum value is ‘1000’ Default value is ‘50’ |
Optional |
| offset | Sets the starting index for the returned results. By specifying offset, you retrieve a subset of records starting with the offset value. Default value is ‘0’ |
Optional |
| search | An Advanced Search parameter to query the response. Note: Retrieves all the occurrences that are included in the string. |
Optional |
| sort_by | The name of the field by which to sort the results. The response fields available for sorting the data are found in the following documentation: https://docs.cycognito.com/reference/reference-getting-started | Optional |
| sort_order | Specifies whether to sort the results in either ascending or descending order. Supported values: ‘asc’, ‘desc’ Default value is ‘desc’ |
Optional |
| first_seen | The date and time at which CyCognito first discovered and attributed the asset to the organization. Supported formats: 2 minutes, 2 hours, 2 days, 2 weeks, 2 months, 2 years, yyyy-mm-dd, yyyy-mm-ddTHH:MM:SSZ For example: 01 Mar 2021, 01 Feb 2021 04:45:33, 2022-04-17T14:05:44Z |
Optional |
| last_seen | The date and time at which CyCognito most recently attributed the asset to the organization. Supported formats: 2 minutes, 2 hours, 2 days, 2 weeks, 2 months, 2 years, yyyy-mm-dd, yyyy-mm-ddTHH:MM:SSZ For example: 01 Mar 2021, 01 Feb 2021 04:45:33, 2022-04-17T14:05:44Z |
Optional |
| organizations | Retrieves the assets attributed to a specific organization, subsidiary, or assignee. Supports comma-separated values. | Optional |
| hosting_type | Filters the assets according to their hosting type. Supports comma-separated values. Supported values: ‘owned’, ‘cloud’, ‘undetermined’ |
Optional |
| security_grade | Filters the assets according to security rating. Supports comma-separated values. Supported values: ‘A’, ‘B’, ‘C’, ‘D’, ‘F’ Where: A = Very strong B = Strong C = Less vulnerable D = Vulnerable F = Highly vulnerable |
Optional |
| status | Filters the assets according to their status. Supports comma-separated values. Supported values: ‘changed’, ‘new’, ‘normal’ |
Optional |
| locations | The geographical locations in which the asset is found. Supported values contain the three-letter ISO country code for the respective countries–e.g., IND, USA. Locations are available only for IP, Domain, and Certificate asset types. |
Optional |
| tags | A keyword or phrase that can be added to an asset or issue metadata. Supports comma-separated values. | Optional |
Context Output
There is no context output for this command.
Command example
!cycognito-get-indicators asset_type=ip count=2
Human Readable Output
Indicator Detail
Asset type: IP
Asset ID Security Grade Status Organizations First Seen Last Seen Locations Hosting Type 127.0.0.1 F normal ACME Ticketing, ACME Cleantech Solutions, Acme Holdings 30 Jun 2021, 12:32 PM 24 Mar 2022, 04:26 AM United States cloud 127.0.0.2 D normal Acme Interior Design 22 Jul 2021, 03:07 AM 24 Mar 2022, 04:26 AM India owned
Configuration parameters
feedIncremental— Incremental Feedapi_key— API Key (required)region— Regionother_region— Other Regionasset_type— Asset Type (required)first_fetch— First Fetch Timemax_fetch— Max Fetchorganizations— Organizationssecurity_grade— Security Gradehosting_type— Hosting Typelocations— Locationsfeed— Fetch indicatorsfeedReputation— Indicator ReputationfeedReliability— Source Reliability (required)feedFetchInterval— Feed Fetch IntervalfeedExpirationPolicy—feedExpirationInterval—feedBypassExclusionList— Bypass exclusion listfeedTags— Tagstlp_color— Traffic Light Protocol Colordefault_mapping— Default Indicator Mappingonly_alive— Fetch only Live Assetsinsecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (1)
-
cycognito-get-indicatorsFetches a given limit of indicators from the CyCognito platform and displays them in human-readable format in the war room.
"""Test file for FeedCyCognito Integration.""" import json import os import time import pytest from FeedCyCognito import ( AVAILABLE_ASSET_TYPES, AVAILABLE_HOSTING_TYPES, AVAILABLE_STATUS_TYPES, AVAILABLE_SECURITY_GRADE, BASE_URL, DATE_FORMAT, ERRORS, ) from CommonServerPython import arg_to_datetime DUMMY_TIME = "2022-03-21T07:06:41.000Z" ASSET_IP_ENDPOINT = "/assets/ip" CURRENT_TIME = time.time() BASE_URL = BASE_URL.format("") def util_load_json(path): """Load a json file to python dictionary.""" with open(path, encoding="utf-8") as f: return json.loads(f.read()) @pytest.fixture() def mocked_client(): """Create a mock client for testing.""" from FeedCyCognito import CyCognitoFeedClient client = CyCognitoFeedClient(params={"api_key": "dummy_key"}, verify=False, proxy=False) return client @pytest.mark.parametrize( "expected, args", [ ( [{"field": "locations", "op": "in", "values": ["IND"]}, {"field": "hosting-type", "op": "in", "values": ["cloud"]}], {"asset_type": "ip", "hosting_type": ["cloud"], "locations": ["IND"]}, ), ( [{"field": "locations", "op": "in", "values": ["IND"]}, {"field": "hosting-type", "op": "in", "values": ["cloud"]}], {"asset_type": "domain", "hosting_type": ["cloud"], "locations": ["IND"]}, ), ([{"field": "security-grade", "op": "in", "values": ["a"]}], {"asset_type": "iprange", "security_grade": ["a"]}), ( [ { "field": "first-seen", "op": "between", "values": [["2020-01-01T00:00:00Z", arg_to_datetime(CURRENT_TIME).strftime(DATE_FORMAT)]], }, { "field": "last-seen", "op": "between", "values": [["2020-01-01T00:00:00Z", arg_to_datetime(CURRENT_TIME).strftime(DATE_FORMAT)]], }, ], {"first_seen": "2020-01-01T00:00:00Z", "last_seen": "2020-01-01T00:00:00Z"}, ), ], ) def test_prepare_filters_for_get_indicators(expected, args, mocker): """Test case scenario for successful execution of prepare_filters_for_get_indicators function.""" from FeedCyCognito import prepare_body_filters_for_get_indicators mocker.patch("time.time", return_value=CURRENT_TIME) assert prepare_body_filters_for_get_indicators(**args) == expected @pytest.mark.parametrize( "err_msg, args", [ (ERRORS["INVALID_REQUIRED_PARAMETER"].format("asset_type"), {"asset_type": ""}), (ERRORS["INVALID_SINGLE_SELECT_PARAM"].format("test", "asset_type", AVAILABLE_ASSET_TYPES), {"asset_type": "test"}), (ERRORS["INVALID_PAGE_SIZE"].format("-10"), {"count": "-10", "asset_type": "ip"}), ('Invalid number: "count"="abc"', {"count": "abc"}), (ERRORS["INVALID_PAGE_SIZE"].format("10000"), {"count": "10000", "asset_type": "ip"}), ('Invalid number: "offset"="abc"', {"offset": "abc"}), ('Invalid date: "first_seen"="abc"', {"first_seen": "abc"}), ('Invalid date: "last_seen"="abc"', {"last_seen": "abc"}), ( ERRORS["INVALID_SINGLE_SELECT_PARAM"].format("test", "sort_order", ["asc", "desc"]), {"sort_order": "test", "asset_type": "ip"}, ), ( ERRORS["INVALID_MULTI_SELECT_PARAM"].format("hosting_type", AVAILABLE_HOSTING_TYPES), {"hosting_type": "test", "asset_type": "ip"}, ), ( ERRORS["INVALID_MULTI_SELECT_PARAM"].format("security_grade", [x.upper() for x in AVAILABLE_SECURITY_GRADE]), {"security_grade": "a,e", "asset_type": "ip"}, ), (ERRORS["INVALID_MULTI_SELECT_PARAM"].format("status", AVAILABLE_STATUS_TYPES), {"status": "test", "asset_type": "ip"}), ], ) def test_get_indicators_arguments_when_invalid_arguments_provided(err_msg, args, mocked_client): """Test case scenario when arguments provided to get_indicators_command are invalid.""" from FeedCyCognito import get_indicators_command with pytest.raises(ValueError) as err: get_indicators_command(mocked_client, args) assert str(err.value) == err_msg def test_get_indicators_command_when_valid_response_returned_for_ip(requests_mock, mocked_client): """Test case scenario for successful execution of cycognito-get-indicators command.""" from FeedCyCognito import get_indicators_command expected_resp = util_load_json( os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data/get_indicators_success_response_ip.json") ) with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data/get_indicators_success_hr_ip.md")) as f: expected_hr_output = f.read() requests_mock.post(BASE_URL + ASSET_IP_ENDPOINT, json=expected_resp) resp = get_indicators_command(mocked_client, {"asset_type": "ip"}) assert resp.raw_response == expected_resp assert resp.readable_output == expected_hr_output def test_get_indicators_command_when_valid_response_returned_for_domain(requests_mock, mocked_client): """Test case scenario for successful execution of cycognito-get-indicators command.""" from FeedCyCognito import get_indicators_command expected_resp = util_load_json( os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data/get_indicators_success_response_domain.json") ) with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data/get_indicators_success_hr_domain.md")) as f: expected_hr_output = f.read() requests_mock.post(BASE_URL + "/assets/domain", json=expected_resp) resp = get_indicators_command(mocked_client, {"asset_type": "domain"}) assert resp.raw_response == expected_resp assert resp.readable_output == expected_hr_output def test_get_indicators_command_when_valid_response_returned_for_cert(requests_mock, mocked_client): """Test case scenario for successful execution of cycognito-get-indicators command.""" from FeedCyCognito import get_indicators_command expected_resp = util_load_json( os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data/get_indicators_success_response_cert.json") ) with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data/get_indicators_success_hr_cert.md")) as f: expected_hr_output = f.read() requests_mock.post(BASE_URL + "/assets/cert", json=expected_resp) resp = get_indicators_command(mocked_client, {"asset_type": "cert"}) assert resp.raw_response == expected_resp assert resp.readable_output == expected_hr_output def test_get_indicators_command_when_valid_response_returned_for_iprange(requests_mock, mocked_client): """Test case scenario for successful execution of cycognito-get-indicators command.""" from FeedCyCognito import get_indicators_command expected_resp = util_load_json( os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data/get_indicators_success_response_iprange.json") ) with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data/get_indicators_success_hr_iprange.md")) as f: expected_hr_output = f.read() requests_mock.post(BASE_URL + "/assets/iprange", json=expected_resp) resp = get_indicators_command(mocked_client, {"asset_type": "iprange"}) assert resp.raw_response == expected_resp assert resp.readable_output == expected_hr_output def test_get_indicators_command_when_empty_response_returned(requests_mock, mocked_client): """Test case scenario for successful execution of cycognito-get-indicators command when empty response returned.""" from FeedCyCognito import get_indicators_command requests_mock.post(BASE_URL + ASSET_IP_ENDPOINT, json=[]) resp = get_indicators_command(mocked_client, {"asset_type": "ip"}) assert resp.raw_response == [] assert resp.readable_output == "### Indicator Detail: \n #### Asset type: IP\n**No entries.**\n" def test_test_module(requests_mock, mocked_client): """Test case scenario for successful execution of test-module command when valid response returned.""" from FeedCyCognito import test_module requests_mock.post(f"{BASE_URL}{ASSET_IP_ENDPOINT}", json=[], status_code=200) assert test_module(mocked_client, {"feed": False}) == "ok" @pytest.mark.parametrize( "err_msg, args", [ (ERRORS["INVALID_PAGE_SIZE"].format("-10"), {"max_fetch": "-10", "asset_type": "ip", "feed": False}), ('Invalid number: "Max Fetch"="abc"', {"max_fetch": "abc", "feed": False}), (ERRORS["INVALID_PAGE_SIZE"].format("10000"), {"max_fetch": "10000", "asset_type": "ip", "feed": False}), ('Invalid date: "First Fetch Time"="abc"', {"first_fetch": "abc", "feed": False}), ( ERRORS["INVALID_MULTI_SELECT_PARAM"].format("hosting_type", AVAILABLE_HOSTING_TYPES), {"hosting_type": "test", "asset_type": "ip", "feed": False}, ), ( ERRORS["INVALID_MULTI_SELECT_PARAM"].format("security_grade", [x.upper() for x in AVAILABLE_SECURITY_GRADE]), {"security_grade": "a,e", "asset_type": "ip", "feed": False}, ), ( ERRORS["INVALID_COUNTRY_ERROR"].format("invalid_country_name"), {"locations": ["invalid_country_name"], "asset_type": "ip", "feed": False}, ), ], ) def test_fetch_indicators_when_invalid_arguments_provided(err_msg, args, mocked_client, capfd): """Test case scenario when arguments provided to fetch-indicators are invalid.""" from FeedCyCognito import fetch_indicators_command with pytest.raises(ValueError) as err: capfd.close() fetch_indicators_command(mocked_client, args, {}) assert str(err.value) == err_msg def test_fetch_indicators_command_when_valid_response_returned_with_updated_last_run(requests_mock, mocked_client): """Test case scenario when valid response returned by fetch-indicators command with updated last run.""" from FeedCyCognito import fetch_indicators_command mock_response = util_load_json( os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data/fetch_indicator_response.json") ) indicators = util_load_json( os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data/fetch_indicator_indicators.json") ) requests_mock.post(BASE_URL + ASSET_IP_ENDPOINT, json=mock_response, status_code=200) args = { "asset_type": "ip", "max_fetch": 10, "feed": True, "first_fetch": "10 days", "organizations": "Acme Holding, Acme Interior", "security_grade": ["A: Very Strong", "B: Strong"], "hosting_type": ["owned"], "locations": ["India", "United States"], "default_mapping": False, } last_run = {"last_fetch": DUMMY_TIME, "offset": 2} next_run, actual_indicators = fetch_indicators_command(mocked_client, args, last_run) assert next_run == {"last_fetch": "2022-03-31T03:39:22.569000Z", "offset": 0} assert actual_indicators == indicators def test_fetch_indicators_command_when_empty_response_returned_with_last_run(requests_mock, mocked_client): """Test case scenario when empty response is returned with same last run as previous.""" from FeedCyCognito import fetch_indicators_command requests_mock.post(BASE_URL + ASSET_IP_ENDPOINT, json=[], status_code=200) args = {"asset_type": "ip", "max_fetch": 10, "feed": True, "locations": ["India"]} last_run = {"last_fetch": DUMMY_TIME, "offset": 2} next_run, actual_indicators = fetch_indicators_command(mocked_client, args, last_run) assert next_run == {"last_fetch": DUMMY_TIME, "offset": 2} assert actual_indicators == [] def test_fetch_indicators_command_when_empty_response_returned_without_last_run(requests_mock, mocked_client): """Test case scenario when empty response is returned with empty last run.""" from FeedCyCognito import fetch_indicators_command requests_mock.post(BASE_URL + ASSET_IP_ENDPOINT, json=[], status_code=200) args = {"asset_type": "ip", "max_fetch": 10, "feed": True, "locations": ["India"]} next_run, actual_indicators = fetch_indicators_command(mocked_client, args, {}) assert next_run == {} assert actual_indicators == [] def test_test_module_when_region_param_is_selected(requests_mock): """ Test case scenario for successful execution of test_module when region param is selected. Given: - mocked client When: - Calling `test_module` function Then: - Returns an ok message """ from FeedCyCognito import test_module, CyCognitoFeedClient, BASE_URL params = {"api_key": "dummy_key", "region": "US", "feed": "false"} BASE_URL = BASE_URL.format("us-") mock_client = CyCognitoFeedClient(params=params, verify=False, proxy=False) requests_mock.post(f"{BASE_URL}/assets/ip", json=[], status_code=200) assert test_module(mock_client, params) == "ok" def test_test_module_when_other_region_param_is_selected(requests_mock): """ Test case scenario for successful execution of test_module when other_region param is selected. Given: - mocked client When: - Calling `test_module` function Then: - Returns an ok message """ from FeedCyCognito import test_module, CyCognitoFeedClient, BASE_URL params = {"api_key": "dummy_key", "region": "Other", "other_region": "europe", "feed": "false"} BASE_URL = BASE_URL.format("europe-") mock_client = CyCognitoFeedClient(params=params, verify=False, proxy=False) requests_mock.post(f"{BASE_URL}/assets/ip", json=[], status_code=200) assert test_module(mock_client, params) == "ok"