示例#1
0
class TestMitreSoftware(object):
    mitre_attack = MitreAttackConnection()

    def test_software_doesnt_have_mardown_links(self):
        """
        Mocked Domain Generation Algorithms on purpose has added code tags to where they could appear.
        """
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            software = MitreAttackSoftware.get_all(self.mitre_attack)
            dict_reps = [s.dict_form() for s in software]
            # check for every technique's representation that all the field don't have the tag
            assert all([(re.search("\[(.*?)\]\((.*?)\)", s_repr["description"])
                         is None) for s_repr in dict_reps])

    def test_get_all(self):
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            assert len(MitreAttackSoftware.get_all(
                self.mitre_attack)) == len(MitreQueryMocker.SOFTWARE[0]) + len(
                    MitreQueryMocker.SOFTWARE[1]) + len(
                        MitreQueryMocker.SOFTWARE[2])
示例#2
0
class TestMitreUtilMultipleTechniques(object):
    mitre_attack = MitreAttackConnection()

    @pytest.fixture(autouse=True)
    def set_up_mock_for_query(self):
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            yield

    def test_multiple_techniques_works_by_id(self):
        techniques = get_multiple_techniques(
            self.mitre_attack,
            mitre_technique_ids="T1213, T1483",
            mitre_technique_names=None)
        assert len(techniques) == 2

    def test_multiple_techniques_works_by_name(self):
        """
        In mocked data, for these names there's more than one technique.
        """
        techniques = get_multiple_techniques(
            self.mitre_attack,
            mitre_technique_ids=None,
            mitre_technique_names="Port Knocking, Domain Generation Algorithms"
        )
        assert len(techniques) > 2

    def test_ids_precede_names(self):
        """
        Since 2 techniques are returned and not 3, we know that it used ids.
        """
        techniques = get_multiple_techniques(
            self.mitre_attack,
            mitre_technique_ids="T1213, T1483",
            mitre_technique_names="Port Knocking, Domain Generation Algorithms"
        )
        assert len(techniques) == 2

    def test_unknown_ids_fail(self):
        with pytest.raises(ValueError):
            techniques = get_multiple_techniques(
                self.mitre_attack,
                mitre_technique_ids="T1205, T1213, T007",
                mitre_technique_names=None)

    def test_unknown_names_fail(self):
        with pytest.raises(ValueError):
            techniques = get_multiple_techniques(
                self.mitre_attack,
                mitre_technique_ids=None,
                mitre_technique_names="Made up technique")
示例#3
0
def get_tactics_and_techniques(tactic_names=None, tactic_ids=None, opts=None, function_opts=None):
    """
    Get techniques for all input tactics
    :param tactic_names:    string of tactic names separated by comma
    :param tactic_ids:      string of tactic ids separated by comma
    :param opts:            Top level configuration options
    :param function_opts:   Function configuration options.
    :return:                techniques
    """
    mitre_conn = MitreAttackConnection(opts, function_opts)

    tactics = []

    # Check ids first, as it takes priority in querying
    if tactic_ids is not None:
        t_ids = tactic_ids.split(',')

        for tid in t_ids:
            tactics_id = MitreAttackTactic.get_by_id(mitre_conn, tid)
            if tactics_id is not None:
                for tactic in tactics_id:
                    tactics.append(tactic.id)
            else:
                raise ValueError("Tactics with id {} do not exist.".format(tid))
    elif tactic_names is not None:
        # It's possible for multiple tactics to have the same name
        # And we want to make sure that all of them are processed in that case
        tactic_names = tactic_names.split(',')

        for t_name in tactic_names:
            tactics_named = MitreAttackTactic.get_by_name(mitre_conn, t_name)
            if not tactics_named:
                raise ValueError("Tactics with name {} do not exist.".format(t_name))
            else:
                for tactic in tactics_named:
                    tactics.append(tactic.id)

    ret = []
    for tactic_id in tactics:
        t_obj = MitreAttackTactic.get_by_id(mitre_conn, tactic_id)[0]  # since we search by id, its unique

        techs = t_obj.get_techniques(mitre_conn)

        # get the dict for tactic and include techniques into it
        tactic_dict = t_obj.dict_form()
        tactic_dict.update({
            "mitre_techniques": [tech.dict_form() for tech in techs]
        })

        ret.append(tactic_dict)
    return ret
