FireEyeFeed

FireEye Intelligence Feed Integration.

Data Enrichment & Threat Intelligence · FireEye Feed · Feed

Details

IDFireEyeFeed
ProviderGoogle
CategoryData Enrichment & Threat Intelligence
From Version5.5.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Use the FireEye feed integration to fetch indicators from the FireEye Intelligence Feed feed.

Configure FireEye Feed in Cortex


Parameter Description
Name A meaningful name for the integration instance.
Fetch indicators If checked, fetches indicators.
Indicator Reputation The reputation applied to indicators from this integration instance. Default is “Bad”.
Source Reliability The reliability of the source providing the intelligence data. Default is “A - Completely reliable”
Traffic Light Protocol 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.
Indicator Expiration Method The method by which to expire indicators from this feed for this integration instance.
Indicator Expiration Interval How often to expire the indicators from this integration instance (in minutes). This only applies if the feedExpirationPolicy is set to interval.
Feed Fetch Interval How often to fetch indicators from the feed for this integration instance (in minutes). Default is 60.
Public Key + Password The credentials used to access the feed’s data.
Collection(s) to fetch from feed Select which collections to fetch from the feed. Default is “Indicators, Reports”
First Fetch Time First fetch time (<number> <time unit>, e.g., 12 hours, 7 days, 3 months, 1 year).
Malicious Threshold The minimum score returned from the feed to determine whether the indicator is malicious. Default is 70.
Reputation Interval If this amount of days passed since the indicator was created, then its reputation can be at most Suspicious. Default is 30.
Bypass exclusion list Whether 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.

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 from the feed


Gets the feed indicators and reports.

Base Command

fireeye-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.

Command Example

!fireeye-get-indicators limit=10

fireeye-reset-fetch-indicators


WARNING: This command will reset your fetch history.

Base Command

fireeye-reset-fetch-indicators

Input

There are no input arguments for this command.

Context Output

There is no context output for this command.

Command Example

!fireeye-reset-fetch-indicators

Human Readable Output

Fetch was reset successfully. Your next indicator fetch will collect indicators from the configured “First Fetch Time”

Configuration parameters

  • feed — Fetch indicators
  • feedReputation — Indicator Reputation
  • feedReliability — Source Reliability (required)
  • tlp_color — Traffic Light Protocol Color
  • feedExpirationPolicy
  • feedExpirationInterval
  • feedFetchInterval — Feed Fetch Interval
  • feedBypassExclusionList — Bypass exclusion list
  • credentials — Public Key (required)
  • collections_to_fetch — Collection(s) to fetch from feed (required)
  • first_fetch_timestamp — First fetch time (<number> <time unit>, e.g., 12 hours, 7 days, 3 months, 1 year). Leave empty to fetch from the first indicator available.
  • threshold — Malicious Threshold
  • reputation_interval — Reputation Interval
  • feedTags — Tags
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • polling_timeout — Request Timeout

Commands (2)

  • fireeye-get-indicators

    Gets indicators from the feed.

  • fireeye-reset-fetch-indicators

    WARNING: This command will reset your fetch history.

import random

import demistomock as demisto
import pytest
import requests_mock
from FeedFireEye import FE_CONFIDENCE_TO_REPUTATION, Client, STIX21Processor, handle_first_fetch_timestamp, parse_timestamp
from freezegun import freeze_time


def create_client(
    public_key: str = "public_key",
    private_key: str = "secret_key",
    threshold: int = 70,
    reputation_interval: int = 30,
    polling_timeout: int = 20,
    insecure: bool = False,
    proxy: bool = False,
    tags: list = [],
    tlp_color: str | None = "AMBER",
):
    return Client(public_key, private_key, threshold, reputation_interval, polling_timeout, insecure, proxy)


def test_get_access_token_with_valid_token_in_context():
    """

    Given:
        - Entry context with a valid authentication token

    When:
        - Getting authentication token

    Then:
        - Returns the auth token from context

    """
    demisto.setIntegrationContext({"auth_token": "Token", "expiration_time": 11740347200})

    client = create_client()
    assert client.get_access_token() == "Token"


