Cisco Secure Malware Analytics

Secure Malware Analytics (formerly Threat Grid) combines advanced sandboxing with threat intelligence into one unified solution to protect organizations from malware.

Data Enrichment & Threat Intelligence · Cisco Secure Malware Analytics · Feed

Details

IDCisco Secure Malware Analytics
ProviderCisco Systems
CategoryData Enrichment & Threat Intelligence
From Version5.5.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM EDR Cortex Cloud Cloud Runtime Security

README

Secure Malware Analytics (formerly Threat Grid) combines advanced sandboxing with threat intelligence into one unified solution to protect organizations from malware.

Configure Cisco Secure Malware Analytics in Cortex

Parameter Description Required
API Key The Cisco Secure Malware Analytics API key. True
Feed Name The feed name to fetch. True
First fetch The date or number of days from when to start fetching indicators. False
Fetch indicators Whether to fetch indicators. False
Indicator Reputation Indicators from this integration instance will be marked with this reputation. False
Traffic Light Protocol Color The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed. False
Tags Supports CSV values. False
Source Reliability Reliability of the source providing the intelligence data. True
Feed Fetch Interval The feed fetch interval. 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
Use system proxy settings Whether to use the system proxy settings. False
Trust any certificate Whether to 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.

cisco-sma-get-indicators


Retrieves indicators.

Base Command

cisco-sma-get-indicators

Input

Argument Name Description Required
limit The maximum number of indicators to retrieve. Optional

Context Output

Path Type Description
CiscoSMA.value String The indicator value.
CiscoSMA.type Unknown The indicator type.
CiscoSMA.Tags String Tags that are associated with the indicator.
CiscoSMA.Description String The feed description.
CiscoSMA.FeedRelatedIndicators.type String The type of the indicators that are associated with the domain.
CiscoSMA.FeedRelatedIndicators.value String Indicators that are associated with the domain.

Command Example

!cisco-sma-get-indicators limit=1

Context Example

{
    "CiscoSMA": {
        "fields": {
            "Description": "DNS response information from requests made by document samples performing network communications.",
            "FirstSeenBySource": "2021-04-13T12:47:34Z",
            "Tags": [
                "doc-net-com-dns"
            ],
            "reportedby": "CiscoSMA",
            "trafficlightprotocol": "GREEN"
        },
        "rawJSON": {
            "description": "DNS response information from requests made by document samples performing network communications.",
            "domain": "example.com",
            "info": "example.com/feeds/doc-net-com-dns/domain",
            "ips": [
                "0.0.0.0"
            ],
            "sample": "example",
            "sample_md5": "1234556",
            "sample_sha1": "1234556",
            "sample_sha256": "1234556",
            "timestamp": "2021-04-13T12:47:34Z"
        },
        "type": "IP",
        "value": "0.0.0.0"
    }
}

Human Readable Output

CiscoSMA Indicators

value type
o.o.o.o IP

cisco-sma-reset-fetch-indicators


WARNING: This command will reset your fetch history.

Base Command

cisco-sma-reset-fetch-indicators

Input

There are no input arguments for this command.

Context Output

There is no context output for this command.

Command Example

!cisco-sma-reset-fetch-indicators

Human Readable Output

Fetch history deleted successfully

Configuration parameters

  • base_url — URL
  • api_key — API Key (Leave empty. Fill in the API Key in the password field.)
  • feed_name — Feed Name (required)
  • first_fetch — First fetch
  • feed — Fetch indicators
  • feedReputation — Indicator Reputation
  • tlp_color — Traffic Light Protocol Color
  • feedTags — Tags
  • feedReliability — Source Reliability (required)
  • feedExpirationPolicy
  • feedExpirationInterval
  • feedFetchInterval — Feed Fetch Interval
  • feedBypassExclusionList — Bypass exclusion list
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)
  • create_relationships — Create Relationships

