Zoom Feed

Use the Zoom Feed integration to get indicators from the feed.

Data Enrichment & Threat Intelligence · Zoom Feed · Feed

Details

IDZoom Feed
ProviderZoomInfo
CategoryData Enrichment & Threat Intelligence
From Version5.5.0
Docker Imagedemisto/btfl-soup:1.0.1.10120494
Supported ModulesAgentix XSIAM

README

Most IT services are moving from on-premise solutions to cloud-based solutions. The public IP addresses, domains, and URLs that function as the endpoints for these solutions are very often not fixed, and the providers of the service publish their details on their websites in a less than ideal format (i.e., HTML) rather than through a proper REST API (i.e., JSON).

This fact makes it very difficult for IT and Security teams to provide these services with an appropriate level of security and automation. Any changes in the HTML schema of the provider website, will break the automation and has the potential to cause serious disruption to the users and the business. The alternative is to compromise on the security posture of the organization.

One example of these providers is Zoom.

This pack addresses this issue by automating the collection of endpoint data in the form of an indicator feed. This will facilitate validation of the indicators before using them in enforcement points, for example firewalls, proxies, and more.

Zoom Network Settings

For information about Zoom network settings, see the Zoom documentation.

Configure Zoom Feed in Cortex

Parameter Description Required
Fetch indicators   False
Firewall rules for certificate validation Zoom clients for certificate validation. False
Firewall rules for Zoom website All Zoom Clients. User’s web browser. 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
Feed Fetch Interval Setting a more frequent fetch interval may cause errors from the vendor. 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.

zoom-get-indicators


Gets indicators from the feed.

Base Command

zoom-get-indicators

Input

Argument Name Description Required
limit The maximum number of results to return. Default is 10. Optional

Context Output

There is no context output for this command.

Configuration parameters

  • feed — Fetch indicators
  • zoom_clients_certificate_validation — Firewall rules for certificate validation
  • zoom_clients_user_browser — Firewall rules for Zoom website
  • feedReputation — Indicator Reputation
  • feedReliability — Source Reliability (required)
  • tlp_color — Traffic Light Protocol Color
  • feedExpirationPolicy
  • feedExpirationInterval
  • feedFetchInterval — Feed Fetch Interval
  • feedTags — Tags
  • feedBypassExclusionList — Bypass exclusion list
  • enrichmentExcluded — Enrichment Excluded
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (1)

  • zoom-get-indicators

    Gets indicators from the feed.

from collections.abc import Callable

import demistomock as demisto
import urllib3
from CommonServerPython import *

# disable insecure warnings
urllib3.disable_warnings()

INTEGRATION_NAME = "Zoom Feed"
ZOOM_DOCS_IP_RANGES_URL = "https://assets.zoom.us/docs/ipranges"


class Client(BaseClient):
    """
    Client to use in the Zoom Feed integration. Overrides BaseClient.
    """

    def __init__(self, base_url: str, verify: bool = False, proxy: bool = False):
        """
        Implements class for Zoom feeds.
        :param url: the Zoom endpoint URL
        :verify: boolean, if *false* feed HTTPS server certificate is verified. Default: *false*
        :param proxy: boolean, if *false* feed HTTPS server certificate will not use proxies. Default: *false*
        """
        super().__init__(base_url, verify=verify, proxy=proxy)

    def get_indicators(self) -> Set:
        """
        Uses 5 text files which contains zoom endpoints. This files are linked from:
        https://support.zoom.us/hc/en-us/articles/201362683-Network-Firewall-or-Proxy-Server-Settings-for-Zoom
        and contains all the endpoints listed on the zoom firewall rules tables, accept the domains and ipv6 addresses.
        Using the text files instead of parsing the http page ןs due to blockage of the zoom support site.
        """
        params = demisto.params()
        list_ips_txt_files = ["Zoom.txt", "ZoomMeetings.txt", "ZoomCRC.txt", "ZoomPhone.txt", "ZoomCDN.txt"]

        indicators = set(argToList(params.get("zoom_clients_certificate_validation", [])))
        indicators.update(set(argToList(params.get("zoom_clients_user_browser", []))))

        for url in list_ips_txt_files:
            res = self._http_request(method="GET", url_suffix=url, resp_type="text")
            for ip in res.split("\n"):
                indicators.add(ip)
        return indicators

    def build_iterator(self) -> list:
        """Retrieves all entries from the feed.
        Returns:
            A list of objects, containing the indicators.
        """
        result = []

        try:
            indicators = list(self.get_indicators())

            for indicator in indicators:
                if auto_detect_indicator_type(indicator):
                    result.append({"value": indicator, "type": auto_detect_indicator_type(indicator), "FeedURL": self._base_url})

        except requests.exceptions.SSLError as err:
            demisto.debug(str(err))
            raise Exception(f"Connection error in the API call to {INTEGRATION_NAME}.\nCheck your not secure parameter.\n\n{err}")
        except requests.ConnectionError as err:
            demisto.debug(str(err))
            raise Exception(f"Connection error in the API call to {INTEGRATION_NAME}.\nCheck your Server URL parameter.\n\n{err}")
        except requests.exceptions.HTTPError as err:
            demisto.debug(str(err))
            raise Exception(f"Connection error in the API call to {INTEGRATION_NAME}.\n")
        except ValueError as err:
            demisto.debug(str(err))
            raise ValueError(f"Could not parse returned data to Json. \n\nError massage: {err}")

        return result


