コード例 #1
0
ファイル: mitre.py プロジェクト: 0x706972686f/PyMITRE
def retrieve_collection(collection_id):
    # Initialize dictionary to hold Enterprise ATT&CK content
    attack = {}

    # Establish TAXII2 Collection instance for Enterprise ATT&CK collection
    collection_url = STIX_URL + "/stix/collections/{}/".format(collection_id)
    collection = taxii2client.Collection(collection_url,
                                         verify=False)  #,proxies=PROXIES)

    # Supply the collection to TAXIICollection
    tc_source = stix2.TAXIICollectionSource(collection)

    # Create filters to retrieve content from Enterprise ATT&CK based on type
    taxii_filters = {
        "techniques": stix2.Filter("type", "=", "attack-pattern"),
        "mitigations": stix2.Filter("type", "=", "course-of-action"),
        "groups": stix2.Filter("type", "=", "intrusion-set"),
        "malware": stix2.Filter("type", "=", "malware"),
        "tools": stix2.Filter("type", "=", "tool"),
        "relationships": stix2.Filter("type", "=", "relationship"),
        "tactic": stix2.Filter("type", "=", "x-mitre-tactic"),
        "matrix": stix2.Filter("type", "=", "x-mitre-matrix")
    }

    # Retrieve all Enterprise ATT&CK content
    for field in taxii_filters:
        attack[field] = tc_source.query(taxii_filters[field])

    return attack
コード例 #2
0
def test_add_get_remove_filter(collection):
    ds = stix2.TAXIICollectionSource(collection)

    # First 3 filters are valid, remaining properties are erroneous in some way
    valid_filters = [
        Filter('type', '=', 'malware'),
        Filter('id', '!=', 'stix object id'),
        Filter('labels', 'in', ["heartbleed", "malicious-activity"]),
    ]

    assert len(ds.filters) == 0

    ds.filters.add(valid_filters[0])
    assert len(ds.filters) == 1

    # Addin the same filter again will have no effect since `filters` acts
    # like a set
    ds.filters.add(valid_filters[0])
    assert len(ds.filters) == 1

    ds.filters.add(valid_filters[1])
    assert len(ds.filters) == 2

    ds.filters.add(valid_filters[2])
    assert len(ds.filters) == 3

    assert valid_filters == [f for f in ds.filters]

    # remove
    ds.filters.remove(valid_filters[0])

    assert len(ds.filters) == 2

    ds.filters.add(valid_filters)
コード例 #3
0
def test_get_object_found(collection):
    tc_source = stix2.TAXIICollectionSource(collection)
    result = tc_source.query([
        stix2.Filter("id", "=",
                     "indicator--00000000-0000-4000-8000-000000000001"),
    ])
    assert result
コード例 #4
0
def test_can_read_error(collection_no_rw_access):
    """create a TAXIICOllectionSource with a taxii2client.Collection
    instance that does not have read access, check ValueError exception is raised"""

    with pytest.raises(DataSourceError) as excinfo:
        stix2.TAXIICollectionSource(collection_no_rw_access)
    assert "Collection object provided does not have read access" in str(excinfo.value)
コード例 #5
0
def main():
    collection = Collection(
        "http://127.0.0.1:5000/trustgroup1/collections/52892447-4d7e-4f70-b94d-d7f22742ff63/",
        user="******",
        password="******")

    # instantiate TAXII data source
    taxii = stix2.TAXIICollectionSource(collection)

    # get (url watch indicator)
    indicator_fw = taxii.get("indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f")
    print("\n\n-------Queried for Indicator - got:")
    print(indicator_fw.serialize(indent=4))

    # all versions (url watch indicator - currently two)
    indicator_fw_versions = taxii.all_versions(
        "indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f")
    print("\n\n------Queried for indicator (all_versions()) - got:")
    for indicator in indicator_fw_versions:
        print(indicator.serialize(indent=4))

    # add TAXII filter (ie filter should be passed to TAXII)
    query_filter = stix2.Filter("type", "in", "malware")

    # query() - but with filter attached. There are no malware objects in this collection
    malwares = taxii.query(query=query_filter)
    print(
        "\n\n\n--------Queried for Malware string (with above filter attached) - got:"
    )
    for malware in malwares:
        print(malware.serialize(indent=4))
    if not malwares:
        print(malwares)
コード例 #6
0
def main():
    collection = Collection(
        "http://127.0.0.1:5000/trustgroup1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/",
        user="******",
        password="******",
    )

    # instantiate TAXII data source
    taxii = stix2.TAXIICollectionSource(collection)

    # get (url watch indicator)
    indicator_fw = taxii.get("indicator--6770298f-0fd8-471a-ab8c-1c658a46574e")
    print("\n\n-------Queried for Indicator - got:")
    print(indicator_fw.serialize(indent=4))

    # all versions (url watch indicator - currently two)
    indicator_fw_versions = taxii.all_versions(
        "indicator--6770298f-0fd8-471a-ab8c-1c658a46574e")
    print("\n\n------Queried for indicator (all_versions()) - got:")
    for indicator in indicator_fw_versions:
        print(indicator.serialize(indent=4))

    # add TAXII filter (ie filter should be passed to TAXII)
    query_filter = stix2.Filter("type", "in", "malware")

    # query() - but with filter attached. There are no malware objects in this collection
    malwares = taxii.query(query=query_filter)
    print(
        "\n\n\n--------Queried for Malware string (with above filter attached) - got:"
    )
    for malware in malwares:
        print(malware.serialize(indent=4))
    if not malwares:
        print(malwares)
