VirusTotal Livehunt Feed

Use this feed integration to fetch VirusTotal Livehunt notifications as indicators.

Data Enrichment & Threat Intelligence · VirusTotal · Feed

Details

IDVirusTotal Livehunt Feed
ProviderGoogle
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

Use the VirusTotal Livehunt Feed integration to fetch indicators from Livehunt rules or rulesets.

Configure VirusTotal Livehunt Feed in Cortex

Parameter Description Required
feed The fetch indicators. False
api_key API Key. True
filter Exact name of the rule or ruleset you want to filter on. Leave empty to receive all. False
feedReputation The indicator reputation. False
feedReliability The source’s reliability. True
tlp_color The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed. More information about the protocol can be found at https://us-cert.cisa.gov/tlp False
feedExpirationPolicy The feed’s expiration policy. False
feedFetchInterval The feed fetch interval. False
feedBypassExclusionList Whether to bypass exclusion list. False

Livehunt Feed info

By default the Livehunt feed retrieve indicators based on all active rulesets in livehunt, you have the option to get indicators only from one rule or ruleset using the filter parameter.

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.

Get Indicators


Gets the indicators from VirusTotal Livehunt.

Base Command

vt-livehunt-get-indicators

Input
Argument Name Description Required
limit The maximum number of indicators to return. The default value is 10 and max 40. Optional
filter Exact name of the rule or ruleset you want to filter on. Optional
Context Output

There is no context output for this command.

Command Example

!vt-livehunt-get-indicators limit=1 filter=WannaCry_Ransomware

Human Readable Output

Indicators from VirusTotal Livehunt

Sha256 Detections Filetype Rulesetname Rulename
f221425286c9073cbb2168f73120b6… 59/69 Win32 EXE Wannacry Ransomware WannaCry_Ransomware_Gen

Demo Video

vt-reset-fetch-indicators


This command will reset your fetch history.

Base Command

vt-reset-fetch-indicators

Input

There are no input arguments for this command.

Context Output

There is no context output for this command.

Configuration parameters

  • credentials — API Key (leave empty. Fill in the API key in the password field.) (required)
  • filter — Filter
  • limit — Limit
  • feed — Fetch indicators
  • feedReputation — Indicator Reputation
  • feedReliability — Source Reliability (required)
  • feedExpirationPolicy
  • feedExpirationInterval
  • feedFetchInterval — Feed Fetch Interval
  • feedBypassExclusionList — Bypass exclusion list
  • feedTags — Tags
  • tlp_color — Traffic Light Protocol Color

Commands (2)

  • vt-livehunt-get-indicators

    Gets the indicators from VirusTotal Livehunt.

  • vt-reset-fetch-indicators

    This command will reset your fetch history.

from datetime import datetime

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

# Disable insecure warnings
urllib3.disable_warnings()


class DetectionRatio:
    malicious = 0
    total = 0

    def __init__(self, last_analysis_stats: dict):
        self.malicious = last_analysis_stats["malicious"]
        self.total = (
            last_analysis_stats["harmless"]
            + last_analysis_stats["suspicious"]
            + last_analysis_stats["undetected"]
            + last_analysis_stats["malicious"]
        )

    def __repr__(self):
        return f"{self.malicious}/{self.total}"


class Client(BaseClient):
    def get_api_indicators(self, query_filter: str = None, limit: int = 10):
        return self._http_request(
            "GET",
            "intelligence/hunting_notification_files",
            params=assign_params(
                filter=query_filter,
                limit=min(limit, 40),
            ),
        )

    def fetch_indicators(self, limit: int = 10, filter_tag: Optional[str] = None, fetch_command: bool = False) -> List:
        """Retrieves all entries from the feed.
        Returns:
            A list of objects, containing the indicators.
        """
        result = []
        query_filter = ""

        if isinstance(filter_tag, str):
            query_filter = f'tag:"{filter_tag}"'

        if fetch_command and (last_run := self.get_last_run()):
            query_filter = f"{query_filter} {last_run}"

        response = self.get_api_indicators(query_filter.strip(), limit)

        try:
            for indicator in response.get("data", []):
                result.append({"data": indicator, "type": "file", "FeedURL": self._base_url})
        except ValueError as err:
            demisto.debug(str(err))
            raise ValueError(f"Could not parse returned data as indicator. \n\nError message: {err}")

        if fetch_command:
            self.set_last_run()

        return result

    @staticmethod
    def set_last_run():
        """
        Returns: Current timestamp
        """
        current_time = datetime.now()
        current_timestamp = datetime.timestamp(current_time)
        timestamp = str(int(current_timestamp))
        demisto.setIntegrationContext({"last_run": timestamp})

    @staticmethod
    def get_last_run() -> str:
        """Gets last run time in timestamp
        Returns:
            last run in timestamp, or '' if no last run
        """
        if last_run := demisto.getIntegrationContext().get("last_run"):
            demisto.info(f"get last_run: {last_run}")
            params = f"date:{last_run}+"
        else:
            params = ""
        return params


def test_module(client: Client, args: dict) -> str:
    try:
        client.fetch_indicators()
    except Exception:
        raise Exception("Could not fetch VT livehunt Feed\n\nCheck your API key and your connection to VirusTotal.")
    return "ok"