示例#4
0
class TestMitre(object):
    """
    These tests are mostly livetests to confirm that MITRE's schema stays the same
    """
    mitre_conn = MitreAttackConnection()

    @pytest.mark.livetest
    def test_get_all_tactics_from_all_frameworks(self):
        tactics = MitreAttackTactic.get_all(self.mitre_conn)
        # As 8/5/19 there are 40 tactics
        assert len(tactics) >= 40

    @pytest.mark.livetest
    def test_get_tactic_url(self):
        tactics = MitreAttackTactic.get_all(self.mitre_conn)

        for tactic in tactics[:1]:
            url = tactic.get_url()
            assert url_get(url)

    @pytest.mark.livetest
    def test_get_tech_mitigation(self):
        """
        There are some techniques that do not have mitigations.
        We will test few and if at least one of the first 5 has mitigations we're ok,
        otherwise we probably need to check if there's an error.
        """
        techs = MitreAttackTechnique.get_all(self.mitre_conn)
        assert len(techs)
        try:
            count = 0
            for tech in techs:
                id = tech.id
                assert (id)
                mitigation = tech.get_mitigations(self.mitre_conn)

                count += 1

                if len(mitigation):
                    assert MitreAttackMitigation.get_by_name(
                        self.mitre_conn, mitigation[0].name)
                    break

                if count > MAXIMUM_N_TECHNIQUES_WITHOUT_MITIGATION:
                    assert False
        except Exception as e:
            assert (False)

    @pytest.mark.livetest
    def test_get_representative_techniques(self):
        t = MitreAttackTechnique.get(self.mitre_conn,
                                     id="T1453")  # From Mobile collection
        assert t
        assert [x.get_tactic(self.mitre_conn) for x in t]

        t = MitreAttackTechnique.get(self.mitre_conn,
                                     id="T1155")  # From Enterprise
        assert t
        assert [x.get_tactic(self.mitre_conn) for x in t]

        t = MitreAttackTechnique.get(self.mitre_conn,
                                     id="T1245")  # From Pre-Attack
        assert t
        assert [x.get_tactic(self.mitre_conn) for x in t]

    def test_mitre_attack_util(self):
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            tactics = "Impact, Collection"
            techs = get_tactics_and_techniques(tactic_names=tactics)
            assert len(techs) == 3

            tactics = "TA0040, TA0007, TA0009"
            techs = get_tactics_and_techniques(tactic_ids=tactics)
            assert (len(techs) > 0)

    def test_get_tech_info(self):
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            tech = MitreAttackTechnique.get_by_name(self.mitre_conn,
                                                    "Port Knocking")
            assert (tech[0].name == "Port Knocking")

            tech = MitreAttackTechnique.get_by_id(self.mitre_conn, "T1205")
            assert (tech[0].id == "T1205")
