TAXIIFeed
Ingests indicator feeds from TAXII 1.x servers.
Data Enrichment & Threat Intelligence · TAXII Feed · Feed
Details
| ID | TAXIIFeed |
|---|---|
| Provider | Open Source |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 5.5.0 |
| Docker Image | demisto/taxii:1.0.0.10133006 |
| Supported Modules | Agentix XSIAM |
README
The TAXII Feed integration ingests indicator feeds from TAXII 1.x servers.
Configure TAXIIFeed on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for TAXIIFeed.
- Click Add instance to create and configure a new integration instance.
- Name: a textual name for the integration instance.
- Fetch indicators: boolean flag. If set to true will fetch indicators.
- Fetch Interval: Interval of the fetches.
- Reliability: Reliability of the feed.
- 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
- Trust any certificate (not secure)
- Use system proxy settings
- Discovery Service: TAXII discovery service endpoint. For example:
http://example.com/taxii-discovery-service - Collection: Collection name to fetch indicators from.
- Subscription ID: Subscription ID for the TAXII consumer.
- Username: Username/Password (if required)
- Request Timeout: Time (in seconds) before HTTP requests timeout.
- Poll Service: Used by a TAXII Client to request information from a TAXII Server.
- API Key: API key used for authentication with the TAXII server.
- API Header Name: API key header to be used to provide API key to the TAXII server. For example, “Authorization”.
- First Fetch Time: The time interval for the first fetch (retroactive). [number] [time unit] of type minute/hour/day. For example, 1 minute, 12 hours, 7 days.
- Click Test to validate the URLs, token, and connection.
Step by step configuration
As an example, we’ll use the public TAXII threat intelligence feed by Abuse_ch accessible via Hail a TAXII. These are the feed instance configuration parameters for our example.
Indicator Reputation - Because this is just an example, we can leave the default value. Ordinarily you would set the reputation based on the specific feed’s information about what type of indicators they are returning, i.e., whether they are good or bad.
Source Reliability - Because this is just an example, we can leave the default value. Ordinarily you would set the reliability according to your level of trust in this feed.
Indicator Expiration Method - For this example, we can leave the default value here. Ordinarily you would set the value according to the type of feed you were fetching from. As an example, let’s that you are a customer of a Cloud Services provider and you want to add the URLs from which that provider serves up many of the services you use to your network firewall exclusion list. Assuming that that same Cloud Services provider maintains an up-to-date feed of the URLs from which they currently provide service, you would probably want to configure a feed integration instance with this parameter set to Expire indicators when they disappear from feed so that you don’t continue to mark a given URL with a Good reputation after it is no longer being used by your Cloud Services provider.
Feed Fetch Interval - For this example, we can leave the default value here.
Discovery Service - Enter http://example.com/taxii-discovery-service.
Collection - Enter guest.Abuse_ch.
Subscription ID - No need to enter a value here for this example since the TAXII server we are addressing does not require it so we’ll leave it blank.
Username - Enter guest.
Password - Enter guest.
Request Timeout - Let’s increase the number to 80 seconds since the request may take a while to complete.
Poll Service - We don’t have to enter a value here for this example because the poll service will be determined dynamically in the integration code if it is not explicitly provided.
API Key - We don’t have to enter a value here for this example because the TAXII server we are addressing doesn’t require an API key.
API Header Name - We don’t have to enter a value here for this example because the TAXII server we are addressing doesn’t require an API header name.
First Fetch Time - Since this example feed isn’t very high volume, let’s enter 500 days to make sure we fetch a sufficient number of indicators.
Click the Test button and ensure that a green Success message is returned.
Now we have successfully configured an instance for the TAXII threat intelligence feed by Abuse_ch accessible via Hail a TAXII, once we enable Fetches indicators the instance will start pulling indicators.
By clicking Mapping in the integration instance, we can map indicator data returned by the feed to actual indicator fields in Cortex XSOAR.
We can use Set up a new classification rule using actual data from the feed.
Get indicators
Gets indicators from the the feed.
Base Command
get-indicators
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of results to return. | Optional |
| initial_interval | The time interval for the first fetch (retroactive). <number> <time unit> of type minute/hour/day. For example, 1 minute, 12 hours, 7 days. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| TAXII.Indicator.Value | String | The indicator value. |
| TAXII.Indicator.Type | String | The indicator type. |
| TAXII.Indicator.Title | String | The observable title. |
| TAXII.Indicator.Description | String | The observable description. |
| TAXII.Indicator.Stixindicatordescription | String | The indicator description. |
| TAXII.Indicator.Stixindicatorname | String | The indicator title. |
| TAXII.Indicator.Stixttptitle | String | The ttp title. |
| TAXII.Indicator.Stixmalwaretypes | String | The stix malware type. |
| TAXII.Indicator.Confidence | String | The indicator confidence. |
| TAXII.Indicator.Score | String | The indicator DBot score. |
| TAXII.Indicator.Relationships | String | The indicator relationships. |
| TAXII.Indicator.Fields | Unknown | The indicator fields. |
| TAXII.Indicator.Rawjson | Unknown | The indicator rawJSON value. |
Command Example
!get-indicators limit=1 initial_interval="1 day"
Context Example
{
"TAXII": {
"Indicator": [
{
"Confidence": "High",
"Description": "URL: https://example.com| isOnline:yes| dateVerified:2021-11-06T21:53:09+00:00",
"Fields": {},
"Rawjson": {
"TLP": "WHITE",
"confidence": "High",
"indicator": "https://example.com",
"indicator_ref": "opensource:Observable-9fe6464a-4a53-4269-90c6-d81013b2073e",
"relationships": [
{
"indicator": "URL embedded in Email",
"stix_ttp_title": "Email Emmbedded URL",
"ttp_description": "Target Users via Email by adding a malicious URL",
"type": "Attack Pattern",
"value": "URL embedded in Email"
}
],
"share_level": "white",
"stix_description": "URL: https://example.com| isOnline:yes| dateVerified:2021-11-06T21:53:09+00:00",
"stix_indicator_description": "This URL:[https://example.com] was identified by phishtank.com as part of a phishing email. This URL appears to still be online as of 2021-11-06T21:53:09+00:00. More detailed infomation can be found at http://www.phishtank.com/phish_detail.php?phish_id=7341640",
"stix_indicator_name": "phishTank.com id:7341640 with malicious URL:https://example.com...",
"stix_title": "URL: https://example.com...",
"ttp_ref": [
"opensource:ttp-c819f3ef-fbc3-4077-8d56-bf619c8d9b29"
],
"type": "URL",
"value": "https://example.com"
},
"Relationships": [
{
"entityA": "https://example.com",
"entityAFamily": "Indicator",
"entityAType": "URL",
"entityB": "URL embedded in Email",
"entityBFamily": "Indicator",
"entityBType": "Attack Pattern",
"fields": {},
"name": "related-to",
"reverseName": "related-to",
"type": "IndicatorToIndicator"
}
],
"Stixindicatordescription": "This URL:[https://example.com] was identified by phishtank.com as part of a phishing email. This URL appears to still be online as of 2021-11-06T21:53:09+00:00. More detailed infomation can be found at http://www.phishtank.com/phish_detail.php?phish_id=7341640",
"Stixindicatorname": "phishTank.com id:7341640 with malicious URL:https://example.com...",
"Title": "URL: https://example.com...",
"Type": "URL",
"Value": "https://example.com"
}
]
}
}
Human Readable Output
Indicators
Value Type Rawjson https://example.com URL indicator: https://example.com
type: URL
indicator_ref: opensource:Observable-9fe6464a-4a53-4269-90c6-d81013b2073e
stix_title: URL: https://example.com…
stix_description: URL: https://example.com| isOnline:yes| dateVerified:2021-11-06T21:53:09+00:00
share_level: white
TLP: WHITE
stix_indicator_name: phishTank.com id:7341640 with malicious URL:https://example.com…
stix_indicator_description: This URL:[https://example.com] was identified by phishtank.com as part of a phishing email. This URL appears to still be online as of 2021-11-06T21:53:09+00:00. More detailed infomation can be found at http://www.phishtank.com/phish_detail.php?phish_id=7341640
confidence: High
ttp_ref: opensource:ttp-c819f3ef-fbc3-4077-8d56-bf619c8d9b29
relationships: {‘stix_ttp_title’: ‘Email Emmbedded URL’, ‘ttp_description’: ‘Target Users via Email by adding a malicious URL’, ‘type’: ‘Attack Pattern’, ‘indicator’: ‘URL embedded in Email’, ‘value’: ‘URL embedded in Email’}
value: https://example.com
Configuration parameters
feed— Fetch indicatorsfeedReputation— Indicator ReputationfeedIncremental— Incremental feedfeedReliability— Source Reliability (required)tlp_color— Traffic Light Protocol ColorfeedExpirationPolicy—feedExpirationInterval—feedFetchInterval— Feed Fetch IntervalfeedBypassExclusionList— Bypass exclusion listdiscovery_service— Discovery Service (required)collection— Collectionsubscription_id— Subscription IDcredentials— Name (To use the API key click the "?" icon)creds_certificate— Certificate File as Textcert_text— Certificate File as Textkey_text— Key File as Textpolling_timeout— Request Timeoutpoll_service— Poll Serviceinitial_interval— First Fetch TimefeedTags— Tagsinsecure— Trust any certificate (not secure)proxy— Use system proxy settingsenrichmentExcluded— Enrichment Excluded
Commands (1)
-
get-indicatorsGets indicators from the the feed.
import json import pytest import demistomock as demisto from FeedTAXII import TAXIIClient, fetch_indicators_command, Taxii11 """ helper functions """ def get_files_in_dir(mypath, only_with_ext=None): from os import listdir from os.path import isfile, join files_list = [f for f in listdir(mypath) if isfile(join(mypath, f))] if only_with_ext: return [f for f in files_list if f.endswith(only_with_ext)] return files_list class TestStixDecode: FILE_PATH = "test_data/StixDecodeTest" def test_decode(self): """Test decode on all files""" from FeedTAXII import StixDecode xml_files_names = get_files_in_dir(self.FILE_PATH, "xml") for xml_f_name in xml_files_names: file_path = f"{self.FILE_PATH}/{xml_f_name}" with open(file_path) as xml_f: stix_str = xml_f.read() res = StixDecode.decode(stix_str) res_path = f'{file_path.rstrip(".xml")}-result.json' with open(res_path) as res_f: expected_res = json.load(res_f) assert expected_res == list(res[1]) class TestUtilFunctions: multipliers = { "minute": 60, "hour": 3600, "day": 86400, } def test_interval_in_sec_1(self): """Empty""" from FeedTAXII import interval_in_sec assert interval_in_sec(None) is None def test_interval_in_sec_2(self): """Integer""" from FeedTAXII import interval_in_sec val = 25 assert interval_in_sec(val) == val def test_interval_in_sec_3(self): """Str with len < 2""" from FeedTAXII import interval_in_sec val = "25" with pytest.raises(ValueError): interval_in_sec(val) def test_interval_in_sec_4(self): """Str with len > 2""" from FeedTAXII import interval_in_sec val = "25 minutes ok" with pytest.raises(ValueError): interval_in_sec(val) def test_interval_in_sec_5(self): """Invalid str with len == 2""" from FeedTAXII import interval_in_sec val = "25 minu" with pytest.raises(ValueError): interval_in_sec(val) def test_interval_in_sec_6(self): """Valid str""" from FeedTAXII import interval_in_sec # Minutes val = "25 minutes" assert interval_in_sec(val) == 25 * self.multipliers["minute"] # Hours val = "30 hours" assert interval_in_sec(val) == 30 * self.multipliers["hour"] # Days val = "40 hours" assert interval_in_sec(val) == 40 * self.multipliers["hour"] class TestCommands: def test_fetch_indicators(self, mocker): client = TAXIIClient(collection="a collection") with open("test_data/raw_indicators.json") as f: raw_indicators = json.load(f) mocker.patch.object(client, "build_iterator", return_value=raw_indicators) res = fetch_indicators_command(client) with open("test_data/indicators_results.json") as exp_f: expected = json.load(exp_f) assert res == expected def test_poll_collection(mocker): """ Given: - A collection of indicators in STIX format where there are more than one indicator for some blocks. When: - fetch_indicators_command is running. Then: - Validate the indicator extract as expected. """ import requests_mock from FeedTAXII import fetch_indicators_command client = TAXIIClient(collection="a collection", poll_service="http://example/taxii-data") with open("test_data/collection_example.xml", "rb") as xml_f: stix_content = xml_f.read() with requests_mock.Mocker() as m: m.post("http://example/taxii-data", content=stix_content) res = fetch_indicators_command(client) with open("test_data/indicators_example.json") as json_f: expected_result = json.load(json_f) assert res == expected_result @pytest.mark.parametrize("tags", (["title", "description"], [])) def test_tags_parameter(mocker, tags): """ Given: - tags parameters When: - Executing any command on feed Then: - Validate the tags supplied exists in the indicators """ client = TAXIIClient(collection="a collection", feedTags=json.dumps(tags)) with open("test_data/raw_indicators.json") as f: raw_indicators = json.load(f) mocker.patch.object(client, "build_iterator", return_value=raw_indicators) res = fetch_indicators_command(client) assert tags == list(res[0]["fields"].keys()) def test_client_headers(): """ Given: - TAXII1 client When: - Getting the client headers Then: - Validate the headers contain the Accept header """ client = Taxii11() headers = client.headers() assert headers["Accept"] == "application/xml" assert headers["X-TAXII-Content-Type"] == client.MESSAGE_BINDING assert headers["X-TAXII-Accept"] == client.MESSAGE_BINDING assert headers["X-TAXII-Services"] == client.SERVICES assert headers["X-TAXII-Protocol"] == "urn:taxii.mitre.org:protocol:http:1.0" headers = client.headers(protocol="https") assert headers["X-TAXII-Protocol"] == "urn:taxii.mitre.org:protocol:https:1.0" def test_fetch_enrichment_excluded(mocker): """ Given: - A TAXII client with the enrichmentExcluded parameter set to True. When: - Calling the fetch_indicators command Then: - The indicators returned should have enrichmentExcluded set to True. """ client = TAXIIClient(collection="a collection", enrichmentExcluded=True) with open("test_data/raw_indicators.json") as f: raw_indicators = json.load(f) mocker.patch.object(client, "build_iterator", return_value=raw_indicators) res = fetch_indicators_command(client) with open("test_data/indicators_results.json") as exp_f: expected = json.load(exp_f) for ind in expected: ind["enrichmentExcluded"] = True assert res == expected def test_client_enrichment_excluded_with_tlp_red(mocker): """ Given: integration params with enrichment excluded set to False and tlp_color set to RED When: creating client Then: validate the enrichment_excluded is set to True """ from FeedTAXII import TAXIIClient mocker.patch("FeedTAXII.is_xsiam_or_xsoar_saas", return_value=True) client = TAXIIClient(collection="test", enrichmentExcluded=False, tlp_color="RED") assert client.enrichment_excluded is True def test_decoding_domain(): """ Given: domain indicator type without a protocol When: decoding the indicator Then: validate return of the indicator """ from bs4 import BeautifulSoup from FeedTAXII import DomainNameObject xml = '<DomainName type="FQDN"><Value>www.a.com</Value></DomainName>' soup = BeautifulSoup(xml, "xml") props = soup.find("DomainName") indicator = DomainNameObject.decode(props)[0] assert indicator.get("indicator") == "www.a.com" assert indicator.get("type") == "Domain" def test_decoding_url(): """ Given: domain indicator type with a protocol When: decoding the indicator Then: validate return of the indicator """ from bs4 import BeautifulSoup from FeedTAXII import URIObject xml = '<URI type="Domain Name"><Value>https://www.a.com</Value></URI>' soup = BeautifulSoup(xml, "xml") props = soup.find("URI") indicator = URIObject.decode(props)[0] assert indicator.get("indicator") == "www.a.com" assert indicator.get("type") == "Domain" def test_poll_collection_uses_safe_xml_parser_settings(mocker): """ Given: - A TAXIIClient that polls a collection. When: - The _poll_collection method invokes etree.iterparse. Then: - Verify that safe XML parser settings are used: resolve_entities=False, load_dtd=False, no_network=True. """ from datetime import datetime, UTC mock_iterparse = mocker.patch("FeedTAXII.etree.iterparse", return_value=iter([])) mocker.patch.object(demisto, "getLastRun", return_value={}) mock_response = mocker.MagicMock() mock_response.raw = mocker.MagicMock() mock_response.raw.decode_content = True client = TAXIIClient( poll_service="https://test.com/poll", collection="test_collection", credentials={"identifier": "user", "password": "pass"}, cert_text=None, key_text=None, insecure=True, ) mocker.patch.object(client, "_send_request", return_value=mock_response) begin = datetime(2024, 1, 1, tzinfo=UTC) end = datetime(2024, 1, 2, tzinfo=UTC) # _poll_collection is a generator; exhaust it to trigger iterparse call list(client._poll_collection("https://test.com/poll", begin, end)) mock_iterparse.assert_called_once() call_kwargs = mock_iterparse.call_args.kwargs assert call_kwargs.get("resolve_entities") is False, "resolve_entities should be False" assert call_kwargs.get("load_dtd") is False, "load_dtd should be False" assert call_kwargs.get("no_network") is True, "no_network should be True"