Commands (2)

  • cisco-sma-get-indicators

    Retrieves indicators.

  • cisco-sma-reset-fetch-indicators

    WARNING: This command will reset your fetch history.

import demistomock as demisto  # noqa: F401
import urllib3
from CommonServerPython import *  # noqa: F401

# disable insecure warnings
urllib3.disable_warnings()

FEED_NAME = [
    "dga-dns",
    "autorun-registry",
    "banking-dns",
    "dll-hijacking-dns",
    "doc-net-com-dns",
    "downloaded-pe-dns",
    "dynamic-dns",
    "irc-dns",
    "modified-hosts-dns",
    "parked-dns",
    "public-ip-check-dns",
    "ransomware-dns",
    "rat-dns",
    "scheduled-tasks",
    "sinkholed-ip-dns",
    "stolen-cert-dns",
]


class Client(BaseClient):
    def __init__(
        self,
        api_key,
        verify,
        proxy,
        first_fetch,
        feed_name,
        feed_tags,
        tlp_color,
        create_relationships,
        base_url="https://panacea.threatgrid.com/api/v3/feeds/",
    ):
        """Implements class for the feed.

        Args:
            api_key: API Key.
            verify: boolean, if *false* feed HTTPS server certificate is verified. Default: *false*
            first_fetch: The date from which to start fetching feeds
            feed_name: The feed names to fetch
            feed_tags: feed tags.
            tlp_color: Traffic Light Protocol color.
            create_relationships: boolean, if *false* no relationships are created. Default: *true*
        """
        super().__init__(base_url=base_url, verify=verify, proxy=proxy)
        self.first_fetch = first_fetch
        self.feed_name = feed_name
        self.feed_tags = feed_tags
        self.tlp_color = tlp_color
        self.create_relationships = create_relationships
        self._api_key = api_key

    def get_indicators(self, feed_name: str, time_stamp: Optional[str]):
        """Retrieves all indicators from the feed.

        Args:
            :param feed_name: the feed name to fetch
            :param time_stamp: Optional - fetch feeds only from this day

        """
        suffix = f"{feed_name}_{time_stamp}.json" if time_stamp else f"{feed_name}.json"
        try:
            return self._http_request("GET", suffix, params={"api_key": self._api_key}, timeout=70)
        except Exception as error:
            if "Unauthorized" in str(error):
                raise DemistoException("Authorization Error: make sure the API Key is correctly set")
            else:
                raise DemistoException(error)


def create_related_ips(obj: dict, feed_name: str, tlp_color: str) -> list[dict]:
    """creates list indicators of the related ips.

    Args:
        :param obj: from the response
        :param feed_name: the feed That it was fetch there
        :param tlp_color: Traffic Light Protocol color
        :return: indicators list

    """
    return [
        (
            {
                "value": ip,
                "type": "IP",
                "rawJSON": obj,
                "fields": {
                    "Tags": [feed_name],
                    "reportedby": "CiscoSMA",
                    "Description": obj.get("description"),
                    "FirstSeenBySource": obj.get("timestamp"),
                    "trafficlightprotocol": tlp_color,
                },
            }
        )
        for ip in obj.get("ips")  # type:ignore
    ]


def create_related_files(obj: dict, feed_name: str, tlp_color: str) -> dict:
    """creates dict of the related file indicator.

    Args:
        :param obj: from the response
        :param feed_name: the feed That it was fetch there
        :param tlp_color: Traffic Light Protocol color
        :return: indicator

    """
    return {
        "value": obj.get("sample_sha256"),
        "type": "File",
        "rawJSON": obj,
        "fields": {
            "Tags": [feed_name],
            "reportedby": "CiscoSMA",
            "Description": obj.get("description"),
            "FirstSeenBySource": obj.get("timestamp"),
            "MD5": obj.get("sample_md5"),
            "SHA1": obj.get("sample_sha1"),
            "trafficlightprotocol": tlp_color,
        },
    }