示例#5
0
class TestMitreTactic(object):
    mitre_attack = MitreAttackConnection()

    @pytest.fixture(autouse=True)
    def set_up_mock_for_query(self):
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            yield

    def test_get_by_id_works(self):
        assert MitreAttackTactic.get_by_id(self.mitre_attack,
                                           "TA0007") is not None
        assert MitreAttackTactic.get_by_id(self.mitre_attack,
                                           "TA00007") is None

    def test_get_by_name_works(self):
        assert MitreAttackTactic.get_by_name(self.mitre_attack,
                                             "Collection") is not None
        assert MitreAttackTactic.get_by_name(self.mitre_attack,
                                             "Absurd Search") is None

    def test_extra_spaces_doent_fail_search(self):
        assert MitreAttackTactic.get_by_id(self.mitre_attack,
                                           " TA0007") is not None
        assert MitreAttackTactic.get_by_name(self.mitre_attack,
                                             " Collection  ") is not None

    def test_get_all(self):
        assert len(MitreAttackTactic.get_all(
            self.mitre_attack)) == len(MitreQueryMocker.TACTICS[0]) + len(
                MitreQueryMocker.TACTICS[1]) + len(MitreQueryMocker.TACTICS[2])

    def test_collection_name_included(self):
        tactics = MitreAttackTactic.get_by_name(self.mitre_attack, "Impact")
        assert len(tactics) == 2
        assert tactics[0].collection is not None and tactics[
            1].collection is not None
        assert tactics[0].collection != tactics[1].collection

    def test_mutiple_of_same_name_returns_list(self):
        tactics = MitreAttackTactic.get_by_name(self.mitre_attack, "Impact")
        assert isinstance(tactics, list)

    def test_tactic_representation_doesnt_have_unsupported_tags(self):
        """
        Mocked Impact has code tags added on purpose
        """
        tactics = MitreAttackTactic.get_by_name(self.mitre_attack, "Impact")
        dict_reps = [tactic.dict_form() for tactic in tactics]
        # check for every tactic that every field of their representation doesn't container the tag.
        assert all([("<code>" not in tactic_repr[key] for key in tactic_repr)
                    for tactic_repr in dict_reps])

    def test_deprecated_tactic_states_so_in_description(self):
        """
        Gets tactics with name Impact, and checks that deprecation message was added.
        Deprecation flag was added to one of the mocked tactics.
        """
        tactics = MitreAttackTactic.get_by_name(self.mitre_attack, "Impact")
        assert any(x.description.startswith("Deprecated") for x in tactics)

    def test_get_by_shortname_works(self):
        tactics = MitreAttackTactic.get_by_shortname(self.mitre_attack,
                                                     "collection")
        assert tactics
示例#6
0
class TestMitreGroup(object):
    class MockGroupID(object):
        def __init__(self, group_id):
            self.id = group_id

    mitre_attack = MitreAttackConnection()

    def test_groups_done_have_mardown_links(self):
        """
        Test that links are sanitized.
        """
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            groups = MitreAttackGroup.get_all(self.mitre_attack)
            dict_reps = [g.dict_form() for g in groups]
            # check for every technique's representation that all the field don't have the tag
            assert all([
                (re.search("\[(.*?)\]\((.*?)\)", group["description"]) is None)
                for group in dict_reps
            ])

    def test_groups_dont_have_mardown_links(self):
        """
        Mocked Domain Generation Algorithms on purpose has added code tags to where they could appear.
        """
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            software = MitreAttackSoftware.get_all(self.mitre_attack)
            dict_reps = [s.dict_form() for s in software]
            # check for every technique's representation that all the field don't have the tag
            assert all([(re.search("\[(.*?)\]\((.*?)\)", s_repr["description"])
                         is None) for s_repr in dict_reps])

    def test_group_single_intersection_exists(self):
        """
        test_list is a list of lists.
        Each sublist is the groups that use a technique.
        Group with id 42 is in every sublist.
        """
        GROUP = self.MockGroupID
        test_list = [[GROUP(42), GROUP(1),
                      GROUP(2), GROUP(3)],
                     [GROUP(10), GROUP(11),
                      GROUP(12), GROUP(42)],
                     [GROUP(20),
                      GROUP(21),
                      GROUP(22),
                      GROUP(23),
                      GROUP(42)], [GROUP(30),
                                   GROUP(31),
                                   GROUP(32),
                                   GROUP(42)]]
        intersection = MitreAttackGroup.get_intersection_of_groups(test_list)
        assert len(intersection) == 1
        assert 42 in intersection

    def test_group_multiple_intersection_exists(self):
        """
        test_list is a list of lists.
        Each sublist is the groups that use a technique.
        Groupswith id 42 and 123 are in every sublist.
        """
        GROUP = self.MockGroupID
        test_list = [[
            GROUP(42),
            GROUP(1),
            GROUP(2),
            GROUP(3),
            GROUP(123),
            GROUP(122)
        ], [
            GROUP(10),
            GROUP(11),
            GROUP(123),
            GROUP(122),
            GROUP(12),
            GROUP(42)
        ],
                     [
                         GROUP(20),
                         GROUP(21),
                         GROUP(22),
                         GROUP(23),
                         GROUP(42),
                         GROUP(123),
                         GROUP(122)
                     ],
                     [GROUP(123),
                      GROUP(30),
                      GROUP(31),
                      GROUP(32),
                      GROUP(42)]]
        intersection = MitreAttackGroup.get_intersection_of_groups(test_list)
        assert len(intersection) == 2
        assert 42 in intersection
        assert 123 in intersection

    def test_group_no_intersection_exists(self):
        """
        test_list is a list of lists.
        Each sublist is the groups that use a technique.
        There aren't any groups in each of the subsets.
        """
        GROUP = self.MockGroupID
        test_list = [[
            GROUP(42),
            GROUP(1),
            GROUP(2),
            GROUP(3),
            GROUP(123),
            GROUP(122)
        ], [
            GROUP(10),
            GROUP(11),
            GROUP(123),
            GROUP(122),
            GROUP(12),
            GROUP(42)
        ], [GROUP(20),
            GROUP(21),
            GROUP(22),
            GROUP(23),
            GROUP(42),
            GROUP(122)], [GROUP(123),
                          GROUP(30),
                          GROUP(31),
                          GROUP(32)]]
        intersection = MitreAttackGroup.get_intersection_of_groups(test_list)
        assert len(intersection) == 0
