Cisco WebEx Feed
Use the Cisco Webex Feed integration to fetch indicators from Webex.
Data Enrichment & Threat Intelligence · Cisco WebEx Feed · Feed
Details
| ID | Cisco WebEx Feed |
|---|---|
| Provider | Cisco Systems |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 6.0.0 |
| Docker Image | demisto/btfl-soup:1.0.1.10120494 |
| Supported Modules | Agentix XSIAM |
README
Use the Cisco Webex Feed integration to fetch indicators from WeBex.
Configure Cisco Webex Feed in Cortex
| Parameter | Description | Required |
|---|---|---|
| Fetch indicators | 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 |
| Traffic Light Protocol Color | The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed. | False |
| False | ||
| False | ||
| Feed Fetch Interval | False | |
| Tags | Supports CSV values. | 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 |
| Enrichment Excluded | Select this option to exclude the fetched indicators from the enrichment process. | False |
| Trust any certificate (not secure) | False | |
| 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.
webex-get-indicators
Gets indicators from the feed.
Base Command
webex-get-indicators
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of results to return. Default is 30. | Optional |
| indicator_type | The indicator type. Possible values are: CIDR, DOMAIN, Both. Default is Both. | Optional |
Context Output
There is no context output for this command.
Command example
!webex-get-indicators indicator_type=Both limit=3
Human Readable Output
Indicators from Webex
value type 1.1.1.1/1 CIDR 1.2.3.4/5 CIDR 8.8.8.8/8 CIDR *.wbx2.com DomainGlob *.ciscospark.com DomainGlob *.webexcontent.com DomainGlob
Configuration parameters
feed— Fetch indicatorsfeedReputation— Indicator ReputationfeedReliability— Source Reliability (required)tlp_color— Traffic Light Protocol ColorfeedExpirationPolicy—feedExpirationInterval—feedFetchInterval— Feed Fetch IntervalfeedTags— TagsfeedBypassExclusionList— Bypass exclusion listenrichmentExcluded— Enrichment Excludedinsecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (1)
-
webex-get-indicatorsGets indicators from the feed.
import json import bs4 import CiscoWebExFeed import pytest from bs4 import BeautifulSoup from CommonServerPython import * # noqa: F401 def util_load_json(path): with open(path, encoding="utf-8") as f: return json.loads(f.read()) def MockedClient(Client): client = Client(base_url="test") return client __BASE_URL = "https://help.webex.com/en-us/WBX264/How-Do-I-Allow-Webex-Meetings-Traffic-on-My-Network" DOMAIN_TABLE = [ ["Client Type", "Domain(s)"], ["domain1", "*.d1.com\t\t\t*.d5.com"], ["domain2", "*.d2.com"], ["Long message without domain name"], ] IP_LIST = [ [ "1.1.1.1/1 (CIDR) or 8.8.8.8 - 8.8.8.8 (net range)", "1.1.1.1/1 (CIDR) or 8.8.8.8 - 8.8.8.8 (net range)", "1.2.3.4/5 (CIDR) or 8.8.8.8 - 8.8.8.8 (net range)", ] ] HTML_DOMAIN_SECTION = util_load_json("test_data/tests_data_1.json") HTML_IP_SECTION = """<div class="panel-collapse collapse" id="id_135011"> <div class="panel-body"> <div class="body refbody"> <ul><li></li><li></li><li>1.1.1.1/1 (CIDR) or 8.8.8.8 - 8.8.8.8 (net range)</li><li></li><li></li></ul> </div> </div> </div>""" FETCH_INDICATORS_INPUT_1 = {"CIDR": ["ipmock"], "DOMAIN": ["domainmock"]} FETCH_INDICATORS_OUTPUT_1 = [ {"value": "ipmock", "type": "Domain", "fields": {"tags": ("very_good", "very_bad"), "trafficlightprotocol": "very_yellow"}}, { "value": "domainmock", "type": "Domain", "fields": {"tags": ("very_good", "very_bad"), "trafficlightprotocol": "very_yellow"}, }, ] FETCH_INDICATORS_NO_ENRICH_OUTPUT_1 = [ { "value": "ipmock", "type": "Domain", "fields": {"tags": ("very_good", "very_bad"), "trafficlightprotocol": "very_yellow"}, "enrichmentExcluded": True, }, { "value": "domainmock", "type": "Domain", "fields": {"tags": ("very_good", "very_bad"), "trafficlightprotocol": "very_yellow"}, "enrichmentExcluded": True, }, ] FETCH_INDICATORS_INPUT_2 = {"CIDR": ["ipmock1", "ipmock2"], "DOMAIN": ["domainmock1", "domainmock2"]} FETCH_INDICATORS_OUTPUT_2 = [ {"value": "ipmock1", "type": "Domain", "fields": {"tags": ("very_good", "very_bad"), "trafficlightprotocol": "very_yellow"}}, {"value": "ipmock2", "type": "Domain", "fields": {"tags": ("very_good", "very_bad"), "trafficlightprotocol": "very_yellow"}}, { "value": "domainmock1", "type": "Domain", "fields": {"tags": ("very_good", "very_bad"), "trafficlightprotocol": "very_yellow"}, }, { "value": "domainmock2", "type": "Domain", "fields": {"tags": ("very_good", "very_bad"), "trafficlightprotocol": "very_yellow"}, }, ] def test_grab_domains(): """ Given: - Raw list of tuples that contains domain name and domain url, returned by api call: first array is the title, 2 seconds arrays are data, last array is message. When: - Filtered list contains domain's urls only Then: - Return domains list without errors """ from CiscoWebExFeed import grab_domains expected_result = ["*.d1.com", "*.d2.com", "*.d5.com"] assert sorted(grab_domains(DOMAIN_TABLE)) == expected_result def test_grab_CIDR_ips(): """ Given: - Raw list that contains ips CIDR and NET RANGE, returned by api call: When: - Calling grab_CIDR_ips Then: - Return CIDR ips list without without duplicates """ from CiscoWebExFeed import grab_CIDR_ips expected_result = ["1.1.1.1/1", "1.2.3.4/5"] assert sorted(grab_CIDR_ips(IP_LIST)) == expected_result def test_grab_domain_table(): """ Given: a beautiful soup object that is similar to the domain table When: - grab_domain_table(soup) Then: - the function should return a list of lists that contains the domain table """ from CiscoWebExFeed import grab_domain_table soup = BeautifulSoup(HTML_DOMAIN_SECTION, "html.parser") expected_result = util_load_json("test_data/tests_data_2.json") assert grab_domain_table(soup) == expected_result def test_grab_ip_table(): """ Given: a soup object that is similar to the ip table When: - grab_ip_table(soup) Then: - the function should return a list of lists that contains the ips from the table """ from CiscoWebExFeed import grab_ip_table soup = BeautifulSoup(HTML_IP_SECTION, "html.parser") expected_result = [["1.1.1.1/1 (CIDR) or 8.8.8.8 - 8.8.8.8 (net range)"]] assert grab_ip_table(soup) == expected_result @pytest.mark.parametrize("input, expected", [("1.1.1.1/16", "CIDR"), ("*.example.com", "DomainGlob"), ("example.com", "Domain")]) def test_check_indicator_type__diffrent_inputs(input, expected): """ Given: A indicator of type: ip, domain or domain glob When: - check_indicator_type is called Then: - the function should return the correct indicator type """ from CiscoWebExFeed import check_indicator_type assert check_indicator_type(input) == expected @pytest.mark.parametrize( "input, limit, expected", [ ( "Both", 1, "### Indicators from Webex:\n|value|type|\n|---|---|\n| ipmock1 | mocked_type |\n| domainmock1 | mocked_type |\n", ), ( "CIDR", 2, "### Indicators from Webex:\n|value|type|\n|---|---|\n| ipmock1 | mocked_type |\n| ipmock2 | mocked_type |\n", ), ( "DOMAIN", 5, "### Indicators from Webex:\n|value|type|\n|---|---|\n| domainmock1 | mocked_type |\n| domainmock2 | mocked_type |\n", ), ], ) def test_get_indicators_command__diffrent_indicator_type_and_limit_as_input(mocker, input, expected, limit): """ Given: - a limit and an indicator type When: - get_indicators_command is called Then: - the function should return the expectetd result with the correct limit and indicator type """ from CiscoWebExFeed import Client, get_indicators_command client = MockedClient(Client) mocker.patch.object(Client, "all_raw_data", return_value="gg") mocker.patch.object(CiscoWebExFeed, "check_indicator_type", return_value="mocked_type") mocker.patch.object( CiscoWebExFeed, "parse_indicators_from_response", return_value={"CIDR": ["ipmock1", "ipmock2"], "DOMAIN": ["domainmock1", "domainmock2"]}, ) res = get_indicators_command(client=client, limit=limit, indicator_type=input) assert res.readable_output == expected def test_get_indicators_command__wrong_indicator_type(mocker): """ Given: - illegal indicator type as input When: - get_indicators_command is called Then: - the function should return the expectetd error message """ from CiscoWebExFeed import Client, get_indicators_command client = MockedClient(Client) mocker.patch.object(Client, "all_raw_data", return_value="gg") mocker.patch.object(CiscoWebExFeed, "check_indicator_type") mocker.patch.object( CiscoWebExFeed, "parse_indicators_from_response", return_value={"CIDR": ["ipmock1", "ipmock2"], "DOMAIN": ["domainmock1", "domainmock2"]}, ) with pytest.raises(DemistoException) as e: get_indicators_command(client=client, indicator_type="mock_type") assert e.value.message == "The indicator_type argument must be one of the following: Both, CIDR, DOMAIN" @pytest.mark.parametrize( "input, expected", [(FETCH_INDICATORS_INPUT_1, FETCH_INDICATORS_OUTPUT_1), (FETCH_INDICATORS_INPUT_2, FETCH_INDICATORS_OUTPUT_2)], ) def test_fetch_indicators_command__different_sizes_of_inputs(mocker, input, expected): """ Given: - tags and tlp_color When: - the fetch_indicators_command is called and uses the output of parse_indicators_from_response as input Then: - the function should return the expectetd result with the correct tags and tlp_color """ from CiscoWebExFeed import Client, fetch_indicators_command client = MockedClient(Client) mocker.patch.object(Client, "all_raw_data", return_value="gg") mocker.patch.object(CiscoWebExFeed, "parse_indicators_from_response", return_value=input) expected_result = expected assert fetch_indicators_command(client=client, tags=("very_good", "very_bad"), tlp_color="very_yellow") == expected_result def test_fetch_indicators_command__exclude_enrichment(mocker): """ Given: - Exclude enrichment parameter is used When: - Calling the fetch_indicators_command Then: - The indicators should include the enrichmentExcluded field if exclude is True. """ from CiscoWebExFeed import Client, fetch_indicators_command input = FETCH_INDICATORS_INPUT_1 expected_result = FETCH_INDICATORS_NO_ENRICH_OUTPUT_1 client = MockedClient(Client) mocker.patch.object(Client, "all_raw_data", return_value="gg") mocker.patch.object(CiscoWebExFeed, "parse_indicators_from_response", return_value=input) assert ( fetch_indicators_command(client=client, tags=("very_good", "very_bad"), tlp_color="very_yellow", enrichment_excluded=True) == expected_result ) def test_parse_indicators_from_response__fail_to_parse(mocker, requests_mock): """ Given: - a response from the website that is not in the expected format When: - parse_indicators_from_response is called Then: - the function should return the expected error message """ from CiscoWebExFeed import parse_indicators_from_response mocker.patch.object(bs4, ("BeautifulSoup")) mocker.patch.object(CiscoWebExFeed, "grab_domain_table") mocker.patch.object(CiscoWebExFeed, "grab_ip_table") mocker.patch.object(CiscoWebExFeed, "grab_CIDR_ips") mocker.patch.object(CiscoWebExFeed, "grab_domains", side_effect=DemistoException("No domains to grab")) mocked_response = requests_mock.get({__BASE_URL}, json={"name": "awesome-mock"}) mocked_response.text = "mocked text" with pytest.raises(DemistoException) as e: parse_indicators_from_response(mocked_response) assert e.value.message == "Failed to parse the response from the website. Error: No domains to grab" @pytest.mark.parametrize("CIDR_results, domain_results", [("domainmock", None), (None, "domainmock")]) def test_parse_indicators_from_response__ip_or_domain_indicators_are_None(mocker, requests_mock, CIDR_results, domain_results): """ Given: - a response from the website, (CIDR or domains) with the value None When: - parse_indicators_from_response is called Then: - the function should return the expected error message """ from CiscoWebExFeed import parse_indicators_from_response mocker.patch.object(bs4, ("BeautifulSoup")) mocker.patch.object(CiscoWebExFeed, "grab_domain_table") mocker.patch.object(CiscoWebExFeed, "grab_ip_table") mocker.patch.object(CiscoWebExFeed, "grab_CIDR_ips", return_value=CIDR_results) mocker.patch.object(CiscoWebExFeed, "grab_domains", return_value=domain_results) mocked_response = requests_mock.get({__BASE_URL}, json={"name": "awesome-mock"}) mocked_response.text = "mocked text" with pytest.raises(DemistoException) as e: parse_indicators_from_response(mocked_response) assert e.value.message == "Did not find the expected indicators in the response from the website"