MITRE ATT&CK v2
Use the MITRE ATT&CK® feed to fetch MITRE’s Adversarial Tactics, Techniques, and Common Knowledge (ATT&CK®) content. MITRE ATT&CK is a globally-accessible knowledge base of adversary tactics and techniques based on real-world observations. The ATT&CK knowledge base is used as a foundation for the development of specific threat models and methodologies in the private sector, in government, and in the cybersecurity product and service community.
Data Enrichment & Threat Intelligence · MITRE ATT&CK · Feed
Details
| ID | MITRE ATT&CK v2 |
|---|---|
| Provider | MITRE Corporation |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 5.5.0 |
| Docker Image | demisto/taxii2:1.0.0.7704170 |
| Supported Modules | Agentix XSIAM EDR Cortex Cloud Cloud Runtime Security Attack Surface Management Cloud Posture Security Exposure Management |
README
Use the MITRE ATT&CK Feed integration to fetch indicators from MITRE ATT&CK.
For more information click here.
Note: When upgrading from v1 (MITRE IDs Feed) to v2 (MITRE ATT&CK) - disabling the MITRE IDs Feed indicator type, and instance are important for the smooth flow of the upgrade.
Configure MITRE ATT&CK Feed in Cortex
| Parameter | Description | Required |
|---|---|---|
| includeAPT | This option will also create indicators using APT / actor name references if they are part of a MITRE Intrusion Set | False |
| feedReputation | The indicator reputation (defaults to ‘None’). | 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 |
| feedExpirationInterval | The interval after which the feed expires. | False |
| feedFetchInterval | The feed fetch interval. | False |
| feedBypassExclusionList | Whether to bypass exclusion list. | False |
| insecure | Whether to trust any certificate (not secure). | False |
| proxy | Whether to use the system proxy settings. | False |
| Create relationships | Create relationships between indicators as part of Enrichment. | False |
Feed timeouts
MITRE enforce a rate limit for connecting to their taxii server. Ensure that your fetch interval is reasonable, otherwise you will receive connection errors.
Commands
You can execute these commands from the XSOAR 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 MITRE ATT&CK.
Note: This command does not create indicators within Cortex XSOAR.
Base Command
mitre-get-indicators
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of indicators to return. The default value is 10. | Optional |
| raw | Enabling raw will also output the raw content of each indicator | Optional |
Context Output
The context is output as:
- MITRE (dict)
- ATT&CK (list)
Each item in the “ATT&CK” list contains the following keys:
- fields (any fields that the indicator will attempt to map into the indicator)
- rawJSON (the raw JSON of the indicator)
- score (the indicator score)
- type (the type of indicator - will always be “MITRE ATT&CK”)
- value (the indicator value, for example “T1134”)
Command Example
!mitre-get-indicators limit=2
Human Readable Output
MITRE ATT&CK Indicators
| Value | Score | Type |
|---|---|---|
| T1531 | 0 | MITRE ATT&CK |
| T1506 | 0 | MITRE ATT&CK |
| Argument Name | Description | Required |
|---|---|---|
| indicator | Indicator to lookup | Required |
Context Output
The context is output as:
- DBotScore
- MITRE (dict)
- ATT&CK (list)
Each item in the “ATT&CK” list contains the customFields that are mapped into the indicator (each beginning with ‘mitre’)
MITRE Show Feeds
Displays the available feeds from the MITRE taxii service.
Base Command
mitre-show-feeds
Input
There are no inputs
Context Output
There is no context output
Command Example
!mitre-showfeeds
Human Readable Output
MITRE ATT&CK Feeds
| Name | ID |
|---|---|
| Enterprise ATT&CK | 95ecc380-afe9-11e4-9b6c-751b66dd541e |
| PRE-ATT&CK | 062767bd-02d2-4b72-84ba-56caef0f8658 |
| Mobile ATT&CK | 2f669986-b40b-4423-b720-4396ca6a462b |
MITRE Get Indicator Name
Gets the Attack Pattern value from the Attack Pattern ID in the Enterprise collection only.
Base Command
mitre-get-indicator-name
Input
| Argument Name | Description | Required |
|---|---|---|
| attack_ids | The Attack Pattern IDs list | True |
Context Output
| Path | Type | Description |
|---|---|---|
| MITREATTACK.id | String | MITRE ATTACK Attack Pattern ID. |
| MITREATTACK.value | String | MITRE ATTACK Attack Pattern value. |
Command Example
!mitre-get-indicator-name attack_id=T1111
Human Readable Output
MITRE ATTACK Attack Patterns values
| Attack ID | Attack Value |
|---|---|
| T1111 | Some Attack Value |
attack-pattern
Looks up the reputation of the indicator in the Enterprise collection only.
Base Command
attack-pattern
Input
| Argument Name | Description | Required |
|---|---|---|
| attack_pattern | Indicator to look up. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| DBotScore.Indicator | string | The indicator that was tested. |
| DBotScore.Score | number | The actual score. |
| DBotScore.Type | string | The indicator type. |
| DBotScore.Vendor | string | The vendor used to calculate the score. |
| AttackPattern.STIXID | string | The STIX ID of the Attack Pattern. |
| AttackPattern.KillChainPhases | string | The kill chain phases of the Attack Pattern. |
| AttackPattern.FirstSeenBySource | string | The first seen by source of the Attack Pattern. |
| AttackPattern.Description | string | The description of the Attack Pattern. |
| AttackPattern.OperatingSystemRefs | string | The operating system references of the Attack Pattern. |
| AttackPattern.Publications | string | The publications of the Attack Pattern. |
| AttackPattern.MITREID | string | The MITRE ID of the Attack Pattern. |
| AttackPattern.Tags | string | The tags of the Attack Pattern. |
Command Example
!attack-pattern attack_pattern="Search Threat Vendor Data"
Human Readable Output
MITRE ATTACK
Name: Search Threat Vendor Data - ID: T1681
Threat actors may seek information/indicators from closed or open threat intelligence sources gathered about their own campaigns, as well as those conducted by other adversaries that may align with their target industries, capabilities/objectives, or other operational concerns. These reports may include descriptions of behavior, detailed breakdowns of attacks, atomic indicators such as malware hashes or IP addresses, timelines of a group’s activity, and more. Adversaries may change their behavior when planning their future operations.
Adversaries have been observed replacing atomic indicators mentioned in blog posts in under a week. Adversaries have also been seen searching for their own domain names in threat vendor data and then taking them down, likely to avoid seizure or further investigation.
This technique is distinct from Threat Intel Vendors in that it describes threat actors performing reconnaissance on their own activity, not in search of victim information.
Troubleshooting
Rate-Limiting or IP Blocking Issues
Problem: You may encounter a “Too Many Requests” error for the URL https://attack-taxii.mitre.org/taxii2/ when accessing the MITRE ATT&CK API, because the MITRE ATT&CK API enforces rate limits and may block requests based on the IP address. This often occurs when multiple users or systems are making requests from the same IP address.
Solution: To resolve this issue, it is recommended to use a dedicated engine for your MITRE ATT&CK Feed integration. This will provide a unique IP address for the integration instance, preventing it from being blocked due to shared usage. Additionally, ensure that your fetch interval is set to a reasonable value to avoid exceeding the rate limits.
Configuration parameters
feed— Fetch indicatorsfeedReputation— Indicator ReputationfeedReliability— Source Reliabilitytlp_color— Traffic Light Protocol ColorfeedExpirationPolicy—feedExpirationInterval—feedFetchInterval— Feed Fetch IntervalfeedTags— Tagscreate_relationships— Create relationshipsswitch_intrusion_set_to_threat_actor— Save intrusion sets as threat actor indicator typesfeedBypassExclusionList— Bypass exclusion listproxy— Use system proxy settingsinsecure— Trust any certificate (not secure)
Commands (4)
-
attack-patternLooks up the reputation of the indicator in the Enterprise collection only.
-
mitre-get-indicator-nameGets the Attack Pattern value from the Attack Pattern ID in the Enterprise collection only.
-
mitre-get-indicatorsRetrieves a limited number of indicators.
-
mitre-show-feedsShows the feed names and IDs from TAXII.
import json import demistomock as demisto # noqa: F401 import pytest from stix2 import TAXIICollectionSource, parse from test_data.mitre_test_data import ( ATTACK_PATTERN, ATTACK_PATTERNS, CAMPAIGN, COURSE_OF_ACTION, ID_TO_NAME, INDICATORS_LIST, INTRUSION_SET, MALWARE, MALWARE_LIST_WITH_PREFIX, MALWARE_LIST_WITHOUT_PREFIX, MITRE_ID_TO_MITRE_NAME, NEW_ID_TO_NAME, NEW_INDICATORS_LIST, OLD_ID_TO_NAME, RELATION, RELATIONSHIP_ENTITY, TOOL, ) ENTERPRISE_COLLECTION_ID = " x-mitre-collection–1f5f1533-f617-4ca8-9ab4-6a02367fa019" # noqa: RUF001 NON_ENTERPRISE_COLLECTION_ID = "101010101010101010101010101010101" class MockCollection: def __init__(self, id_, title): self.id = id_ self.title = title def mock_create_relations(original): def mock(item_json, id_to_name): return original(item_json, ID_TO_NAME) return mock @pytest.mark.parametrize( "indicator, expected_result", [ ([ATTACK_PATTERN.get("response")], ATTACK_PATTERN.get("indicator")), ([COURSE_OF_ACTION.get("response")], COURSE_OF_ACTION.get("indicator")), ([INTRUSION_SET.get("response")], INTRUSION_SET.get("indicator")), ([MALWARE.get("response")], MALWARE.get("indicator")), ([TOOL.get("response")], TOOL.get("indicator")), ], ) def test_fetch_indicators(mocker, indicator, expected_result): """ Given - fetch incidents command - command args - command raw response When - mock the Client's get_stix_objects. Then - run the fetch incidents command using the Client Validate that all the indicators extracted successfully """ import FeedMitreAttackv2 as fm from FeedMitreAttackv2 import Client, create_relationship client = Client(url="https://test.org", proxies=False, verify=False, tags=[], tlp_color=None) client.tactic_name_to_mitre_id = { "Defense Evasion": "TA0005", "Privilege Escalation": "TA0004", "Resource Development": "TA0042", } default_id = ENTERPRISE_COLLECTION_ID nondefault_id = 2 client.collections = [MockCollection(default_id, "enterprise att&ck"), MockCollection(nondefault_id, "not_default")] mocker.patch.object(client, "initialise") mocker.patch.object(TAXIICollectionSource, "__init__", return_value=None) mocker.patch.object(TAXIICollectionSource, "query", return_value=indicator) # mocker.patch.object(json, 'loads', return_value=indicator[0]) mocker.patch.object(fm, "create_relationship", wraps=mock_create_relations(create_relationship)) indicators = client.build_iterator(create_relationships=True, limit=7) assert indicators == expected_result default_id = NON_ENTERPRISE_COLLECTION_ID nondefault_id = 2 client.collections = [MockCollection(default_id, "default"), MockCollection(nondefault_id, "not_default")] mocker.patch.object(client, "initialise") mocker.patch.object(TAXIICollectionSource, "__init__", return_value=None) mocker.patch.object(TAXIICollectionSource, "query", return_value=indicator) mocker.patch.object(json, "loads", return_value=indicator[0]) mocker.patch.object(fm, "create_relationship", wraps=mock_create_relations(create_relationship)) indicators = client.build_iterator(create_relationships=True, limit=7) assert indicators == ([], [], {}, {}) @pytest.mark.parametrize( "field_name, field_value, expected_result", [ ("created", "2017-05-31T21:31:43.540Z", "2017-05-31T21:31:43.540Z"), ("created", "2019-04-25T20:53:07.719Z\n2019-04-25T20:53:07.814Z", "2019-04-25T20:53:07.719Z"), ("modified", "2017-05-31T21:31:43.540Z", "2017-05-31T21:31:43.540Z"), ("modified", "2020-03-16T15:38:37.650Z\n2020-01-17T16:45:24.252Z", "2020-03-16T15:38:37.650Z"), ], ) def test_handle_multiple_dates_in_one_field(field_name, field_value, expected_result): """ Given - created / modified indicator field When - this field contains two dates Then - run the handle_multiple_dates_in_one_field Validate The field contain one specific date. """ from FeedMitreAttackv2 import handle_multiple_dates_in_one_field assert handle_multiple_dates_in_one_field(field_name, field_value) == expected_result @pytest.mark.parametrize( "indicator, expected_result", [({"x_mitre_deprecated": True}, True), ({"revoked": True}, True), ({}, False)] ) def test_is_indicator_deprecated_or_revoked(indicator, expected_result): """ Given - indicator in STIX format. When - we cheed Then - run the create_list_relationships Validate The relationships list extracted successfully. """ from FeedMitreAttackv2 import is_indicator_deprecated_or_revoked assert is_indicator_deprecated_or_revoked(indicator) == expected_result @pytest.mark.parametrize( "indicator_type, indicator_json, expected_result", [ ("Attack Pattern", ATTACK_PATTERN.get("response"), ATTACK_PATTERN.get("map_result")), ("Course of Action", COURSE_OF_ACTION.get("response"), COURSE_OF_ACTION.get("map_result")), ("Intrusion Set", INTRUSION_SET.get("response"), INTRUSION_SET.get("map_result")), ("Malware", MALWARE.get("response"), MALWARE.get("map_result")), ("Tool", TOOL.get("response"), TOOL.get("map_result")), ("Campaign", CAMPAIGN.get("response"), CAMPAIGN.get("map_result")), ], ) def test_map_fields_by_type(indicator_type, indicator_json, expected_result): from FeedMitreAttackv2 import map_fields_by_type assert map_fields_by_type(indicator_type, indicator_json) == expected_result def test_create_relationship(): """ Given - relationship obj in STIX format. When - we extract this relationship to Demisto format Then - run the create_relationship Validate The relationship extracted successfully. """ from FeedMitreAttackv2 import create_relationship relation = create_relationship(RELATION.get("response"), ID_TO_NAME) relation._entity_a = "entity a" relation._entity_a_type = "STIX Malware" relation._entity_b = "entity b" relation._entity_b_type = "STIX Attack Pattern" relation._name = "uses" relation._relation_type = "IndicatorToIndicator" relation._reverse_name = "used-by" def test_get_item_type(): from FeedMitreAttackv2 import get_item_type assert get_item_type("malware", True) == "Malware" assert get_item_type("malware", False) == "STIX Malware" assert get_item_type("intrusion-set", True) == "Intrusion Set" assert get_item_type("intrusion-set", False) == "Intrusion Set" def test_create_relationship_list(): from FeedMitreAttackv2 import create_relationship_list assert create_relationship_list([RELATION.get("response")], ID_TO_NAME) == RELATION.get("indicator") def test_add_malware_prefix_to_dup_with_intrusion_set(): from FeedMitreAttackv2 import add_malware_prefix_to_dup_with_intrusion_set malware_list = MALWARE_LIST_WITHOUT_PREFIX add_malware_prefix_to_dup_with_intrusion_set(MALWARE_LIST_WITHOUT_PREFIX, ID_TO_NAME) assert malware_list == MALWARE_LIST_WITH_PREFIX def test_add_obj_to_mitre_id_to_mitre_name(): from FeedMitreAttackv2 import add_obj_to_mitre_id_to_mitre_name mitre_id_to_mitre_name = {} add_obj_to_mitre_id_to_mitre_name(mitre_id_to_mitre_name, ATTACK_PATTERN["response"]) assert mitre_id_to_mitre_name == {"T1047": "ATTACK_PATTERN 1"} def test_add_technique_prefix_to_sub_technique(): from FeedMitreAttackv2 import add_technique_prefix_to_sub_technique indicators = INDICATORS_LIST mitre_id_to_mitre_name = MITRE_ID_TO_MITRE_NAME id_to_name = OLD_ID_TO_NAME add_technique_prefix_to_sub_technique(indicators, id_to_name, mitre_id_to_mitre_name) assert indicators == NEW_INDICATORS_LIST assert id_to_name == NEW_ID_TO_NAME def test_publication_link_not_none(): from FeedMitreAttackv2 import map_fields_by_type indicator = {"created": "2022-01-05T14:27:46.612705Z", "modified": "2022-01-05T14:27:46.612705Z", "external_references": [{}]} res = map_fields_by_type("Malware", indicator) assert res["publications"][0]["link"] is not None def test_create_relationships_invalid(): from FeedMitreAttackv2 import create_relationship item_json = {"source_ref": "", "target_ref": ""} assert create_relationship(item_json, {}) is None def test_create_relationship_with_unknown_relationship_name(): from FeedMitreAttackv2 import create_relationship item_json = {"source_ref--source_ref": "source_ref", "target_ref--target_ref": "target_ref"} output = create_relationship(RELATIONSHIP_ENTITY, item_json) assert output is not None @pytest.mark.parametrize( "attack_id, attack_pattern_obj, expected_result", [ ("T1111", {"external_references": [{"external_id": "T1111"}]}, True), ("T1098", {"external_references": [{"external_id": "T1111"}]}, False), ], ) def test_filter_attack_pattern_object_by_attack_id(attack_id, attack_pattern_obj, expected_result): from FeedMitreAttackv2 import filter_attack_pattern_object_by_attack_id output = filter_attack_pattern_object_by_attack_id(attack_id, attack_pattern_obj) assert output == expected_result @pytest.mark.parametrize( "description, expected_result", [ ("Test (23)", ""), ("Test (2020, Mar)", "2020-03-01T00:00:00"), ("Test (Test) (2020, Mar)", "2020-03-01T00:00:00"), ("Test 2033)", ""), ("Test ()", ""), ("Test (Test)", ""), ("Gross, J. (2016, February 23). Operation Dust Storm. Retrieved December 22, 2021.", "2016-02-23T00:00:00"), ("Cisco. (n.d.). Cisco IOS Software Integrity Assurance - Command History. Retrieved October 21, 2020.", ""), ("Citation: Security Affairs Elderwood Sept 2012)", ""), ("Insikt Group (Recorded Future). (2017, May 17).", "2017-05-17T00:00:00"), ("Insikt Group (Recorded Future). (2017, May17).", "2017-05-17T00:00:00"), ("Insikt Group (Recorded Future). (2017,May17).", "2017-05-17T00:00:00"), ("Insikt Group (Recorded Future). (2017,March17).", "2017-03-17T00:00:00"), ("Insikt Group (Recorded Future). (2017, March 17).", "2017-03-17T00:00:00"), ], ) def test_extract_date_time_from_description(description, expected_result): from FeedMitreAttackv2 import extract_date_time_from_description output = extract_date_time_from_description(description) assert output == expected_result def test_attack_pattern_reputation_command(mocker): """ Given: Some attack patterns to retrieve, with and without sub-technique When: Running attack-pattern reputation command Then: Returns the wanted attack patterns """ from FeedMitreAttackv2 import attack_pattern_reputation_command stix_objs = [parse(stix_obj_dict, allow_custom=True) for stix_obj_dict in ATTACK_PATTERNS] mocker.patch("FeedMitreAttackv2.get_mitre_data_by_filter", return_value=stix_objs) args = {"attack_pattern": "Abuse Elevation Control Mechanism, Active Scanning: Wordlist Scanning"} command_results = attack_pattern_reputation_command("", args) assert command_results[0].indicator.value == "Abuse Elevation Control Mechanism" assert command_results[1].indicator.value == "Active Scanning: Wordlist Scanning" def test_attack_pattern_reputation_without_answer_command(mocker): """ Given: One attach pattern to retrive data on, that is not found in the collection When: Running attack-pattern reputation command Then: Ensures the command_results is not empty and readable_output is as expected """ from FeedMitreAttackv2 import attack_pattern_reputation_command stix_objs = [parse(stix_obj_dict, allow_custom=True) for stix_obj_dict in ATTACK_PATTERNS] mocker.patch("FeedMitreAttackv2.get_mitre_data_by_filter", return_value=stix_objs) args = {"attack_pattern": "dummy attack pattern"} command_results = attack_pattern_reputation_command("", args) assert command_results assert ( command_results.readable_output == "MITRE ATTACK Attack Patterns values: No Attack " "Patterns found for ['dummy attack pattern'] in the Enterprise collection." ) def test_get_mitre_value_from_id_without_answer_command(mocker): """ Given: One attach pattern to retrive data on, that is not found in the collection When: Running attack-pattern reputation command Then: Ensures the command_results is not empty and readable_output is as expected """ from FeedMitreAttackv2 import get_mitre_value_from_id stix_objs = [parse(stix_obj_dict, allow_custom=True) for stix_obj_dict in ATTACK_PATTERNS] mocker.patch("FeedMitreAttackv2.get_mitre_data_by_filter", return_value=stix_objs) args = {"attack_ids": ["dummy attack pattern id"]} command_results = get_mitre_value_from_id("", args) assert command_results assert ( command_results.readable_output == "MITRE ATTACK Attack Patterns values: " "No Attack Patterns found for ['dummy attack pattern id'] in the " "Enterprise collection." ) @pytest.mark.parametrize( "description, expected_result", [ ( "Waterbear is modular malware attributed to BlackTech ...(Citation: Trend Micro Waterbear December 2019)", "Waterbear is modular malware attributed to BlackTech ...", ), ( "Adversaries may employ various means to detect and avoid debuggers.(Citation: ProcessHacker Github)\ (assuming a present debugger would “swallow” or handle the potential error).\ (Citation: hasherezade debug)(Citation: AlKhaser Debug)(Citation: vxunderground debug)\ <code>OutputDebugStringW()</code>.(Citation: wardle evilquest partii)(Citation: Checkpoint Dridex Jan 2021)", "Adversaries may employ various means to detect and avoid debuggers.\ (assuming a present debugger would “swallow” or handle the potential error).\ <code>OutputDebugStringW()</code>.", ), ], ) def test_remove_citations(description, expected_result): """ Given: A description with Citation. When: Calling remove_citation method. Then: Output description will not contain Citation parts. """ from FeedMitreAttackv2 import remove_citations actual_result = remove_citations(description) assert "Citation" not in actual_result assert actual_result == expected_result def test_create_indicator_with_unknown_tactic_name(mocker): """ Given: An Attack Pattern whose kill_chain_phases contains a tactic phase name ('stealth') that is NOT present in the client's tactic_name_to_mitre_id mapping. When: Calling client.create_indicator(). Then: The indicator is created successfully without raising a KeyError. Both relationships are created: the known tactic uses the full "ID - Name" format, and the unknown tactic falls back to using just its name. """ from FeedMitreAttackv2 import Client client = Client(url="https://test.org", proxies=False, verify=False, tags=[], tlp_color=None) # Only known tactics are pre-populated; 'Stealth' is intentionally absent client.tactic_name_to_mitre_id = { "Defense Evasion": "TA0005", } mitre_item_json = { "id": "attack-pattern--test-stealth-1234", "name": "Some Technique", "type": "attack-pattern", "created": "2024-01-01T00:00:00.000Z", "modified": "2024-01-01T00:00:00.000Z", "description": "A technique that uses stealth.", "external_references": [ {"source_name": "mitre-attack", "external_id": "T9999", "url": "https://attack.mitre.org/techniques/T9999"}, ], "kill_chain_phases": [ {"kill_chain_name": "mitre-attack", "phase_name": "defense-evasion"}, {"kill_chain_name": "mitre-attack", "phase_name": "stealth"}, # new unknown tactic ], "x_mitre_platforms": ["Windows"], } mocker.patch("FeedMitreAttackv2.demisto.debug") # Should not raise KeyError indicator = client.create_indicator("Attack Pattern", "Some Technique", mitre_item_json) assert indicator["value"] == "Some Technique" # Both tactics should appear in relationships: # - known tactic uses full "ID - Name" format # - unknown tactic falls back to name-only (no MITRE ID prefix) assert len(indicator["relationships"]) == 2 entity_b_values = {rel["entityB"] for rel in indicator["relationships"]} assert "TA0005 - Defense Evasion" in entity_b_values assert "Stealth" in entity_b_values def test_get_mitre_value_from_id_with_valid_ids(mocker): """ Given: Valid MITRE technique IDs (T1111 and T1111.001) that exist in the collection. When: Running mitre-get-indicator-name command. Then: Returns the correct attack pattern names, including parent: sub-technique format. """ from FeedMitreAttackv2 import get_mitre_value_from_id stix_objs = [parse(stix_obj_dict, allow_custom=True) for stix_obj_dict in ATTACK_PATTERNS] mocker.patch("FeedMitreAttackv2.get_mitre_data_by_filter", return_value=stix_objs) # T1111 is a top-level technique ("Active Scanning") args = {"attack_ids": ["T1111"]} command_results = get_mitre_value_from_id("", args) assert command_results assert command_results.outputs assert command_results.outputs[0]["id"] == "T1111" assert command_results.outputs[0]["value"] == "Active Scanning" def test_get_mitre_value_from_id_sub_technique_with_parent(mocker): """ Given: A valid MITRE sub-technique ID (T1111.001) whose parent (T1111) exists in the collection. When: Running mitre-get-indicator-name command. Then: Returns the attack pattern name in "Parent: Sub-technique" format. """ from FeedMitreAttackv2 import get_mitre_value_from_id stix_objs = [parse(stix_obj_dict, allow_custom=True) for stix_obj_dict in ATTACK_PATTERNS] mocker.patch("FeedMitreAttackv2.get_mitre_data_by_filter", return_value=stix_objs) # T1111.001 is "Wordlist Scanning", parent T1111 is "Active Scanning" args = {"attack_ids": ["T1111.001"]} command_results = get_mitre_value_from_id("", args) assert command_results assert command_results.outputs assert command_results.outputs[0]["id"] == "T1111.001" assert command_results.outputs[0]["value"] == "Active Scanning: Wordlist Scanning" def test_get_mitre_value_from_id_sub_technique_missing_parent(mocker): """ Given: A MITRE sub-technique ID whose parent technique is NOT in the collection. When: Running mitre-get-indicator-name command. Then: Does not raise an IndexError; returns the sub-technique name without parent prefix. """ from FeedMitreAttackv2 import get_mitre_value_from_id # Only include the sub-technique, not the parent sub_technique_only = [ATTACK_PATTERNS[0]] # T1111.001 "Wordlist Scanning", parent T1111 not included stix_objs = [parse(stix_obj_dict, allow_custom=True) for stix_obj_dict in sub_technique_only] mocker.patch("FeedMitreAttackv2.get_mitre_data_by_filter", return_value=stix_objs) args = {"attack_ids": ["T1111.001"]} # Should not raise IndexError command_results = get_mitre_value_from_id("", args) assert command_results assert command_results.outputs assert command_results.outputs[0]["id"] == "T1111.001" # Without parent, name is just the sub-technique name assert command_results.outputs[0]["value"] == "Wordlist Scanning" def test_show_feeds_command(mocker): """ Given: A Client. When: Calling show_feeds_command method. Then: Validate the output extracted successfully. """ from FeedMitreAttackv2 import Client, show_feeds_command client = Client(url="https://test.org", proxies=False, verify=False, tags=[], tlp_color=None) default_id = NON_ENTERPRISE_COLLECTION_ID nondefault_id = 2 client.collections = [MockCollection(default_id, "default"), MockCollection(nondefault_id, "not_default")] mocker.patch.object(demisto, "results") show_feeds_command(client) assert demisto.results.call_count == 1 assert demisto.results.call_args[0][0] == { "Type": 1, "Contents": [{"Name": "default", "ID": "101010101010101010101010101010101"}, {"Name": "not_default", "ID": 2}], "ContentsFormat": "json", "HumanReadable": "### MITRE ATT&CK Feeds:\n|Name|ID|\n|---|---|\n| default |\ 101010101010101010101010101010101 |\n| not_default | 2 |\n", "ReadableContentsFormat": "markdown", }