コード例 #7
0
def build_taxii_source(collection_name):
    """Downloads latest Enterprise or Mobile ATT&CK content from MITRE TAXII Server."""
    # Establish TAXII2 Collection instance for Enterprise ATT&CK collection
    collection_map = {
        "enterprise_attack": "95ecc380-afe9-11e4-9b6c-751b66dd541e",
        "mobile_attack": "2f669986-b40b-4423-b720-4396ca6a462b"
    }
    collection_url = "https://cti-taxii.mitre.org/stix/collections/" + collection_map[
        collection_name] + "/"
    collection = taxii2client.Collection(collection_url)
    taxii_ds = stix2.TAXIICollectionSource(collection)

    # Create an in-memory source (to prevent multiple web requests)
    return stix2.MemorySource(stix_data=taxii_ds.query())
コード例 #8
0
def test_parse_taxii_filters(collection):
    query = [
        Filter("added_after", "=", "2016-02-01T00:00:01.000Z"),
        Filter("id", "=", "taxii stix object ID"),
        Filter("type", "=", "taxii stix object ID"),
        Filter("version", "=", "first"),
        Filter("created_by_ref", "=", "Bane"),
    ]

    taxii_filters_expected = [
        Filter("added_after", "=", "2016-02-01T00:00:01.000Z"),
        Filter("id", "=", "taxii stix object ID"),
        Filter("type", "=", "taxii stix object ID"),
        Filter("version", "=", "first"),
    ]

    ds = stix2.TAXIICollectionSource(collection)

    taxii_filters = ds._parse_taxii_filters(query)

    assert taxii_filters == taxii_filters_expected
コード例 #9
0
def test_get_404():
    """a TAXIICollectionSource.get() call that receives an HTTP 404 response
    code from the taxii2client should be be returned as None.

    TAXII spec states that a TAXII server can return a 404 for nonexistent
    resources or lack of access. Decided that None is acceptable reponse
    to imply that state of the TAXII endpoint.
    """
    class TAXIICollection404():
        can_read = True

        def get_object(self, id, version=None):
            resp = Response()
            resp.status_code = 404
            resp.raise_for_status()

    ds = stix2.TAXIICollectionSource(TAXIICollection404())

    # this will raise 404 from mock TAXII Client but TAXIICollectionStore
    # should handle gracefully and return None
    stix_obj = ds.get("indicator--1")
    assert stix_obj is None
コード例 #10
0
def test_get_stix2_object(collection):
    tc_sink = stix2.TAXIICollectionSource(collection)

    objects = tc_sink.get("indicator--00000000-0000-4000-8000-000000000001")

    assert objects
コード例 #11
0
def test_get_object_not_found(collection):
    tc_source = stix2.TAXIICollectionSource(collection)
    result = tc_source.get("indicator--00000000-0000-4000-8000-000000000005")
    assert result is None
コード例 #12
0
def test_ds_taxii(collection):
    ds = stix2.TAXIICollectionSource(collection)
    assert ds.collection is not None
コード例 #13
0
    def customQuery(self, query, instance, reconnect=True):

        mydf = None
        status = ""
        str_err = ""
        out_res_df = pd.DataFrame()
        inst = self.instances[instance]
        qlist = self.formatQuery(query)
        qfilter = self.retQueryFilter(qlist)
        try:
            if self.opts['taxii_group_collections'][0] == 1:
                searcher = stix2.CompositeDataSource()
                searcher.add_data_sources([
                    stix2.TAXIICollectionSource(c)
                    for c in inst['taxii_collections']
                ])
                tres = searcher.query(qfilter)
                for r in tres:
                    try:
                        tdf = pd.json_normalize(json.loads(r.serialize()))
                        if len(tdf) > 0:
                            out_res_df = pd.concat([out_res_df, tdf],
                                                   ignore_index=True)
                    except Exceptions as e:
                        if self.debug:
                            print("Error grouped: %s" % e)
            else:
                for c in inst['taxii_collections']:
                    c_title = c.title
                    c_id = c.id
                    searcher = stix2.CompositeDataSource()
                    searcher.add_data_sources([stix2.TAXIICollectionSource(c)])
                    tres = searcher.query(qfilter)
                    for r in tres:
                        try:
                            tdf = pd.json_normalize(json.loads(r.serialize()))
                            if len(tdf) > 0:
                                tdf['collection_name'] = c_title
                                tdf['collection_id'] = c_id
                                out_res_df = pd.concat([out_res_df, tdf],
                                                       ignore_index=True)
                        except Exception as e:
                            if self.debug:
                                print("Error ungrouped: %s" % e)
            if len(out_res_df) == 0:
                mydf = None
                str_err = "Success - No Results"
            elif len(out_res_df) > 0:
                mydf = out_res_df
                str_err = "Success"
        except Exception as e:
            mydf = None
            str_err = str(e)

        if str_err.find("Success") >= 0:
            pass
        elif str_err.find("Session is not logged in") >= 0:  # Need to fix this
            # Try to rerun query
            if reconnect == True:
                self.disconnect(instance)
                self.connect(instance)
                m, s = self.customQuery(query, instance, False)
                mydf = m
                status = s
            else:
                mydf = None
                status = "Failure - Session not logged in and reconnect failed"
        else:
            status = "Failure - query_error: " + str_err
        return mydf, status