def create_entity_relationships(feed_related_indicators: list, current_domain: str) -> list:
    """

    Args:
        feed_related_indicators: Indicators related to the domain returned from fetch_indicators.
        current_domain: Returned indicator from fetch_indicators.

    Returns:
        relationships: EntityRelationships list.

    """
    relationships = []
    for relation in feed_related_indicators:
        if relation.get("value") != "":
            entity_relation = EntityRelationship(
                name=EntityRelationship.Relationships.RELATED_TO,
                entity_a=current_domain,
                entity_a_type="Domain",
                entity_b=relation.get("value"),
                entity_b_type=relation.get("type"),
            )
            relationships.append(entity_relation.to_indicator())
    return relationships


def test_module(client: Client) -> str:
    """Goes through all the code of the fetch.
    Args:
        client: Client object with request

    Returns:
        str: ok.
    """
    fetch_indicators(client)
    return "ok"


def fetch_indicators(client: Client, time_to_stop_fetch: Optional[datetime] = None) -> tuple[list, bool]:
    """Retrieves indicators from the feed

    Args:
        client: Client object with request
        time_to_stop_fetch: Time to stop the fetch before it falls on timeout

    Returns:
        List. Processed indicator from feed.
    """
    fetch_time_stamp = None
    files = ["sample_sha256", "sample_sha1", "sample_md5"]
    if client.first_fetch.date() < arg_to_datetime("now").date():  # type:ignore
        fetch_time_stamp = client.first_fetch.date().isoformat()
    else:
        client.first_fetch = arg_to_datetime("now")

    indicators = []
    domains_map: dict[str, dict] = {}
    for name in client.feed_name:
        if time_to_stop_fetch and arg_to_datetime("now") > time_to_stop_fetch:  # type:ignore
            return [], False
        result = client.get_indicators(feed_name=name, time_stamp=fetch_time_stamp)
        for obj in result:
            feed_related_indicators = [{"type": "IP", "value": ip} for ip in obj.get("ips")]
            feed_related_indicators.extend([{"type": "File", "value": obj.get(file_hash)} for file_hash in files])
            current_domain = obj.get("domain")
            relationships = create_entity_relationships(feed_related_indicators, current_domain)
            if current_domain in domains_map:
                if name not in domains_map[current_domain]["fields"]["Tags"]:
                    domains_map[current_domain]["fields"]["Tags"].append(name)
                domains_map[current_domain]["fields"]["FeedRelatedIndicators"].extend(
                    related
                    for related in feed_related_indicators
                    if related not in domains_map[current_domain]["fields"]["FeedRelatedIndicators"]
                )
                existing_relations = [relation.get("entityB") for relation in domains_map[current_domain]["relationships"]]
                new_relations = filter(lambda relation: relation.get("entityB") not in existing_relations, relationships)
                domains_map[current_domain]["relationships"].extend(new_relations)

            else:
                domains_map[current_domain] = {
                    "value": current_domain,
                    "type": "Domain",
                    "rawJSON": obj,
                    "relationships": relationships,
                    "fields": {
                        "Tags": [name],
                        "reportedby": "CiscoSMA",
                        "FeedRelatedIndicators": feed_related_indicators,
                        "Description": obj.get("description"),
                        "FirstSeenBySource": obj.get("timestamp"),
                    },
                }
            if client.tlp_color:
                domains_map[current_domain]["fields"]["trafficlightprotocol"] = client.tlp_color
            if client.feed_tags:
                domains_map[current_domain]["fields"]["Tags"] += client.feed_tags
            indicators += create_related_ips(obj, name, client.tlp_color)
            indicators.append(create_related_files(obj, name, client.tlp_color))

    indicators += list(domains_map.values())
    return indicators, True


