AzureFeed

Azure.CloudIPs Feed Integration.

Data Enrichment & Threat Intelligence · Azure Feed · Feed

Details

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

README

Azure.CloudIPs Feed Integration.

Configure AzureFeed in Cortex

Parameter Description Required
feed Fetch indicators False
feedReputation Indicator Reputation False
feedReliability Source Reliability True
tlp_color Traffic Light Protocol Color False
feedExpirationPolicy   False
feedExpirationInterval   False
feedFetchInterval Feed Fetch Interval False
feedBypassExclusionList Bypass exclusion list False
Enrichment Excluded Select this option to exclude the fetched indicators from the enrichment process. False
regions Regions True
services Services True
feedTags Tags False
insecure Trust any certificate (not secure) False
proxy Use system proxy settings False
polling_timeout Request Timeout 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.

azure-get-indicators


Gets indicators from the feed.

Base Command

azure-get-indicators

Input

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

Context Output

There is no context output for this command.

Command Example

!azure-get-indicators

Human Readable Output

Indicators from Azure Feed

value type
20.37.158.0/23 CIDR
20.37.194.0/24 CIDR
20.39.13.0/26 CIDR

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
  • enrichmentExcluded — Enrichment Excluded
  • regions — Regions (required)
  • services — Services (required)
  • feedTags — Tags
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • polling_timeout — Request Timeout

Commands (1)

  • azure-get-indicators

    Gets indicators from the feed.

import pytest
from pytest_mock import MockerFixture
from FeedAzure import AZUREJSON_URL, Client, fetch_indicators_command


@pytest.mark.parametrize("regions_list, services_list", [(["All"], ["All"])])
def test_download_link_fetching(mocker, regions_list, services_list):
    with open("./test_data/response_mock.txt") as f:
        response = f.read()
        client = Client(regions_list, services_list)

        mocker.patch("CommonServerPython.BaseClient._http_request", return_value=response)
        assert (
            client.get_azure_download_link() == "https://download.microsoft.com/download"
            "/7/1/D/71D86715-5596-4529-9B13-DA13A5DE5B63/"
            "ServiceTags_Public_20200504.json"
        )


BUILD_IP_PACK = [
    (
        ["All"],
        ["All"],
        "19.117.63.126",
        "global",
        "some service",
        {
            "value": "19.117.63.126",
            "type": "IP",
            "region": "global",
            "service": "some service",
        },
    ),
    (
        ["All"],
        ["All"],
        "FE80::0202:B3FF:FE1E:8329",
        "global",
        "some service",
        {
            "value": "FE80::0202:B3FF:FE1E:8329",
            "type": "IPv6",
            "region": "global",
            "service": "some service",
        },
    ),
    (["All"], ["All"], "8.8.8/10", "global", "some service", {}),
]


@pytest.mark.parametrize("regions_list, services_list, ip, region, service, expected_result", BUILD_IP_PACK)
def test_build_ip(regions_list, services_list, ip, region, service, expected_result):
    client = Client(regions_list, services_list)
    assert client.build_ip_indicator(ip, region=region, service=service) == expected_result


EXTRACT_METADATA_PACK = [
    (
        ["All"],
        ["All"],
        {
            "name": "AzureAD.Suffix",
            "id": "AzureAD.Suffix",
            "properties": {
                "changeNumber": 0,
                "region": "",
                "platform": "Azure",
                "systemService": "AzureAD",
                "addressPrefixes": ["9.9.9.9"],
            },
        },
        {
            "id": "AzureAD.Suffix",
            "name": "AzureAD.Suffix",
            "region": "",
            "platform": "Azure",
            "system_service": "AzureAD",
            "address_prefixes": ["9.9.9.9"],
        },
    ),
    (
        ["All"],
        ["All"],
        {
            "name": "AzureAD.Suffix",
            "id": "AzureAD.Suffix",
            "properties": {
                "changeNumber": 0,
                "region": "",
                "platform": "Azure",
                "systemService": "",
                "addressPrefixes": ["9.9.9.9"],
            },
        },
        {
            "id": "AzureAD.Suffix",
            "name": "AzureAD.Suffix",
            "region": "",
            "platform": "Azure",
            "system_service": "AzureAD",
            "address_prefixes": ["9.9.9.9"],
        },
    ),
    (["All"], ["All"], {"name": "test-name-2", "id": "test-id-2", "region": "ME"}, {}),
    (["All"], ["All"], {"name": "test-name", "id": "test-id", "properties": {}}, {}),
]