def test_module(client: Client, *_) -> str:
    """Builds the iterator to check that the feed is accessible.
    Args:
        client: Client object.
    Returns:
        Outputs.
    """
    client.build_iterator()
    return "ok"


def fetch_indicators(
    client: Client, feed_tags: list = [], tlp_color: str | None = None, limit: int = -1, enrichment_excluded: bool = False
) -> list[dict]:
    """Retrieves indicators from the feed
    Args:
        client (Client): Client object with request
        feed_tags (list): tags to assign fetched indicators
        limit (int): limit the results
        tlp_color (str): Traffic Light Protocol color
    Returns:
        Indicators.
    """
    iterator = client.build_iterator()
    indicators = []
    if limit > 0:
        iterator = iterator[:limit]
    for item in iterator:
        value = item.get("value")
        type_ = item.get("type", FeedIndicatorType.Domain)
        raw_data = {
            "value": value,
            "type": type_,
        }
        for key, val in item.items():
            raw_data.update({key: val})

        indicator_obj = {
            "value": value,
            "type": type_,
            "service": "Zoom Feed",
            "rawJSON": raw_data,
            "fields": {},
        }

        if feed_tags:
            indicator_obj["fields"]["tags"] = feed_tags

        if tlp_color:
            indicator_obj["fields"]["trafficlightprotocol"] = tlp_color

        if enrichment_excluded:
            indicator_obj["enrichmentExcluded"] = enrichment_excluded

        indicators.append(indicator_obj)
    return indicators


def get_indicators_command(client: Client, params: dict, args: dict[str, str]) -> CommandResults:
    """Wrapper for retrieving indicators from the feed to the war-room.
    Args:
        client: Client object with request
        params: demisto.params()
        args: demisto.args()
    Returns:
        Outputs.
    """
    feed_tags = argToList(params.get("feedTags", ""))
    tlp_color = params.get("tlp_color")
    limit = arg_to_number(args.get("limit")) or 10
    enrichment_excluded = params.get("enrichmentExcluded", False)
    indicators = fetch_indicators(client, feed_tags, tlp_color, limit, enrichment_excluded)

    if indicators:
        human_readable = tableToMarkdown("Indicators from Zoom Feed:", indicators, headers=["value", "type"], removeNull=True)
    else:
        human_readable = "No indicators from Zoom Feed were fetched."

    return CommandResults(readable_output=human_readable, raw_response=indicators)


def fetch_indicators_command(client: Client, params: dict) -> list[dict]:
    """Wrapper for fetching indicators from the feed to the Indicators tab.
    Args:
        client: Client object with request
        params: demisto.params()
    Returns:
        Indicators.
    """
    feed_tags = argToList(params.get("feedTags", ""))
    tlp_color = params.get("tlp_color")
    enrichment_excluded = params.get("enrichmentExcluded", False)
    indicators = fetch_indicators(client, feed_tags, tlp_color, enrichment_excluded=enrichment_excluded)
    return indicators


def main():
    """
    PARSE AND VALIDATE INTEGRATION PARAMS
    """
    params = demisto.params()
    insecure = not params.get("insecure", False)
    proxy = params.get("proxy", False)

    command = demisto.command()
    demisto.info(f"Command being called is {command}")

    try:
        client = Client(base_url=ZOOM_DOCS_IP_RANGES_URL, verify=insecure, proxy=proxy)

        commands: dict[str, Callable[[Client, dict[str, str], dict[str, str]], str | CommandResults]] = {
            "test-module": test_module,
            "zoom-get-indicators": get_indicators_command,
        }
        if command in commands:
            return_results(commands[command](client, demisto.params(), demisto.args()))

        elif command == "fetch-indicators":
            indicators = fetch_indicators_command(client, demisto.params())
            for iter_ in batch(indicators, batch_size=2000):
                demisto.createIndicators(iter_)

        else:
            raise NotImplementedError(f"Command {command} is not implemented.")

    except Exception as err:
        err_msg = f"Error in {INTEGRATION_NAME} Integration. [{err}]"
        return_error(err_msg)


if __name__ in ["__main__", "builtin", "builtins"]:
    main()