def fetch_indicators_command(
    client: Client,
    tlp_color: Optional[str] = None,
    feed_tags: List = [],
    limit: int = 10,
    filter_tag: Optional[str] = None,
    fetch_command: bool = False,
) -> List[Dict]:
    """Retrieves indicators from the feed
    Args:
        client (Client): Client object with request
        tlp_color (str): Traffic Light Protocol color
        feed_tags (list): tags to assign fetched indicators
        limit (int): limit the results
        filter_tag (string): filter response by ruleset name
    Returns:
        Indicators.
    """
    indicators = []

    raw_indicators = client.fetch_indicators(limit, filter_tag, fetch_command=fetch_command)

    # extract values from iterator
    for item in raw_indicators:
        value_ = item.get("data")
        type_ = FeedIndicatorType.File
        attributes = value_.get("attributes", {})
        context_attributes = value_.get("context_attributes", {})
        raw_data = {
            "value": value_,
            "type": type_,
        }

        detection_ratio = DetectionRatio(attributes.get("last_analysis_stats"))

        # Create indicator object for each value.
        # The object consists of a dictionary with required and optional keys
        # and values, as described blow.
        indicator_obj = {
            # The indicator value.
            "value": attributes["sha256"],
            # The indicator type as defined in Cortex XSOAR.
            # One can use the FeedIndicatorType class under CommonServerPython
            # to populate this field.
            "type": type_,
            # The name of the service supplying this feed.
            "service": "VirusTotal",
            # A dictionary that maps values to existing indicator fields defined
            # in Cortex XSOAR.
            # One can use this section in order to map custom indicator fields
            # previously defined
            # in Cortex XSOAR to their values.
            "fields": {
                "md5": attributes.get("md5"),
                "sha1": attributes.get("sha1"),
                "sha256": attributes.get("sha256"),
                "ssdeep": attributes.get("ssdeep"),
                "fileextension": attributes.get("type_extension"),
                "filetype": attributes.get("type_tag"),
                "imphash": attributes.get("pe_info", {}).get("imphash"),
                "firstseenbysource": attributes.get("first_submission_date"),
                "lastseenbysource": attributes.get("last_submission_date"),
                "creationdate": attributes.get("creation_date"),
                "updateddate": attributes.get("last_modification_date"),
                "detectionengines": detection_ratio.total,
                "positivedetections": detection_ratio.malicious,
                "displayname": attributes.get("meaningful_name"),
                "name": attributes.get("meaningful_name"),
                "size": attributes.get("size"),
            },
            # A dictionary of the raw data returned from the feed source about
            # the indicator.
            "rawJSON": raw_data,
            "sha256": attributes["sha256"],
            "detections": str(detection_ratio),
            "fileType": attributes.get("type_description"),
            "rulesetName": context_attributes.get("ruleset_name"),
            "ruleName": context_attributes.get("rule_name"),
        }

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

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

        indicators.append(indicator_obj)

    return indicators


def get_indicators_command(client: Client, params: Dict[str, str], 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.
    """
    limit = int(args.get("limit", 10))
    filter_tag = args.get("filter")
    tlp_color = params.get("tlp_color")
    feed_tags = argToList(params.get("feedTags", ""))
    indicators = fetch_indicators_command(client, tlp_color, feed_tags, limit, filter_tag)

    human_readable = tableToMarkdown(
        "Indicators from VirusTotal Livehunt Feed:",
        indicators,
        headers=["sha256", "detections", "fileType", "rulesetName", "ruleName"],
        headerTransform=string_to_table_header,
        removeNull=True,
    )

    return CommandResults(
        readable_output=human_readable,
        outputs_prefix="",
        outputs_key_field="",
        raw_response=indicators,
        outputs={},
    )


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


def main():
    """
    main function, parses params and runs command functions
    """

    params = demisto.params()
    feed_tags = argToList(params.get("feedTags"))
    tlp_color = params.get("tlp_color")
    limit = int(params.get("limit", 10))
    filter_tag = params.get("filter")

    # If your Client class inherits from BaseClient, SSL verification is
    # handled out of the box by it, just pass ``verify_certificate`` to
    # the Client constructor
    insecure = not params.get("insecure", False)

    # If your Client class inherits from BaseClient, system proxy is handled
    # out of the box by it, just pass ``proxy`` to the Client constructor
    proxy = params.get("proxy", False)

    command = demisto.command()

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

    try:
        client = Client(
            base_url="https://www.virustotal.com/api/v3/",
            verify=insecure,
            proxy=proxy,
            headers={
                "x-apikey": params["credentials"]["password"],
                "x-tool": "CortexVirusTotalLivehuntFeed",
            },
        )

        if command == "test-module":
            # This is the call made when pressing the integration Test button.
            return_results(test_module(client, {}))

        elif command == "vt-livehunt-get-indicators":
            # This is the command that fetches a limited number of indicators
            # from the feed source and displays them in the war room.
            return_results(get_indicators_command(client, params, demisto.args()))

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

        elif command == "fetch-indicators":
            # This is the command that initiates a request to the feed endpoint
            # and create new indicators objects from the data fetched. If the
            # integration instance is configured to fetch indicators, then this
            # is the command that will be executed at the specified feed fetch
            # interval.
            indicators = fetch_indicators_command(client, tlp_color, feed_tags, limit, filter_tag, fetch_command=True)
            for iter_ in batch(indicators, batch_size=2000):
                demisto.createIndicators(iter_)

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

    # Log exceptions and return errors
    except Exception as e:
        demisto.error(traceback.format_exc())  # Print the traceback
        return_error(f"Failed to execute {command} command.\nError:\n{e!s}")


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