示例#7
0
class TestMitreMitigation(object):
    mitre_attack = MitreAttackConnection()

    def test_mitigation_of_tech(self):
        """
        This one isn't mocked, because it would require mocking relationships
        :return:
        """
        mitigations = MitreAttackTechnique.get_by_name(self.mitre_attack, "Port Knocking")[0]\
            .get_mitigations(self.mitre_attack)
        assert mitigations is not None
        assert len(mitigations)

    def test_mitigation_get_all(self):
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            assert len(MitreAttackMitigation.get_all(
                self.mitre_attack)) == len(
                    MitreQueryMocker.MITIGATIONS[0]) + len(
                        MitreQueryMocker.MITIGATIONS[1]) + len(
                            MitreQueryMocker.MITIGATIONS[2])

    def test_mitigation_representation_doesnt_have_unsupported_tags(self):
        """
        Mocked Domain Generation Algorithms on purpose has added code tags to where they could appear.
        """
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            mitigations = MitreAttackMitigation.get_all(self.mitre_attack)
            dict_reps = [mitigation.dict_form() for mitigation in mitigations]
            # check for every technique's representation that all the field don't have the tag
            assert all([("<code>" not in mitigation_repr[key]
                         for key in mitigation_repr)
                        for mitigation_repr in dict_reps])

    def test_mitigation_doesnt_have_mardown_links(self):
        """
        Mocked Domain Generation Algorithms on purpose has added code tags to where they could appear.
        """
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            mitigation = MitreAttackMitigation.get_all(self.mitre_attack)
            dict_reps = [s.dict_form() for s in mitigation]
            # check for every technique's representation that all the field don't have the tag
            assert all([(re.search("\[(.*?)\]\((.*?)\)", s_repr["description"])
                         is None) for s_repr in dict_reps])

    def test_deprecated_mitigation_states_so_in_description(self):
        """
        Gets tactics with name Impact, and checks that deprecation message was added.
        Deprecation flag was added to one of the mocked mitigations.
        """
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            mitigations = MitreAttackMitigation.get_all(self.mitre_attack)
            assert any(
                x.description.startswith("Deprecated") for x in mitigations)