def test_get_access_token_with_invalid_token_in_context(mocker):
    """

    Given:
        - Entry context with an invalid authentication token

    When:
        - Getting authentication token

    Then:
        - Returns a new fetched auth token

    """
    mocker.patch.object(Client, "fetch_new_access_token", return_value="New Access Token")
    demisto.setIntegrationContext({"auth_token": "Token", "expiration_time": 740347200})

    client = create_client()
    assert client.get_access_token() == "New Access Token"


@freeze_time("1993-06-17 11:00:00 GMT")
def test_parse_access_token_expiration_time():
    """

    Given:
        - Authentication token validity period

    When:
        - Fetching new authentication token

    Then:
        - Returns the expiration time of the newly fetched token

    """
    for _i in range(5):
        random_value = random.randint(0, 1000)
        # 740314800 is the epoch converted time of 1993-06-17 11:00:00
        assert Client.parse_access_token_expiration_time(random_value) - 740314800 == random_value


FETCH_INDICATORS_PACKAGE = [
    (
        "https://api.intelligence.fireeye.com/collections/indicators/objects?length=1000",
        200,
        {
            "objects": [
                {"type": "indicator"},
                {"type": "relationship", "id": "relationship1"},
                {"type": "malware", "id": "malware1"},
                {"type": "indicator"},
            ]
        },
        (
            [{"type": "indicator"}, {"type": "indicator"}],
            {"relationship1": {"type": "relationship", "id": "relationship1"}},
            {"malware1": {"type": "malware", "id": "malware1"}},
            None,
        ),
    ),
    ("https://api.intelligence.fireeye.com/collections/indicators/objects?length=1000", 204, {}, ([], {}, {}, None)),
    ("https://api.intelligence.fireeye.com/collections/indicators/objects?length=1000", 202, {}, ([], {}, {}, None)),
]


@pytest.mark.parametrize("url, status_code, json_data, expected_result", FETCH_INDICATORS_PACKAGE)
def test_fetch_indicators_from_api(mocker, url, status_code, json_data, expected_result):
    """

    Given:
        - Response status code
        - Response data

    When:
        - Fetching indicators from API

    Then:
        - Returns the processed tuple of raw indicators, entities and relationships

    """
    with requests_mock.Mocker() as m:
        mocker.patch.object(Client, "fetch_new_access_token", return_value="New Access Token")
        mocker.patch.object(demisto, "info")
        mocker.patch.object(demisto, "debug")

        m.get(url, status_code=status_code, json=json_data)
        client = create_client()

        if status_code in [200, 204]:
            fetch_result = client.fetch_all_indicators_from_api(-1)

            for i in range(4):
                assert fetch_result[i] == expected_result[i]

            if status_code == 204:
                assert (
                    demisto.info.call_args[0][0]
                    == "FireEye Feed info - API Status Code: 204 No Content Available for this timeframe."
                )

        else:
            with pytest.raises(SystemExit) as e:
                # return_error reached
                client.fetch_all_indicators_from_api(-1)

            if not e:
                pytest.fail()


FETCH_REPORTS_PACKAGE = [
    (
        "https://api.intelligence.fireeye.com/collections/reports/objects?length=100",
        200,
        {
            "objects": [
                {"type": "report", "id": "report1"},
                {"type": "report", "id": "report2"},
            ]
        },
        ([{"type": "report", "id": "report1"}, {"type": "report", "id": "report2"}], None),
    ),
    ("https://api.intelligence.fireeye.com/collections/reports/objects?length=100", 204, {}, ([], None)),
]


@pytest.mark.parametrize("url, status_code, json_data, expected_result", FETCH_REPORTS_PACKAGE)
def test_fetch_reports_from_api(mocker, url, status_code, json_data, expected_result):
    """

    Given:
        - Response status code
        - Response data

    When:
        - Fetching reports from API

    Then:
        - Returns the processed list of raw reports

    """
    with requests_mock.Mocker() as m:
        mocker.patch.object(Client, "fetch_new_access_token", return_value="New Access Token")
        mocker.patch.object(demisto, "debug")

        m.get(url, status_code=status_code, json=json_data)
        client = create_client()

        if status_code == 200:
            fetch_result = client.fetch_all_reports_from_api(-1)
            assert fetch_result == expected_result

        else:
            with pytest.raises(SystemExit) as e:
                # return_error reached
                client.fetch_all_reports_from_api(-1)

            if not e:
                pytest.fail()