@pytest.mark.parametrize(
    "regions_list, services_list, values_group_section, expected_result",
    EXTRACT_METADATA_PACK,
)
def test_extract_metadata(regions_list, services_list, values_group_section, expected_result):
    client = Client(regions_list, services_list)
    assert client.extract_metadata_of_indicators_group(values_group_section) == expected_result


EXTRACT_INDICATORS_PACK = [
    (
        ["All"],
        ["All"],
        [
            {
                "name": "test-name",
                "id": "test-id",
                "properties": {
                    "changeNumber": 0,
                    "region": "",
                    "platform": "Azure",
                    "systemService": "AzureAD",
                    "addressPrefixes": ["9.9.9.9", "5.5.5.5"],
                },
            }
        ],
        [
            {
                "value": "9.9.9.9",
                "type": "IP",
                "azure_id": "test-id",
                "azure_name": "test-name",
                "azure_region": "",
                "azure_platform": "Azure",
                "azure_system_service": "AzureAD",
            },
            {
                "value": "5.5.5.5",
                "type": "IP",
                "azure_id": "test-id",
                "azure_name": "test-name",
                "azure_region": "",
                "azure_platform": "Azure",
                "azure_system_service": "AzureAD",
            },
        ],
    ),
    (
        [],
        ["All"],
        [
            {
                "name": "test-name",
                "id": "test-id",
                "properties": {
                    "changeNumber": 0,
                    "region": "",
                    "platform": "Azure",
                    "systemService": "AzureAD",
                    "addressPrefixes": ["9.9.9.9", "5.5.5.5"],
                },
            }
        ],
        [],
    ),
    (
        ["All"],
        [],
        [
            {
                "name": "test-name",
                "id": "test-id",
                "properties": {
                    "changeNumber": 0,
                    "region": "",
                    "platform": "Azure",
                    "systemService": "AzureAD",
                    "addressPrefixes": ["9.9.9.9", "5.5.5.5"],
                },
            }
        ],
        [],
    ),
    (
        ["NW"],
        ["AD"],
        [
            {
                "name": "test-name",
                "id": "test-id",
                "properties": {
                    "changeNumber": 0,
                    "region": "",
                    "platform": "Azure",
                    "systemService": "AzureAD",
                    "addressPrefixes": ["9.9.9.9", "5.5.5.5"],
                },
            }
        ],
        [],
    ),
    (
        ["All"],
        ["All"],
        [],
        [],
    ),
    (
        ["All"],
        ["All"],
        None,
        [],
    ),
]


@pytest.mark.parametrize(
    "regions_list, services_list, values_group_section, expected_result",
    EXTRACT_INDICATORS_PACK,
)
def test_extract_indicators(regions_list, services_list, values_group_section, expected_result):
    client = Client(regions_list, services_list)
    assert client.extract_indicators_from_values_dict(values_group_section) == expected_result


indicator_objects = [
    (
        [
            {"value": 1},
            {"value": 1, "some_key": 2, "another_key": 3},
            {"value": 2, "some_key": 2},
        ],
        [{"value": 1, "some_key": 2, "another_key": 3}, {"value": 2, "some_key": 2}],
    ),
    (
        [
            {"value": 1, "another_key": 3},
            {"value": 1, "some_key": 2},
            {"value": 2, "some_key": 2},
        ],
        [{"value": 1, "another_key": 3, "some_key": 2}, {"value": 2, "some_key": 2}],
    ),
    (
        [
            {"value": 2},
            {"value": 1, "some_key": 2},
            {"value": 2, "some_key": 2},
            {"value": 1},
        ],
        [{"value": 2, "some_key": 2}, {"value": 1, "some_key": 2}],
    ),
    (
        [{"value": 1, "some_key": 2}, {"value": 2, "some_key": 2}],
        [{"value": 1, "some_key": 2}, {"value": 2, "some_key": 2}],
    ),
]


@pytest.mark.parametrize("list_to_filter, expected_result", indicator_objects)
def test_filter_duplicate_addresses(list_to_filter, expected_result):
    """
    Given:
        - A list of objects, where some of the objects has the same value. (The 4 cases are just different permutations
        and ordering).
    When:
        - Removing duplicate objects from the given list.
    Then:
        - Ensure the resulted list contains the object with the maximal number of keys for each value.
    """
    client = Client([], [])
    assert expected_result == client.filter_and_aggregate_values(list_to_filter)