def fetch_indicators_command(client: Client, time_to_stop_fetch: datetime = None):
    """Retrieves indicators from the feed

    Args:
        client: Client object with request
        time_to_stop_fetch: Time to stop the fetch before it falls on the docker timeout

    Returns:
        List. Processed indicator from feed.
    """
    current_date = arg_to_datetime("now").date()  # type:ignore
    while client.first_fetch.date() <= current_date:
        indicators, status = fetch_indicators(client, time_to_stop_fetch)
        if not status:
            return
        for iter_ in batch(indicators, batch_size=2000):
            demisto.createIndicators(iter_)
        # Each request returns one day's indicators, so we'll keep the date of the next day in IntegrationContext.
        next_fetch = dateparser.parse("tomorrow", settings={"RELATIVE_BASE": client.first_fetch})  # type:ignore
        if client.first_fetch.date() < current_date:
            demisto.setIntegrationContext({"last_fetch": next_fetch.isoformat()})  # type:ignore
        client.first_fetch = next_fetch
        demisto.debug(f"{len(indicators)} XSOAR Indicators were created.")
    return


def get_indicators_command(client: Client, args: dict[str, str]) -> CommandResults:
    """Wrapper for retrieving indicators from the feed to the war-room.

    Args:
        client: Client object with request
        args: demisto.args()

    Returns:
        Demisto Outputs.
    """
    limit = int(args.get("limit", 50))
    indicators, status = fetch_indicators(client)

    limit_indicators = indicators[:limit]

    readable_output = tableToMarkdown("CiscoSMA Indicators:", t=limit_indicators, headers=["value", "type"])
    command_results = CommandResults(
        outputs_prefix="CiscoSMA",
        outputs_key_field="value",
        outputs=limit_indicators,
        readable_output=readable_output,
        raw_response=indicators,
    )
    return command_results


def reset_last_run():
    """
    Reset the last run from the integration context
    """
    demisto.setIntegrationContext({})
    return CommandResults(readable_output="Fetch history deleted successfully")


def main():  # pragma: no cover
    """
    PARSE AND VALIDATE FEED PARAMS
    """
    try:
        time_to_stop_fetch = arg_to_datetime(arg="in 25 minutes")  # type:ignore # To stop before docker timeout.
        params = demisto.params()
        args = demisto.args()
        base_url = params["base_url"]
        api_key = params.get("api_key", {}).get("password")
        if not api_key:
            raise DemistoException("API Key was not given. Please insert your API Key.")
        verify = not params.get("insecure", False)
        proxy = params.get("proxy", False)
        feed_name = params.get("feed_name", "")
        if "all" in feed_name:
            feed_name = FEED_NAME
        feed_tags = argToList(params.get("feedTags"))
        tlp_color = params.get("tlp_color")
        create_relationships = params.get("create_relationships", True)
        if fetch_date_string := demisto.getIntegrationContext().get("last_fetch"):
            first_fetch = arg_to_datetime(fetch_date_string)  # type:ignore
        else:
            if not (first_fetch_param := params.get("first_fetch")):
                first_fetch_param = "today"
            first_fetch = arg_to_datetime(arg=first_fetch_param, arg_name="First fetch")  # type:ignore
        command = demisto.command()
        demisto.debug(f"Command being called is: {command}")

        client = Client(
            base_url=base_url,
            api_key=api_key,
            verify=verify,
            proxy=proxy,
            feed_name=feed_name,
            first_fetch=first_fetch,
            feed_tags=feed_tags,
            tlp_color=tlp_color,
            create_relationships=create_relationships,
        )

        if command == "test-module":
            return_results(test_module(client))

        elif command == "fetch-indicators":
            fetch_indicators_command(client, time_to_stop_fetch)

        elif command == "cisco-sma-get-indicators":
            return_results(get_indicators_command(client, args))

        elif command == "cisco-sma-reset-fetch-indicators":
            return_results(reset_last_run())

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

    except Exception as err:
        return_error(f"Failed to execute {demisto.command()} command.\nError:\n{err!s}")


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()