PROCESS_INDICATOR_VALUE_PACKAGE = [
    (
        "[file:hashes.MD5='1234' OR file:hashes.'SHA-1'='12345' OR file:hashes.'SHA-256'='123456']",
        (["file"], ["1234"], {"MD5": "1234", "SHA-1": "12345", "SHA-256": "123456"}),
    ),
    (
        "[file:hashes.'SHA-1'='12345' OR file:hashes.'SHA-256'='123456']",
        (["file"], ["12345"], {"SHA-1": "12345", "SHA-256": "123456"}),
    ),
    (
        "[file:hashes.'ssdeep'='12345' OR file:hashes.'SHA-256'='123456']",
        (["file"], ["123456"], {"ssdeep": "12345", "SHA-256": "123456"}),
    ),
    ("[file:'fake'='12345' OR file:hashes.'SHA-1'='123456']", (["file"], ["123456"], {"SHA-1": "123456"})),
    ("[domain-name:value='1234.com']", (["domain-name"], ["1234.com"], {})),
    (
        "[domain-name:value='1234.com' AND url:value='www.abc.1245.com']",
        (["domain-name", "url"], ["1234.com", "www.abc.1245.com"], {}),
    ),
]


@pytest.mark.parametrize("pattern_value, expected_result", PROCESS_INDICATOR_VALUE_PACKAGE)
def test_process_indicator_value(pattern_value, expected_result):
    """

    Given:
        - Indicator raw value from response

    When:
        - Processing raw indicators to real indicators

    Then:
        - Returns extracted value and hashes

    """
    process_result = STIX21Processor.process_indicator_value(pattern_value)

    for i in range(3):
        assert process_result[i] == expected_result[i]


REPUTATION_CALCULATION_PACKAGE = [
    (100, "1993-05-27T17:43:41.000Z", 70, 30, 3),
    (100, "1992-05-27T17:43:41.000Z", 0, 30, 2),
    (100, "1993-04-27T17:43:41.000Z", 0, 100, 3),
    (51, "1993-04-27T17:43:41.000Z", 50, 100, 3),
    (1, "1993-04-27T17:43:41.000Z", 50, 100, 0),
    (100, "1993-04-27T17:43:41.000Z", 50, 20, 2),
]


@pytest.mark.parametrize("confidence, date, threshold, reputation_interval, expected", REPUTATION_CALCULATION_PACKAGE)
@freeze_time("1993-06-17 11:00:00 GMT")
def test_reputation_calculation(confidence, date, threshold, reputation_interval, expected):
    """

    Given:
        - Confidence level according to FE
        - Indicator publish date

    When:
        - Processing raw indicators to real indicators

    Then:
        - Returns DBot Score

    """
    FE_CONFIDENCE_TO_REPUTATION[3] = threshold
    assert STIX21Processor.calculate_indicator_reputation(confidence, date, reputation_interval) == expected


def test_parse_timestamp():
    """

    Given:
        - Next URL value from FE response

    When:
        - Saving the last timestamp fetched to context

    Then:
        - Returns decoded timestamp

    """
    assert (
        parse_timestamp(
            "https://api.intelligence.fireeye.com/collections/indicators/objects?length=1000&"
            "last_id_modified_timestamp=MTU4MDgwOTIxOTcyODY0NixpbmRpY2F0b3ItLTA5MWI3OWQxLTllOWQtNWExYS04ODMzLTZlNTkyZmNj"
            "MmM1NQ%3D%3D&added_after=1580764458"
        )
        == 1580809219
    )


@pytest.mark.parametrize(
    "param_input, expected_result",
    [
        ("1 month", "737636400"),
        ("2 months", "735044400"),
        ("1 day", "740228400"),
        ("3 weeks", "738500400"),
        ("", None),
        (None, None),
    ],
)
@freeze_time("1993-06-17 11:00:00 GMT")
def test_handle_first_fetch_timestamp(mocker, param_input, expected_result):
    """

    Given:
        - first_fetch_timestamp parameter from user input

    When:
        - Calculating the first fetch timestamp value

    Then:
        - str value of the required time, or None if empty

    """
    mocker.patch.object(demisto, "params", return_value={"first_fetch_timestamp": param_input})
    assert handle_first_fetch_timestamp() == expected_result