示例#8
0
class TestMitreTechnique(object):
    mitre_attack = MitreAttackConnection()

    @pytest.fixture(autouse=True)
    def set_up_mock_for_query(self):
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            yield

    def test_getting_tactic_from_technique_works(self):
        tech = MitreAttackTechnique.get_by_id(self.mitre_attack, "T1205")[0]
        assert tech.get_tactic(self.mitre_attack) is not None

    def test_tech_of_tactic(self):
        collection_tech = MitreAttackTechnique.get_by_tactic(
            self.mitre_attack,
            MitreAttackTactic.get_by_name(self.mitre_attack, "Collection")[0])
        assert collection_tech is not None
        assert len(collection_tech) > 1

        assert MitreAttackTactic.get_by_name(self.mitre_attack, "Command and Control")[0]\
                   .get_techniques(self.mitre_attack) is not None

    def test_all_searches_returns_list(self):
        techniques = MitreAttackTechnique.get_by_name(self.mitre_attack,
                                                      "Port Knocking")
        assert isinstance(techniques, list)
        assert len(techniques) > 1
        techniques = MitreAttackTechnique.get_by_name(
            self.mitre_attack, "Domain Generation Algorithms")
        assert isinstance(techniques, list)
        assert len(techniques) == 1

    def test_by_id_works(self):
        tech = MitreAttackTechnique.get_by_id(self.mitre_attack, "T1205")
        assert tech is not None
        tech = MitreAttackTechnique.get_by_id(self.mitre_attack, "Made up id")
        assert tech is None

    def test_by_name_works(self):
        tech = MitreAttackTechnique.get_by_name(self.mitre_attack,
                                                "Port Knocking")
        assert tech is not None
        tech = MitreAttackTechnique.get_by_name(self.mitre_attack,
                                                "Absolutely made up name")
        assert tech is None

    def test_tech_get_all(self):
        assert len(MitreAttackTechnique.get_all(
            self.mitre_attack)) == len(MitreQueryMocker.TECHNIQUES[0]) + len(
                MitreQueryMocker.TECHNIQUES[1]) + len(
                    MitreQueryMocker.TECHNIQUES[2])

    def test_collection_name_included(self):
        techniques = MitreAttackTechnique.get_by_name(self.mitre_attack,
                                                      "Port Knocking")
        assert len(techniques) == 2
        assert techniques[0].collection is not None and techniques[
            1].collection is not None
        assert techniques[0].collection != techniques[1].collection

    def test_technique_representation_doesnt_have_unsupported_tags(self):
        """
        Mocked Domain Generation Algorithms on purpose has added code tags to where they could appear.
        """
        techniques = MitreAttackTechnique.get_by_name(
            self.mitre_attack, "Domain Generation Algorithms")
        dict_reps = [technique.dict_form() for technique in techniques]
        # check for every technique's representation that all the field don't have the tag
        assert all([("<code>" not in technique_repr[key]
                     for key in technique_repr)
                    for technique_repr in dict_reps])

    def test_deprecated_technique_states_so_in_description(self):
        """
        Gets tactics with name Impact, and checks that deprecation message was added.
        Deprecation flag was added to one of the mocked techniques.
        """
        techniques = MitreAttackTechnique.get_by_name(
            self.mitre_attack, "Domain Generation Algorithms")
        assert any(x.description.startswith("Deprecated") for x in techniques)
class TestMitre(object):
    mitre_conn = MitreAttackConnection()

    @pytest.mark.livetest
    def test_get_all_tactics_from_all_frameworks(self):
        tactics = MitreAttackTactic.get_all(self.mitre_conn)
        # As 8/5/19 there are 40 tactics
        assert len(tactics) >= 40

    @pytest.mark.livetest
    def test_get_tactic_url(self):
        tactics = MitreAttackTactic.get_all(self.mitre_conn)

        for tactic in tactics[:1]:
            url = tactic.get_url()
            assert url_get(url)

    @pytest.mark.livetest
    def test_get_tech_mitigation(self):
        techs = MitreAttackTechnique.get_all(self.mitre_conn)
        assert len(techs)
        try:
            #
            #   There are more than 200 techs. Try first 5 only
            #
            count = 0
            for tech in techs:
                id = tech.id
                assert (id)
                mitigation = tech.get_mitigations(self.mitre_conn)
                assert mitigation
                count += 1
                if count > 2:
                    break
                # Test getting mitigation using name
                mitigation = tech.get_mitigations(self.mitre_conn)
                assert mitigation
        except Exception as e:
            assert (False)

    def test_mitre_attack_util(self):
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            tactics = "Impact, Collection"
            techs = get_tactics_and_techniques(tactic_names=tactics)
            assert len(techs) == 3

            tactics = "TA0040, TA0007, TA0009"
            techs = get_tactics_and_techniques(tactic_ids=tactics)
            assert (len(techs) > 0)

    def test_get_tech_info(self):
        data_mocker = MitreQueryMocker()
        with patch(
                "fn_mitre_integration.lib.mitre_attack.TAXIICollectionSource.query",
                data_mocker.query):
            tech = MitreAttackTechnique.get_by_name(self.mitre_conn,
                                                    "Port Knocking")
            assert (tech[0].name == "Port Knocking")

            tech = MitreAttackTechnique.get_by_id(self.mitre_conn, "T1205")
            assert (tech[0].id == "T1205")