@pytest.mark.parametrize("enrichment_excluded", [True, False])
def test_fetch_indicators_command(requests_mock, enrichment_excluded):
    """
    Given:
        Parameters (regions_list, services_list, enrichment_excluded) for fetching indicators
    When:
        Calling fetch_indicators_command
    Then:
        The indicators will be returned as expected, with enrichmentExcluded if requested
    """
    url = "https://download.microsoft.com/download/7/1/D/71D86715-5596-4529-9B13-DA13A5DE5B63/ServiceTags_Public_20240819.json"
    downloadData = """
        downloadData={
            "base_0":{
                "url":"https://download.microsoft.com/download/7/1/D/71D86715-5596-4529-9B13-DA13A5DE5B63/ServiceTags_Public_20240819.json",
                "id":"56519",
                "oldid":"3a1b5c65-0f86-41d9-b2fe-24708260c0f1"
            }
        }
    """
    mock_json = {
        "changeNumber": 320,
        "cloud": "Public",
        "values": [
            {
                "name": "AzureAdvancedThreatProtection",
                "id": "AzureAdvancedThreatProtection",
                "properties": {
                    "changeNumber": 24,
                    "region": "",
                    "regionId": 0,
                    "platform": "Azure",
                    "systemService": "AzureAdvancedThreatProtection",
                    "addressPrefixes": [
                        "192.168.0.1/29",
                        "10.0.0.1/29",
                    ],
                    "networkFeatures": ["API", "NSG", "UDR", "FW"],
                },
            }
        ],
    }
    expected = [
        {
            "value": "192.168.0.1/29",
            "type": "CIDR",
            "fields": {
                "region": "",
                "service": "AzureAdvancedThreatProtection",
                "tags": ["test"],
                "trafficlightprotocol": "test_color",
            },
            "rawJSON": {
                "value": "192.168.0.1/29",
                "type": "CIDR",
                "azure_name": "AzureAdvancedThreatProtection",
                "azure_id": "AzureAdvancedThreatProtection",
                "azure_region": "",
                "azure_platform": "Azure",
                "azure_system_service": "AzureAdvancedThreatProtection",
            },
        },
        {
            "value": "10.0.0.1/29",
            "type": "CIDR",
            "fields": {
                "region": "",
                "service": "AzureAdvancedThreatProtection",
                "tags": ["test"],
                "trafficlightprotocol": "test_color",
            },
            "rawJSON": {
                "value": "10.0.0.1/29",
                "type": "CIDR",
                "azure_name": "AzureAdvancedThreatProtection",
                "azure_id": "AzureAdvancedThreatProtection",
                "azure_region": "",
                "azure_platform": "Azure",
                "azure_system_service": "AzureAdvancedThreatProtection",
            },
        },
    ]
    if enrichment_excluded:
        for ind in expected:
            ind["enrichmentExcluded"] = True
    regions_list = ["All"]
    services_list = ["All"]
    requests_mock.get(AZUREJSON_URL, text=f"{downloadData=}")
    requests_mock.get(url, json=mock_json)
    client = Client(regions_list, services_list)
    indicators, _ = fetch_indicators_command(
        client,
        feedTags=["test"],
        tlp_color="test_color",
        enrichment_excluded=enrichment_excluded,
    )
    assert indicators == expected


def test_download_link_regex(mocker):
    """
    Given:
        - A mock response from the endpoint.
    When:
        - call the get_azure_download_link method.
    Then:
        - Ensure the link is valid.
    """
    client = Client(["All"], ["All"])
    with open("./test_data/response_mock_test_regex.txt") as f:
        response = f.read()
    mocker.patch("CommonServerPython.BaseClient._http_request", return_value=response)
    assert (
        client.get_azure_download_link() == "https://download.microsoft.com/download"
        "/7/1/D/71D86715-5596-4529-9B13-DA13A5DE5B63/"
        "ServiceTags_Public_20200504.json"
    )


def test_get_azure_download_link_from_cache(mocker: MockerFixture):
    """
    Given:
        - The request for the Azure HTML page returns an error.
    When:
        - The get_azure_download_link method is called.
    Then:
        - Ensure the link is loaded from the integration context.
    """
    mocker.patch("FeedAzure.load_azure_download_link", return_value="cached_link")

    class MockerFixture:
        def _http_request(*args, **kwargs):
            raise Exception

    res = Client.get_azure_download_link(MockerFixture)

    assert res == "cached_link"