コード例 #1
0
def rel_fs_store():
    cam = Campaign(id=CAMPAIGN_ID, **CAMPAIGN_KWARGS)
    idy = Identity(id=IDENTITY_ID, **IDENTITY_KWARGS)
    ind = Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS)
    mal = Malware(id=MALWARE_ID, **MALWARE_KWARGS)
    rel1 = Relationship(ind, 'indicates', mal, id=RELATIONSHIP_IDS[0])
    rel2 = Relationship(mal, 'targets', idy, id=RELATIONSHIP_IDS[1])
    rel3 = Relationship(cam, 'uses', mal, id=RELATIONSHIP_IDS[2])
    stix_objs = [cam, idy, ind, mal, rel1, rel2, rel3]
    fs = FileSystemStore(FS_PATH)
    for o in stix_objs:
        fs.add(o)
    yield fs

    for o in stix_objs:
        filepath = os.path.join(FS_PATH, o.type, o.id,
                                _timestamp2filename(o.modified) + '.json')

        # Some test-scoped fixtures (e.g. fs_store) delete all campaigns, so by
        # the time this module-scoped fixture tears itself down, it may find
        # its campaigns already gone, which causes not-found errors.
        try:
            os.remove(filepath)
        except OSError as e:
            # 3 is the ERROR_PATH_NOT_FOUND windows error code.  Which has an
            # errno symbolic value, but not the windows meaning...
            if e.errno in (errno.ENOENT, 3):
                continue
            raise
コード例 #2
0
 def _generate_stix_bundle(self, country, city, observable_id):
     # Generate stix bundle
     country_identity = Identity(
         name=country.name,
         identity_class='group',
         custom_properties={
             'x_opencti_identity_type': 'country',
             'x_opencti_alias': [country.official_name],
         }
     )
     city_identity = Identity(
         name=city,
         identity_class='group',
         custom_properties={
             'x_opencti_identity_type': 'city'
         }
     )
     city_to_country = Relationship(
         relationship_type='localization',
         source_ref=city_identity.id,
         target_ref=country_identity.id,
     )
     observable_to_city = Relationship(
         relationship_type='localization',
         source_ref=observable_id,
         target_ref=city_identity.id,
         custom_properties={
             'x_opencti_weight': self.helper.connect_confidence_level
         }
     )
     return Bundle(objects=[country_identity, city_identity,
                            city_to_country, observable_to_city]).serialize()
コード例 #3
0
def rel_mem_store():
    cam = Campaign(id=CAMPAIGN_ID, **CAMPAIGN_KWARGS)
    idy = Identity(id=IDENTITY_ID, **IDENTITY_KWARGS)
    ind = Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS)
    mal = Malware(id=MALWARE_ID, **MALWARE_KWARGS)
    rel1 = Relationship(ind, 'indicates', mal, id=RELATIONSHIP_IDS[0])
    rel2 = Relationship(mal, 'targets', idy, id=RELATIONSHIP_IDS[1])
    rel3 = Relationship(cam, 'uses', mal, id=RELATIONSHIP_IDS[2])
    stix_objs = [cam, idy, ind, mal, rel1, rel2, rel3]
    yield MemoryStore(stix_objs)
コード例 #4
0
 def _generate_stix_bundle(self, country, city, loc, observable_id):
     # Generate stix bundle
     country_location = Location(
         id=OpenCTIStix2Utils.generate_random_stix_id("location"),
         name=country.name,
         country=country.official_name
         if hasattr(country, "official_name") else country.name,
         custom_properties={
             "x_opencti_location_type":
             "Country",
             "x_opencti_aliases": [
                 country.official_name
                 if hasattr(country, "official_name") else country.name
             ],
         },
     )
     loc_split = loc.split(",")
     city_location = Location(
         id=OpenCTIStix2Utils.generate_random_stix_id("location"),
         name=city,
         country=country.official_name
         if hasattr(country, "official_name") else country.name,
         latitude=loc_split[0],
         longitude=loc_split[1],
         custom_properties={"x_opencti_location_type": "City"},
     )
     city_to_country = Relationship(
         id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
         relationship_type="located-at",
         source_ref=city_location.id,
         target_ref=country_location.id,
     )
     observable_to_city = Relationship(
         id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
         relationship_type="located-at",
         source_ref=observable_id,
         target_ref=city_location.id,
         confidence=self.helper.connect_confidence_level,
     )
     return Bundle(
         objects=[
             country_location,
             city_location,
             city_to_country,
             observable_to_city,
         ],
         allow_custom=True,
     ).serialize()
コード例 #5
0
ファイル: misp.py プロジェクト: phucsnguyenv/connectors
    def process_observable_relations(self,
                                     object_attributes,
                                     result_table,
                                     start_element=0):
        if start_element == 0:
            result_table = []
        if len(object_attributes) == 1:
            return []

        for x in range(start_element + 1, len(object_attributes)):
            result_table.append(
                Relationship(
                    relationship_type="corresponds",
                    source_ref=object_attributes[start_element]["indicator"]
                    ["id"],
                    target_ref=object_attributes[x]["indicator"]["id"],
                    description="Same file",
                    custom_properties={"x_opencti_ignore_dates": True},
                ))
        if start_element != len(object_attributes):
            return self.process_observable_relations(object_attributes,
                                                     result_table,
                                                     start_element + 1)
        else:
            return result_table
コード例 #6
0
    def _process_hash(self, observable):

        hash_value = observable["observable_value"]
        artifact_id = None
        bundle_objects = []

        try:
            # Attempt to download the file using the private V3 API method
            request_url = (
                f"https://www.virustotal.com/api/v3/files/{hash_value}/download"
            )
            req = urllib.request.Request(request_url, headers=self.headers)
            response = urllib.request.urlopen(req)
            file_contents = response.read()
            assert file_contents is not None

            # Get the mime type for the file
            mime_type = magic.from_buffer(file_contents, mime=True)

            # Upload the file as an Artifact
            kwargs = {
                "file_name":
                hash_value,
                "data":
                file_contents,
                "mime_type":
                mime_type,
                "x_opencti_description":
                f"Downloaded from Virustotal using hash {hash_value}",
            }
            response = self.helper.api.stix_cyber_observable.upload_artifact(
                **kwargs)

            self.helper.log_info(response)

            artifact_id = response["standard_id"]

        except Exception as e:
            raise Exception(
                f"Failed to download/upload Artifact with hash {hash_value}, exception: {e}"
            )

        # Create a relationship between the StixFile and the new Artifact
        relationship = Relationship(
            id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
            relationship_type="related-to",
            created_by_ref=self.identity,
            source_ref=observable["standard_id"],
            target_ref=artifact_id,
            allow_custom=True,
        )
        bundle_objects.append(relationship)

        if bundle_objects:
            bundle = Bundle(objects=bundle_objects,
                            allow_custom=True).serialize()
            bundles_sent = self.helper.send_stix2_bundle(bundle)
            return f"Sent {len(bundles_sent)} stix bundle(s) for worker import"
        else:
            return "Nothing to attach"
コード例 #7
0
def rel_fs_store():
    cam = Campaign(id=CAMPAIGN_ID, **CAMPAIGN_KWARGS)
    idy = Identity(id=IDENTITY_ID, **IDENTITY_KWARGS)
    ind = Indicator(id=INDICATOR_ID, **INDICATOR_KWARGS)
    mal = Malware(id=MALWARE_ID, **MALWARE_KWARGS)
    rel1 = Relationship(ind, 'indicates', mal, id=RELATIONSHIP_IDS[0])
    rel2 = Relationship(mal, 'targets', idy, id=RELATIONSHIP_IDS[1])
    rel3 = Relationship(cam, 'uses', mal, id=RELATIONSHIP_IDS[2])
    stix_objs = [cam, idy, ind, mal, rel1, rel2, rel3]
    fs = FileSystemStore(FS_PATH)
    for o in stix_objs:
        fs.add(o)
    yield fs

    for o in stix_objs:
        os.remove(os.path.join(FS_PATH, o.type, o.id + '.json'))
コード例 #8
0
def create_relationship():
    """
    Creates a relationship object for the Sigma Rules
    """
    stix_custom_relationship = []
    with open('attack_pattern.json', 'rt') as attack_pattern:
        attack_patterns = json.load(attack_pattern)
        for attack_pattern in attack_patterns:
            if 'attack-pattern' in attack_pattern['attack_pattern']:
                with open('sigma_rules_stix_bundle.json', 'rt') as sigma_rules_stix_bundle:
                    sigma_rules = json.load(sigma_rules_stix_bundle)
                    for sigma_rule in sigma_rules['objects']:
                        if 'tags' in sigma_rule:
                            for attacks in sigma_rule['tags']:
                                if attacks.lower().split("attack.")[-1] == attack_pattern['technique_id'].lower():
                                    relationship = Relationship(relationship_type="sigma_rules",
                                                                source_ref=sigma_rule['id'],
                                                                target_ref=attack_pattern['attack_pattern'],
                                                                created_by_ref="identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5",
                                                                description="Example",
                                                                revoked=False,
                                                                labels="Example",
                                                                external_references=[
                                                                    {
                                                                        "description": "Example",
                                                                        "source_name": "Example",
                                                                        "url": "https://example.com"
                                                                    }
                                                                ],
                                                                object_marking_refs=["marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168"]
                                                                # granular_markings=["Example"],
                                                               )
                                    stix_custom_relationship.append(relationship)
        create_bundle(stix_custom_relationship)
コード例 #9
0
ファイル: transfer_one.py プロジェクト: benbenwt/lisa_docker
def create_relationship(indicator_list, malware):
    relation_list = []
    for indicator in indicator_list:
        relation = Relationship(source_ref=indicator,
                                target_ref=malware['id'],
                                relationship_type='indicates')
        relation_list.append(relation)
    return relation_list
コード例 #10
0
    def _process_hash(self, observable):

        hash_value = observable["observable_value"]
        artifact_id = None
        bundle_objects = []

        try:

            # Attempt to source the file contents from the hash
            bytes_obj = io.BytesIO()
            response = self.api_client.download_file(hash_value, bytes_obj)
            bytes_obj.seek(0)
            file_contents = bytes_obj.read()

            mime_type = magic.from_buffer(file_contents, mime=True)

            # Upload the file as an Artifact
            kwargs = {
                "file_name":
                hash_value,
                "data":
                file_contents,
                "mime_type":
                mime_type,
                "x_opencti_description":
                f"Downloaded from Virustotal via hash {hash_value}",
            }
            response = self.helper.api.stix_cyber_observable.upload_artifact(
                **kwargs)

            self.helper.log_info(response)

            artifact_id = response["standard_id"]

        except Exception as e:
            raise Exception(
                f"Failed to download/upload Artifact with hash {hash_value}, exception: {e}"
            )

        # Create a relationship between the StixFile and the new Artifact
        relationship = Relationship(
            id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
            relationship_type="related-to",
            created_by_ref=self.identity,
            source_ref=observable["standard_id"],
            target_ref=artifact_id,
            allow_custom=True,
        )
        bundle_objects.append(relationship)

        if bundle_objects:
            bundle = Bundle(objects=bundle_objects,
                            allow_custom=True).serialize()
            bundles_sent = self.helper.send_stix2_bundle(bundle)
            return f"Sent {len(bundles_sent)} stix bundle(s) for worker import"
        else:
            return "Nothing to attach"
コード例 #11
0
    def link_to(self, link_type, target, attributes=None):
        """Creates a link between two YetiObjects.

        Args:
          link_type: The type of link.
          target: The YetiObject to link to.
          attributes: A dictionary with attributes to add to the link.
        """
        stix_rel = Relationship(relationship_type=link_type,
                                source_ref=self.id,
                                target_ref=target.id)

        graph = self._db.graph('stix')
        edge_collection = graph.edge_collection('relationships')
        document = {
            '_from': self._arango_id,
            '_to': target._arango_id,  # pylint: disable=protected-access
            'attributes': stix_rel.serialize(),
        }
        return edge_collection.insert(document)
コード例 #12
0
    def link_to(self, target, relationship_type=None, stix_rel=None):
        """Creates a link between two YetiObjects.

        Args:
          target: The YetiObject to link to.
          relationship_type: The type of link. (e.g. targets, uses, mitigates)
          stix_rel: STIX Relationship object
        """
        from yeti.core.relationships import Relationship
        if stix_rel is None:
            stix_rel = StixRelationship(relationship_type=relationship_type,
                                        source_ref=self.id,
                                        target_ref=target.id)
            stix_rel = json.loads(stix_rel.serialize())

        existing = list(Relationship.filter({'attributes.id': stix_rel['id']}))
        if existing:
            return existing[0]
        # pylint: disable=protected-access
        return Relationship(self._arango_id, target._arango_id, stix_rel).save()
コード例 #13
0
ファイル: ipinfo.py プロジェクト: nguyenmanh1997/DarkCTI
 def _generate_stix_bundle(self, country, city, observable_id):
     # Generate stix bundle
     country_identity = Identity(
         name=country.name,
         identity_class="group",
         custom_properties={
             "x_opencti_identity_type":
             "country",
             "x_opencti_alias": [
                 country.official_name
                 if hasattr(country, "official_name") else country.name
             ],
         },
     )
     city_identity = Identity(
         name=city,
         identity_class="group",
         custom_properties={"x_opencti_identity_type": "city"},
     )
     city_to_country = Relationship(
         relationship_type="localization",
         source_ref=city_identity.id,
         target_ref=country_identity.id,
     )
     observable_to_city = Relationship(
         relationship_type="localization",
         source_ref=observable_id,
         target_ref=city_identity.id,
         custom_properties={
             "x_opencti_weight": self.helper.connect_confidence_level,
             "x_opencti_ignore_dates": True,
         },
     )
     return Bundle(objects=[
         country_identity,
         city_identity,
         city_to_country,
         observable_to_city,
     ]).serialize()
コード例 #14
0
ファイル: ipinfo.py プロジェクト: ben12385/connectors
 def _generate_stix_bundle(self, country, city, observable_id):
     # Generate stix bundle
     country_identity = Location(
         name=country.name,
         country=country.official_name
         if hasattr(country, "official_name") else country.name,
         custom_properties={
             "x_opencti_location_type":
             "Country",
             "x_opencti_aliases": [
                 country.official_name
                 if hasattr(country, "official_name") else country.name
             ],
         },
     )
     city_identity = Location(
         name=city,
         country=country.official_name
         if hasattr(country, "official_name") else country.name,
         custom_properties={"x_opencti_location_type": "city"},
     )
     city_to_country = Relationship(
         relationship_type="located-at",
         source_ref=city_identity.id,
         target_ref=country_identity.id,
     )
     observable_to_city = Relationship(
         relationship_type="located-at",
         source_ref=observable_id,
         target_ref=city_identity.id,
         confidence=self.helper.connect_confidence_level,
     )
     return Bundle(objects=[
         country_identity,
         city_identity,
         city_to_country,
         observable_to_city,
     ]).serialize()
コード例 #15
0
ファイル: amitt_stix.py プロジェクト: h0rv4th/amitt_framework
    def amitt_relationship(self):
        """

        """
        # Merge all UUID dictionaries.
        stix_objects = {**self.stix_campaign_uuid, **self.stix_intrusion_set_uuid, **self.stix_tactic_uuid,
                        **self.stix_identity_uuid, **self.stix_technique_uuid, **self.stix_threat_actor_uuid,
                        **self.stix_incident_uuid}
        for i in self.it.itertuples():
            if i.id == "I00000T000":
                continue

            if i.source in stix_objects and i.target in stix_objects:
                relationship = Relationship(
                    source_ref=stix_objects[i.source],
                    target_ref=stix_objects[i.target],
                    relationship_type=i.relationship
                )
                self.stix_objects.append(relationship)
                self.stix_relationship_uuid[i.id] = relationship.id
コード例 #16
0
def create_relationship(
    relationship_type: str,
    author: Identity,
    source: _DomainObject,
    target: _DomainObject,
    object_marking_refs: List[MarkingDefinition],
    start_time: datetime,
    stop_time: datetime,
    confidence_level: int,
) -> Relationship:
    """Create a relationship."""
    return Relationship(
        created_by_ref=author,
        relationship_type=relationship_type,
        source_ref=source.id,
        target_ref=target.id,
        object_marking_refs=object_marking_refs,
        start_time=start_time,
        stop_time=stop_time,
        confidence=confidence_level,
    )
コード例 #17
0
def create_relationship(
    relationship_type: str,
    created_by: Identity,
    source: _DomainObject,
    target: _DomainObject,
    confidence: int,
    object_markings: List[MarkingDefinition],
    start_time: Optional[datetime] = None,
    stop_time: Optional[datetime] = None,
) -> Relationship:
    """Create a relationship."""
    return Relationship(
        created_by_ref=created_by,
        relationship_type=relationship_type,
        source_ref=source,
        target_ref=target,
        start_time=start_time,
        stop_time=stop_time,
        confidence=confidence,
        object_marking_refs=object_markings,
    )
コード例 #18
0
def stixer(vulns, path):
    for vuln in vulns:
        timestamp = datetime.now()
        vuln_name = vuln['name']
        vuln_description = vuln['description']
        if args.mitigations:
            mitigation_description = get_mitigation(vuln['name'])
        else:
            mitigation_description = ""
        snippet_android = vuln['code']
        coa_name = vuln_name + "_coa"
        file_path = PurePath(vuln['file'])
        target = f"{str(file_path)}:{vuln['line']}"

        coa = CourseOfAction(type="course-of-action",
                             name=coa_name,
                             description=mitigation_description,
                             x_actions=[{
                                 "mitigation_android":
                                 "No snippet avaliable"
                             }],
                             allow_custom=True)
        vuln = Vulnerability(type="vulnerability",
                             name=vuln_name,
                             description=vuln_description,
                             vulnerable_snippet=snippet_android,
                             allow_custom=True)
        mitigates = Relationship(coa, 'mitigates', vuln)

        observed_object = File(name=target)

        observed_data = ObservedData(first_observed=timestamp,
                                     last_observed=timestamp,
                                     number_observed=1,
                                     objects={0: observed_object})
        sight = Sighting(vuln, observed_data_refs=[observed_data])
        bundle = Bundle(coa, mitigates, vuln, sight, observed_data,
                        observed_object)
        with open(f"{path}/{vuln_name}.json", "w") as f:
            f.write(str(bundle) + "\n")
コード例 #19
0
ファイル: api.py プロジェクト: Darkheir/TibetanBrownBear
    def get_neighbors(self, obj):
        """Fethes neighbors for a Yeti object.

        Args:
        obj: Yeti object to fetch neighbors for.

        Returns:
            A dictionary containing a list of STIX 2 Relationships (in the 'edge'
                key) and a `{id: object}` dictionary of Yeti objects (in the
                'vertices' key).
        """
        if isinstance(obj, entity.Entity):
            uri = 'entities/{0:s}/neighbors/'.format(obj.id)
        if isinstance(obj, indicator_base.Indicator):
            uri = 'indicators/{0:s}/neighbors/'.format(obj.id)
        response = self._do_get(uri)
        response['edges'] = [Relationship(**r) for r in response['edges']]
        vertices = []
        for item in response['vertices']:
            vertices.append(TYPES_DICT[item['type']](**item))
        response['vertices'] = vertices
        return response
コード例 #20
0
def create_relationship(
    relationship_type: str,
    author: Identity,
    source: STIXDomainObject,
    target: STIXDomainObject,
    object_marking_refs: List[MarkingDefinition],
    first_seen: datetime,
    last_seen: datetime,
    confidence_level: int,
) -> Relationship:
    """Create a relationship."""
    return Relationship(
        created_by_ref=author,
        relationship_type=relationship_type,
        source_ref=source.id,
        target_ref=target.id,
        object_marking_refs=object_marking_refs,
        custom_properties={
            CustomProperties.FIRST_SEEN: first_seen,
            CustomProperties.LAST_SEEN: last_seen,
            CustomProperties.WEIGHT: confidence_level,
        },
    )
コード例 #21
0
ファイル: thehive.py プロジェクト: DEMON1A/connectors
 def generate_case_bundle(self, case):
     markings = []
     if case["tlp"] == 0:
         markings.append(TLP_WHITE)
     if case["tlp"] == 1:
         markings.append(TLP_GREEN)
     if case["tlp"] == 2:
         markings.append(TLP_AMBER)
     if case["tlp"] == 3:
         markings.append(TLP_RED)
     if len(markings) == 0:
         markings.append(TLP_WHITE)
     bundle_objects = []
     incident = StixXOpenCTIIncident(
         id=OpenCTIStix2Utils.generate_random_stix_id("x-opencti-incident"),
         name=case["title"],
         description=case["description"],
         first_seen=datetime.utcfromtimestamp(
             int(case["createdAt"]) / 1000).strftime("%Y-%m-%dT%H:%M:%SZ"),
         last_seen=datetime.utcfromtimestamp(
             int(case["updatedAt"]) / 1000).strftime("%Y-%m-%dT%H:%M:%SZ"),
         object_marking_refs=markings,
         labels=case["tags"] if "tags" in case else [],
         created_by_ref=self.identity["standard_id"],
     )
     bundle_objects.append(incident)
     # Get observables
     observables = self.thehive_api.get_case_observables(
         case_id=case["id"]).json()
     for observable in observables:
         if observable["dataType"] == "hash":
             if len(observable["data"]) == 32:
                 data_type = "file_md5"
             elif len(observable["data"]) == 40:
                 data_type = "file_sha1"
             elif len(observable["data"]) == 64:
                 data_type = "file_sha256"
             else:
                 data_type = "unknown"
         else:
             data_type = observable["dataType"]
         observable_key = OBSERVABLES_MAPPING[data_type]
         if observable_key is not None:
             stix_observable = SimpleObservable(
                 id=OpenCTIStix2Utils.generate_random_stix_id(
                     "x-opencti-simple-observable"),
                 key=observable_key,
                 value=observable["data"],
                 description=observable["message"],
                 x_opencti_score=80 if observable["ioc"] else 50,
                 object_marking_refs=markings,
                 labels=observable["tags"] if "tags" in observable else [],
                 created_by_ref=self.identity["standard_id"],
                 x_opencti_create_indicator=observable["ioc"],
             )
             stix_observable_relation = Relationship(
                 id=OpenCTIStix2Utils.generate_random_stix_id(
                     "relationship"),
                 relationship_type="related-to",
                 created_by_ref=self.identity["standard_id"],
                 source_ref=stix_observable.id,
                 target_ref=incident.id,
                 object_marking_refs=markings,
             )
             bundle_objects.append(stix_observable)
             bundle_objects.append(stix_observable_relation)
             if observable["sighted"]:
                 fake_indicator_id = (
                     "indicator--c1034564-a9fb-429b-a1c1-c80116cc8e1e")
                 stix_sighting = Sighting(
                     id=OpenCTIStix2Utils.generate_random_stix_id(
                         "sighting"),
                     first_seen=datetime.utcfromtimestamp(
                         int(observable["startDate"] /
                             1000)).strftime("%Y-%m-%dT%H:%M:%SZ"),
                     last_seen=datetime.utcfromtimestamp(
                         int(observable["startDate"] / 1000 +
                             3600)).strftime("%Y-%m-%dT%H:%M:%SZ"),
                     where_sighted_refs=[self.identity["standard_id"]],
                     sighting_of_ref=fake_indicator_id,
                     custom_properties={
                         "x_opencti_sighting_of_ref": stix_observable.id
                     },
                 )
                 bundle_objects.append(stix_sighting)
     bundle = Bundle(objects=bundle_objects).serialize()
     return bundle
コード例 #22
0
 def _send_knowledge(self, observable, report):
     bundle_objects = []
     final_observable = observable
     if observable["entity_type"] in ["StixFile", "Artifact"]:
         final_observable = self.helper.api.stix_cyber_observable.update_field(
             id=final_observable["id"],
             key="hashes.MD5",
             value=report["md5"])
         final_observable = self.helper.api.stix_cyber_observable.update_field(
             id=final_observable["id"],
             key="hashes.SHA-1",
             value=report["sha1"])
         final_observable = self.helper.api.stix_cyber_observable.update_field(
             id=final_observable["id"],
             key="hashes.SHA-256",
             value=report["sha256"],
         )
         if "name" not in final_observable or final_observable[
                 "name"] is None:
             self.helper.api.stix_cyber_observable.update_field(
                 id=final_observable["id"],
                 key="x_opencti_additional_names",
                 value=report["submit_name"],
                 operation="add",
             )
         if final_observable["entity_type"] == "StixFile":
             self.helper.api.stix_cyber_observable.update_field(
                 id=final_observable["id"],
                 key="size",
                 value=str(report["size"]),
             )
     self.helper.api.stix_cyber_observable.update_field(
         id=final_observable["id"],
         key="x_opencti_score",
         value=str(report["threat_score"]),
     )
     # Create external reference
     external_reference = self.helper.api.external_reference.create(
         source_name="Hybrid Analysis",
         url="https://www.hybrid-analysis.com/sample/" + report["sha256"],
         description="Hybrid Analysis Report",
     )
     self.helper.api.stix_cyber_observable.add_external_reference(
         id=final_observable["id"],
         external_reference_id=external_reference["id"],
     )
     # Create tags
     for tag in report["type_short"]:
         tag_ha = self.helper.api.label.create(value=tag, color="#0059f7")
         self.helper.api.stix_cyber_observable.add_label(
             id=final_observable["id"], label_id=tag_ha["id"])
     # Attach the TTPs
     for tactic in report["mitre_attcks"]:
         if (tactic["malicious_identifiers_count"] > 0
                 or tactic["suspicious_identifiers_count"] > 0):
             attack_pattern = AttackPattern(
                 id=OpenCTIStix2Utils.generate_random_stix_id(
                     "attack-pattern"),
                 created_by_ref=self.identity,
                 name=tactic["technique"],
                 custom_properties={
                     "x_mitre_id": tactic["attck_id"],
                 },
                 object_marking_refs=[TLP_WHITE],
             )
             relationship = Relationship(
                 id=OpenCTIStix2Utils.generate_random_stix_id(
                     "relationship"),
                 relationship_type="uses",
                 created_by_ref=self.identity,
                 source_ref=final_observable["standard_id"],
                 target_ref=attack_pattern.id,
                 object_marking_refs=[TLP_WHITE],
             )
             bundle_objects.append(attack_pattern)
             bundle_objects.append(relationship)
     # Attach the domains
     for domain in report["domains"]:
         domain_stix = SimpleObservable(
             id=OpenCTIStix2Utils.generate_random_stix_id(
                 "x-opencti-simple-observable"),
             key="Domain-Name.value",
             value=domain,
             created_by_ref=self.identity,
             object_marking_refs=[TLP_WHITE],
         )
         relationship = Relationship(
             id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
             relationship_type="communicates-with",
             created_by_ref=self.identity,
             source_ref=final_observable["standard_id"],
             target_ref=domain_stix.id,
             object_marking_refs=[TLP_WHITE],
         )
         bundle_objects.append(domain_stix)
         bundle_objects.append(relationship)
     # Attach the IP addresses
     for host in report["hosts"]:
         host_stix = SimpleObservable(
             id=OpenCTIStix2Utils.generate_random_stix_id(
                 "x-opencti-simple-observable"),
             key=self.detect_ip_version(host) + ".value",
             value=host,
             created_by_ref=self.identity,
             object_marking_refs=[TLP_WHITE],
         )
         relationship = Relationship(
             id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
             relationship_type="communicates-with",
             created_by_ref=self.identity,
             source_ref=final_observable["standard_id"],
             target_ref=host_stix.id,
             object_marking_refs=[TLP_WHITE],
         )
         bundle_objects.append(host_stix)
         bundle_objects.append(relationship)
     # Attach other files
     for file in report["extracted_files"]:
         if file["threat_level"] > 0:
             file_stix = File(
                 id=OpenCTIStix2Utils.generate_random_stix_id("file"),
                 hashes={
                     "MD5": file["md5"],
                     "SHA-1": file["sha1"],
                     "SHA-256": file["sha256"],
                 },
                 size=file["size"],
                 name=file["name"],
                 custom_properties={"x_opencti_labels": file["type_tags"]},
                 created_by_ref=self.identity,
                 object_marking_refs=[TLP_WHITE],
             )
             relationship = Relationship(
                 id=OpenCTIStix2Utils.generate_random_stix_id(
                     "relationship"),
                 relationship_type="drops",
                 created_by_ref=self.identity,
                 source_ref=final_observable["standard_id"],
                 target_ref=file_stix.id,
             )
             bundle_objects.append(file_stix)
             bundle_objects.append(relationship)
     for tactic in report["mitre_attcks"]:
         if (tactic["malicious_identifiers_count"] > 0
                 or tactic["suspicious_identifiers_count"] > 0):
             attack_pattern = AttackPattern(
                 id=OpenCTIStix2Utils.generate_random_stix_id(
                     "attack-pattern"),
                 created_by_ref=self.identity,
                 name=tactic["technique"],
                 custom_properties={
                     "x_mitre_id": tactic["attck_id"],
                 },
             )
             relationship = Relationship(
                 id=OpenCTIStix2Utils.generate_random_stix_id(
                     "relationship"),
                 relationship_type="uses",
                 created_by_ref=self.identity,
                 source_ref=final_observable["standard_id"],
                 target_ref=attack_pattern.id,
             )
             bundle_objects.append(attack_pattern)
             bundle_objects.append(relationship)
     if len(bundle_objects) > 0:
         bundle = Bundle(objects=bundle_objects).serialize()
         bundles_sent = self.helper.send_stix2_bundle(bundle)
         return ("Sent " + str(len(bundles_sent)) +
                 " stix bundle(s) for worker import")
     else:
         return "Nothing to attach"
コード例 #23
0
    def _send_knowledge(self, observable, report):
        bundle_objects = []
        final_observable = observable

        target = report["target"]["file"]
        task_id = report["info"]["id"]

        final_observable = self.helper.api.stix_cyber_observable.update_field(
            id=final_observable["id"],
            input={
                "key": "hashes.MD5",
                "value": target["md5"]
            },
        )
        final_observable = self.helper.api.stix_cyber_observable.update_field(
            id=final_observable["id"],
            input={
                "key": "hashes.SHA-1",
                "value": target["sha1"]
            },
        )
        final_observable = self.helper.api.stix_cyber_observable.update_field(
            id=final_observable["id"],
            input={
                "key": "hashes.SHA-256",
                "value": target["sha256"],
            },
        )

        self.helper.api.stix_cyber_observable.update_field(
            id=final_observable["id"],
            input={
                "key": "x_opencti_score",
                "value": str(int(report["malscore"] * 10)),
            },
        )

        # Create external references
        # Analysis URL
        external_reference = self.helper.api.external_reference.create(
            source_name="CAPEv2 Sandbox Analysis",
            url=f"{self.cape_url}/analysis/{task_id}/",
            description="CAPEv2 Sandbox Analysis",
        )
        self.helper.api.stix_cyber_observable.add_external_reference(
            id=final_observable["id"],
            external_reference_id=external_reference["id"],
        )
        # JSON report
        external_reference = self.helper.api.external_reference.create(
            source_name="CAPEv2 Sandbox JSON Report",
            url=f"{self.cape_url}/filereport/{task_id}/json/",
            description="CAPEv2 Sandbox JSON Report",
        )
        self.helper.api.stix_cyber_observable.add_external_reference(
            id=final_observable["id"],
            external_reference_id=external_reference["id"],
        )
        # HTML Report
        external_reference = self.helper.api.external_reference.create(
            source_name="CAPEv2 Sandbox HTML Report",
            url=f"{self.cape_url}/filereport/{task_id}/html/",
            description="CAPEv2 Sandbox HTML Report",
        )
        self.helper.api.stix_cyber_observable.add_external_reference(
            id=final_observable["id"],
            external_reference_id=external_reference["id"],
        )

        # Create label if family was detected
        if "detections" in report and report["detections"]:
            label = self.helper.api.label.create(value=report["detections"],
                                                 color="#0059f7")
            self.helper.api.stix_cyber_observable.add_label(
                id=final_observable["id"], label_id=label["id"])

        # Create a Note containing the TrID results
        trid_json = json.dumps(report["trid"], indent=2)
        note = Note(
            abstract="TrID Analysis",
            content=f"```\n{trid_json}\n```",
            created_by_ref=self.identity,
            object_refs=[final_observable["standard_id"]],
        )
        bundle_objects.append(note)

        # Attach the TTPs
        for tactic_dict in report["ttps"]:

            attack_id = tactic_dict["ttp"]
            signature = tactic_dict["signature"]

            attack_pattern = AttackPattern(
                id=OpenCTIStix2Utils.generate_random_stix_id("attack-pattern"),
                created_by_ref=self.identity,
                name=signature,
                custom_properties={
                    "x_mitre_id": attack_id,
                },
                object_marking_refs=[TLP_WHITE],
            )

            relationship = Relationship(
                id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
                relationship_type="uses",
                created_by_ref=self.identity,
                source_ref=final_observable["standard_id"],
                target_ref=attack_pattern.id,
                object_marking_refs=[TLP_WHITE],
            )
            bundle_objects.append(attack_pattern)
            bundle_objects.append(relationship)

        # Handle procdumps and attach any Flare CAPA TTPs
        if "procdump" in report and report["procdump"]:

            # Download the zip archive of procdump files
            zip_contents = self._get_procdump_zip(task_id)
            zip_obj = io.BytesIO(zip_contents)

            # Extract with "infected" password
            zip_file = pyzipper.AESZipFile(zip_obj)
            zip_file.setpassword(b"infected")

            # Process each entry in the procdump key
            for procdump_dict in report["procdump"]:

                # If less noise was specified
                if self.less_noise:
                    # and no Yara matches, skip this procdump
                    if not procdump_dict["cape_yara"] or not procdump_dict[
                            "yara"]:
                        continue

                sha256 = procdump_dict["sha256"]
                cape_type = procdump_dict["cape_type"]
                module_path = procdump_dict["module_path"]
                procdump_contents = zip_file.read(sha256)
                mime_type = magic.from_buffer(procdump_contents, mime=True)

                kwargs = {
                    "file_name": module_path,
                    "data": procdump_contents,
                    "mime_type": mime_type,
                    "x_opencti_description": cape_type,
                }
                response = self.helper.api.stix_cyber_observable.upload_artifact(
                    **kwargs)
                self.helper.log_info(
                    f'Uploaded procdump with sha256 "{sha256}" and type "{cape_type}".'
                )

                # Build labels
                yara_rules = []
                cape_yara_rules = []
                yara_rules.extend(
                    [yara_dict["name"] for yara_dict in procdump_dict["yara"]])
                cape_yara_rules.extend([
                    yara_dict["name"]
                    for yara_dict in procdump_dict["cape_yara"]
                ])
                cape_yara_rules.extend([
                    yara_dict["meta"]["cape_type"]
                    for yara_dict in procdump_dict["cape_yara"]
                ])

                # Create and apply yara rule based labels
                for yara_rule in yara_rules:
                    label = self.helper.api.label.create(value=yara_rule,
                                                         color="#0059f7")
                    self.helper.api.stix_cyber_observable.add_label(
                        id=response["id"], label_id=label["id"])

                # Create and apply cape yara rule based labels
                for cape_yara_rule in cape_yara_rules:
                    label = self.helper.api.label.create(value=cape_yara_rule,
                                                         color="#ff8178")
                    self.helper.api.stix_cyber_observable.add_label(
                        id=response["id"], label_id=label["id"])

                # Create label for cape_type
                label = self.helper.api.label.create(value=cape_type,
                                                     color="#0059f7")
                self.helper.api.stix_cyber_observable.add_label(
                    id=response["id"], label_id=label["id"])

                # Create relationship between uploaded procdump Artifact and original
                relationship = Relationship(
                    id=OpenCTIStix2Utils.generate_random_stix_id(
                        "relationship"),
                    relationship_type="related-to",
                    created_by_ref=self.identity,
                    source_ref=response["standard_id"],
                    target_ref=final_observable["standard_id"],
                )
                bundle_objects.append(relationship)

                # Handle Flare CAPA TTPs
                if "flare_capa" in procdump_dict and procdump_dict[
                        "flare_capa"]:
                    attck_dict = procdump_dict["flare_capa"]["ATTCK"]
                    for tactic in attck_dict:
                        tp_list = attck_dict[tactic]
                        for tp in tp_list:
                            attack_pattern = AttackPattern(
                                id=OpenCTIStix2Utils.generate_random_stix_id(
                                    "attack-pattern"),
                                created_by_ref=self.identity,
                                name=tactic,
                                custom_properties={
                                    "x_mitre_id": tp,
                                },
                                object_marking_refs=[TLP_WHITE],
                            )

                            relationship = Relationship(
                                id=OpenCTIStix2Utils.generate_random_stix_id(
                                    "relationship"),
                                relationship_type="uses",
                                created_by_ref=self.identity,
                                source_ref=response["standard_id"],
                                target_ref=attack_pattern.id,
                                object_marking_refs=[TLP_WHITE],
                            )
                            bundle_objects.append(attack_pattern)
                            bundle_objects.append(relationship)

                else:
                    self.helper.log_info(
                        f"Could not find flare_capa key or was empty in procdump {sha256}."
                    )

            # Close the zip file
            zip_file.close()

        else:
            self.helper.log_info(
                "Skipping processing process dumps, procdump key is empty or not exists."
            )

        # Attach CnC addresses if any configs were found
        if "CAPE" in report and report["CAPE"]["configs"]:
            configs_list = report["CAPE"]["configs"]
            for config_dict in configs_list:
                for detection_name in config_dict:
                    # Create a Note containing the config
                    note = Note(
                        abstract=f"{detection_name} Config",
                        content=
                        f"```\n{json.dumps(config_dict, indent=2)}\n```",
                        created_by_ref=self.identity,
                        object_refs=[final_observable["standard_id"]],
                    )
                    bundle_objects.append(note)

                    if not "address" in config_dict[detection_name]:
                        self.helper.log_info(
                            f'Could not find an "address" key in {detection_name} config.'
                        )
                        continue

                    address_list = config_dict[detection_name]["address"]
                    for address in address_list:
                        parsed = address.rsplit(":", 1)[0]
                        if self._is_ipv4_address(parsed):
                            host_stix = SimpleObservable(
                                id=OpenCTIStix2Utils.generate_random_stix_id(
                                    "x-opencti-simple-observable"),
                                labels=[detection_name, "c2 server"],
                                key="IPv4-Addr.value",
                                value=parsed,
                                created_by_ref=self.identity,
                            )
                            relationship = Relationship(
                                id=OpenCTIStix2Utils.generate_random_stix_id(
                                    "relationship"),
                                relationship_type="communicates-with",
                                created_by_ref=self.identity,
                                source_ref=final_observable["standard_id"],
                                target_ref=host_stix.id,
                            )
                            bundle_objects.append(host_stix)
                            bundle_objects.append(relationship)
                        else:
                            domain = urlparse(address).hostname
                            domain_stix = SimpleObservable(
                                id=OpenCTIStix2Utils.generate_random_stix_id(
                                    "x-opencti-simple-observable"),
                                labels=[detection_name, "c2 server"],
                                key="Domain-Name.value",
                                value=domain,
                                created_by_ref=self.identity,
                                object_marking_refs=[TLP_WHITE],
                            )
                            relationship = Relationship(
                                id=OpenCTIStix2Utils.generate_random_stix_id(
                                    "relationship"),
                                relationship_type="communicates-with",
                                created_by_ref=self.identity,
                                source_ref=final_observable["standard_id"],
                                target_ref=domain_stix.id,
                            )
                            bundle_objects.append(domain_stix)
                            bundle_objects.append(relationship)

        # Attach the domains
        for domain_dict in report.get("network", {}).get("domains", []):
            domain_stix = SimpleObservable(
                id=OpenCTIStix2Utils.generate_random_stix_id(
                    "x-opencti-simple-observable"),
                key="Domain-Name.value",
                value=domain_dict["domain"],
                created_by_ref=self.identity,
                object_marking_refs=[TLP_WHITE],
            )
            relationship = Relationship(
                id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
                relationship_type="communicates-with",
                created_by_ref=self.identity,
                source_ref=final_observable["standard_id"],
                target_ref=domain_stix.id,
            )
            bundle_objects.append(domain_stix)
            bundle_objects.append(relationship)

        # Attach the IP addresses
        for host_dict in report.get("network", {}).get("hosts", []):
            host = host_dict["ip"]
            host_stix = SimpleObservable(
                id=OpenCTIStix2Utils.generate_random_stix_id(
                    "x-opencti-simple-observable"),
                key="IPv4-Addr.value",
                value=host,
                created_by_ref=self.identity,
            )
            relationship = Relationship(
                id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
                relationship_type="communicates-with",
                created_by_ref=self.identity,
                source_ref=final_observable["standard_id"],
                target_ref=host_stix.id,
            )
            bundle_objects.append(host_stix)
            bundle_objects.append(relationship)

        # Handle CAPE payloads and attach Flare CAPA TTPs if any
        if ("CAPE" in report and "payloads" in report["CAPE"]
                and report["CAPE"]["payloads"]):

            # Download the zip archive of payloads
            zip_contents = self._get_payloads_zip(task_id)
            zip_obj = io.BytesIO(zip_contents)

            # Extract with "infected" password
            zip_file = pyzipper.AESZipFile(zip_obj)
            zip_file.setpassword(b"infected")

            # Process each payload
            for payload_dict in report["CAPE"]["payloads"]:

                module_path = payload_dict["module_path"]
                sha256 = payload_dict["sha256"]
                cape_type = payload_dict["cape_type"]
                payload_contents = zip_file.read(sha256)
                mime_type = magic.from_buffer(payload_contents, mime=True)

                kwargs = {
                    "file_name": module_path,
                    "data": payload_contents,
                    "mime_type": mime_type,
                    "x_opencti_description": cape_type,
                }
                response = self.helper.api.stix_cyber_observable.upload_artifact(
                    **kwargs)
                self.helper.log_info(
                    f'Uploaded CAPE payload with sha256 "{sha256}" and type "{cape_type}".'
                )

                # Create and apply label
                label = self.helper.api.label.create(value=cape_type,
                                                     color="#ff8178")
                self.helper.api.stix_cyber_observable.add_label(
                    id=response["id"], label_id=label["id"])

                # Create relationship between uploaded payload Artifact and original
                relationship = Relationship(
                    id=OpenCTIStix2Utils.generate_random_stix_id(
                        "relationship"),
                    relationship_type="related-to",
                    created_by_ref=self.identity,
                    source_ref=response["standard_id"],
                    target_ref=final_observable["standard_id"],
                )
                bundle_objects.append(relationship)

                # Handle Flare CAPA TTPs if any
                if "flare_capa" in payload_dict and payload_dict["flare_capa"]:
                    attck_dict = payload_dict["flare_capa"]["ATTCK"]
                    for tactic in attck_dict:
                        for tp in attck_dict[tactic]:
                            attack_pattern = AttackPattern(
                                id=OpenCTIStix2Utils.generate_random_stix_id(
                                    "attack-pattern"),
                                created_by_ref=self.identity,
                                name=tactic,
                                custom_properties={
                                    "x_mitre_id": tp,
                                },
                                object_marking_refs=[TLP_WHITE],
                            )

                            relationship = Relationship(
                                id=OpenCTIStix2Utils.generate_random_stix_id(
                                    "relationship"),
                                relationship_type="uses",
                                created_by_ref=self.identity,
                                source_ref=response["standard_id"],
                                target_ref=attack_pattern.id,
                                object_marking_refs=[TLP_WHITE],
                            )
                            bundle_objects.append(attack_pattern)
                            bundle_objects.append(relationship)
                else:
                    self.helper.log_info(
                        f"Could not find flare_capa key or was empty in CAPE payload {sha256}."
                    )

            # Close the zip file
            zip_file.close()

        else:
            self.helper.log_info(
                "Skipping processing CAPE payloads, payloads key is empty or not exists."
            )

        # Serialize and send all bundles
        if bundle_objects:
            bundle = Bundle(objects=bundle_objects,
                            allow_custom=True).serialize()
            bundles_sent = self.helper.send_stix2_bundle(bundle)
            return f"Sent {len(bundles_sent)} stix bundle(s) for worker import"
        else:
            return "Nothing to attach"
コード例 #24
0
    def process_attribute(self, author, report_threats, attribute,
                          generic_actor):
        resolved_attributes = self.resolve_type(attribute['type'],
                                                attribute['value'])
        if resolved_attributes is None:
            return None

        for resolved_attribute in resolved_attributes:
            # Default values
            attribute_threats = self.prepare_threats(attribute['Galaxy'])
            if 'Tag' in attribute:
                attribute_markings = self.resolve_markings(attribute['Tag'])
            else:
                attribute_markings = [TLP_WHITE]

            if len(report_threats) == 0 and len(attribute_threats) == 0:
                attribute_threats.append(generic_actor)

            indicator = Indicator(
                name='Indicator',
                description=attribute['comment'],
                pattern=
                "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']",
                labels=['malicious-activity'],
                created_by_ref=author,
                object_marking_refs=attribute_markings,
                custom_properties={
                    'x_opencti_observable_type': resolved_attribute['type'],
                    'x_opencti_observable_value': resolved_attribute['value'],
                })

            relationships = []
            for report_threat_ref in report_threats:
                relationships.append(
                    Relationship(relationship_type='indicates',
                                 created_by_ref=author,
                                 source_ref=indicator.id,
                                 target_ref=report_threat_ref.id,
                                 description=attribute['comment'],
                                 object_marking_refs=attribute_markings,
                                 custom_properties={
                                     'x_opencti_first_seen':
                                     datetime.utcfromtimestamp(
                                         int(attribute['timestamp'])).strftime(
                                             '%Y-%m-%dT%H:%M:%SZ'),
                                     'x_opencti_last_seen':
                                     datetime.utcfromtimestamp(
                                         int(attribute['timestamp'])).strftime(
                                             '%Y-%m-%dT%H:%M:%SZ'),
                                     'x_opencti_weight':
                                     self.helper.connect_confidence_level
                                 }))
            for attribute_threat_ref in attribute_threats:
                relationships.append(
                    Relationship(relationship_type='indicates',
                                 created_by_ref=author,
                                 source_ref=indicator.id,
                                 target_ref=attribute_threat_ref.id,
                                 description=attribute['comment'],
                                 object_marking_refs=attribute_markings,
                                 custom_properties={
                                     'x_opencti_first_seen':
                                     datetime.utcfromtimestamp(
                                         int(attribute['timestamp'])).strftime(
                                             '%Y-%m-%dT%H:%M:%SZ'),
                                     'x_opencti_last_seen':
                                     datetime.utcfromtimestamp(
                                         int(attribute['timestamp'])).strftime(
                                             '%Y-%m-%dT%H:%M:%SZ'),
                                     'x_opencti_weight':
                                     self.helper.connect_confidence_level
                                 }))
            return {
                'indicator': indicator,
                'relationships': relationships,
                'attribute_threats': attribute_threats,
                'markings': attribute_markings
            }
コード例 #25
0
    def process_attribute(
        self,
        author,
        event_elements,
        event_markings,
        attribute_external_references,
        attribute,
    ):
        try:
            resolved_attributes = self.resolve_type(
                attribute["type"], attribute["value"]
            )
            if resolved_attributes is None:
                return None

            for resolved_attribute in resolved_attributes:
                ### Pre-process
                # Elements
                attribute_elements = self.prepare_elements(attribute["Galaxy"], author)
                # Markings & Tags
                attribute_tags = []
                if "Tag" in attribute:
                    attribute_markings = self.resolve_markings(
                        attribute["Tag"], with_default=False
                    )
                    attribute_tags = self.resolve_tags(attribute["Tag"])
                    if len(attribute_markings) == 0:
                        attribute_markings = event_markings
                else:
                    attribute_markings = event_markings

                ### Create the indicator
                observable_type = resolved_attribute["type"]
                observable_value = resolved_attribute["value"]
                name = resolved_attribute["value"]
                pattern_type = "stix"
                # observable type is yara for instance
                if observable_type in PATTERNTYPES:
                    pattern_type = observable_type
                    observable_type = "Unknown"
                    genuine_pattern = (
                        "[file:hashes.md5 = 'd41d8cd98f00b204e9800998ecf8427e']"
                    )
                    pattern = observable_value
                    name = (
                        attribute["comment"]
                        if len(attribute["comment"]) > 0
                        else observable_type
                    )
                # observable type is not in stix 2
                elif observable_type not in OPENCTISTIX2:
                    return None
                # observable type is in stix
                else:
                    if "transform" in OPENCTISTIX2[observable_type]:
                        if (
                            OPENCTISTIX2[observable_type]["transform"]["operation"]
                            == "remove_string"
                        ):
                            observable_value = observable_value.replace(
                                OPENCTISTIX2[observable_type]["transform"]["value"], ""
                            )
                    lhs = ObjectPath(
                        OPENCTISTIX2[observable_type]["type"],
                        OPENCTISTIX2[observable_type]["path"],
                    )
                    genuine_pattern = str(
                        ObservationExpression(
                            EqualityComparisonExpression(lhs, observable_value)
                        )
                    )
                    pattern = genuine_pattern

                indicator = Indicator(
                    name=name,
                    description=attribute["comment"],
                    pattern=genuine_pattern,
                    valid_from=datetime.utcfromtimestamp(
                        int(attribute["timestamp"])
                    ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                    labels=["malicious-activity"],
                    created_by_ref=author,
                    object_marking_refs=attribute_markings,
                    external_references=attribute_external_references,
                    custom_properties={
                        "x_opencti_indicator_pattern": pattern,
                        "x_opencti_observable_type": observable_type,
                        "x_opencti_observable_value": observable_value,
                        "x_opencti_pattern_type": pattern_type,
                        "x_opencti_tags": attribute_tags,
                    },
                )

                ### Create the relationships
                relationships = []
                # Event threats
                for threat in (
                    event_elements["intrusion_sets"]
                    + event_elements["malwares"]
                    + event_elements["tools"]
                ):
                    relationships.append(
                        Relationship(
                            relationship_type="indicates",
                            created_by_ref=author,
                            source_ref=indicator.id,
                            target_ref=threat.id,
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                            },
                        )
                    )
                # Attribute threats
                for threat in (
                    attribute_elements["intrusion_sets"]
                    + attribute_elements["malwares"]
                    + attribute_elements["tools"]
                ):
                    relationships.append(
                        Relationship(
                            relationship_type="indicates",
                            created_by_ref=author,
                            source_ref=indicator.id,
                            target_ref=threat.id,
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                            },
                        )
                    )
                # Event Attack Patterns
                for attack_pattern in event_elements["attack_patterns"]:
                    if len(event_elements["malwares"]) > 0:
                        threats = event_elements["malwares"]
                    elif len(event_elements["intrusion_sets"]) > 0:
                        threats = event_elements["intrusion_sets"]
                    else:
                        threats = []
                    for threat in threats:
                        relationship_uses = Relationship(
                            relationship_type="uses",
                            created_by_ref=author,
                            source_ref=threat.id,
                            target_ref=attack_pattern.id,
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                                "x_opencti_ignore_dates": True,
                            },
                        )
                        relationships.append(relationship_uses)
                        relationship_indicates = Relationship(
                            relationship_type="indicates",
                            created_by_ref=author,
                            source_ref=indicator.id,
                            target_ref="malware--fa42a846-8d90-4e51-bc29-71d5b4802168",  # Fake
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                                "x_opencti_source_ref": indicator.id,
                                "x_opencti_target_ref": relationship_uses.id,
                            },
                        )
                        relationships.append(relationship_indicates)
                # Attribute Attack Patterns
                for attack_pattern in attribute_elements["attack_patterns"]:
                    if len(attribute_elements["malwares"]) > 0:
                        threats = attribute_elements["malwares"]
                    elif len(attribute_elements["intrusion_sets"]) > 0:
                        threats = attribute_elements["intrusion_sets"]
                    else:
                        threats = []
                    for threat in threats:
                        relationship_uses = Relationship(
                            relationship_type="uses",
                            created_by_ref=author,
                            source_ref=threat.id,
                            target_ref=attack_pattern.id,
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                                "x_opencti_ignore_dates": True,
                            },
                        )
                        relationships.append(relationship_uses)
                        relationship_indicates = Relationship(
                            relationship_type="indicates",
                            created_by_ref=author,
                            source_ref=indicator.id,
                            target_ref="malware--fa42a846-8d90-4e51-bc29-71d5b4802168",  # Fake
                            description=attribute["comment"],
                            object_marking_refs=attribute_markings,
                            custom_properties={
                                "x_opencti_first_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_last_seen": datetime.utcfromtimestamp(
                                    int(attribute["timestamp"])
                                ).strftime("%Y-%m-%dT%H:%M:%SZ"),
                                "x_opencti_weight": self.helper.connect_confidence_level,
                                "x_opencti_source_ref": indicator.id,
                                "x_opencti_target_ref": relationship_uses.id,
                                "x_opencti_ignore_dates": True,
                            },
                        )
                        relationships.append(relationship_indicates)

                return {
                    "indicator": indicator,
                    "relationships": relationships,
                    "attribute_elements": attribute_elements,
                    "markings": attribute_markings,
                }
        except:
            return None
コード例 #26
0
    def process_attribute(self, author, event_elements, event_markings, attribute):
        resolved_attributes = self.resolve_type(attribute['type'], attribute['value'])
        if resolved_attributes is None:
            return None

        for resolved_attribute in resolved_attributes:
            ### Pre-process
            # Elements
            attribute_elements = self.prepare_elements(attribute['Galaxy'])
            # Markings
            if 'Tag' in attribute:
                attribute_markings = self.resolve_markings(attribute['Tag'], with_default=False)
                if len(attribute_markings) == 0:
                    attribute_markings = event_markings
            else:
                attribute_markings = event_markings

            ### Create the indicator
            observable_type = resolved_attribute['type']
            observable_value = resolved_attribute['value']
            pattern_type = 'stix'
            if observable_type in PATTERNTYPES:
                pattern_type = observable_type
            elif observable_type not in OPENCTISTIX2:
                return None
            else:
                if 'transform' in OPENCTISTIX2[observable_type]:
                    if OPENCTISTIX2[observable_type]['transform']['operation'] == 'remove_string':
                        observable_value = observable_value.replace(OPENCTISTIX2[observable_type]['transform']['value'], '')
                lhs = ObjectPath(OPENCTISTIX2[observable_type]['type'], OPENCTISTIX2[observable_type]['path'])
                observable_value = ObservationExpression(EqualityComparisonExpression(lhs, observable_value))
            try:
                indicator = Indicator(
                    name=resolved_attribute['value'],
                    description=attribute['comment'],
                    pattern=str(observable_value),
                    valid_from=datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime('%Y-%m-%dT%H:%M:%SZ'),
                    labels=['malicious-activity'],
                    created_by_ref=author,
                    object_marking_refs=attribute_markings,
                    custom_properties={
                        'x_opencti_observable_type': resolved_attribute['type'],
                        'x_opencti_observable_value': resolved_attribute['value'],
                        'x_opencti_pattern_type': pattern_type
                    }
                )
            except:
                return None

            ### Create the relationships
            relationships = []
            # Event threats
            for threat in (event_elements['intrusion_sets'] + event_elements['malwares'] + event_elements['tools']):
                relationships.append(
                    Relationship(
                        relationship_type='indicates',
                        created_by_ref=author,
                        source_ref=indicator.id,
                        target_ref=threat.id,
                        description=attribute['comment'],
                        object_marking_refs=attribute_markings,
                        custom_properties={
                            'x_opencti_first_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_last_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_weight': self.helper.connect_confidence_level
                        }
                    )
                )
            # Attribute threats
            for threat in (attribute_elements['intrusion_sets'] + attribute_elements['malwares'] + attribute_elements[
                'tools']):
                relationships.append(
                    Relationship(
                        relationship_type='indicates',
                        created_by_ref=author,
                        source_ref=indicator.id,
                        target_ref=threat.id,
                        description=attribute['comment'],
                        object_marking_refs=attribute_markings,
                        custom_properties={
                            'x_opencti_first_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_last_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_weight': self.helper.connect_confidence_level
                        }
                    )
                )
            # Event Attack Patterns
            for attack_pattern in event_elements['attack_patterns']:
                if len(event_elements['malwares']) > 0:
                    threats = event_elements['malwares']
                elif len(event_elements['intrusion_sets']) > 0:
                    threats = event_elements['intrusion_sets']
                else:
                    threats = []
                for threat in threats:
                    relationship_uses = Relationship(
                        relationship_type='uses',
                        created_by_ref=author,
                        source_ref=threat.id,
                        target_ref=attack_pattern.id,
                        description=attribute['comment'],
                        object_marking_refs=attribute_markings,
                        custom_properties={
                            'x_opencti_first_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_last_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_weight': self.helper.connect_confidence_level,
                            'x_opencti_ignore_dates': True
                        }
                    )
                    relationships.append(relationship_uses)
                    relationship_indicates = Relationship(
                        relationship_type='indicates',
                        created_by_ref=author,
                        source_ref=indicator.id,
                        target_ref='malware--fa42a846-8d90-4e51-bc29-71d5b4802168',  # Fake
                        description=attribute['comment'],
                        object_marking_refs=attribute_markings,
                        custom_properties={
                            'x_opencti_first_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_last_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_weight': self.helper.connect_confidence_level,
                            'x_opencti_source_ref': indicator.id,
                            'x_opencti_target_ref': relationship_uses.id
                        }
                    )
                    relationships.append(relationship_indicates)
            # Attribute Attack Patterns
            for attack_pattern in attribute_elements['attack_patterns']:
                if len(attribute_elements['malwares']) > 0:
                    threats = attribute_elements['malwares']
                elif len(attribute_elements['intrusion_sets']) > 0:
                    threats = attribute_elements['intrusion_sets']
                else:
                    threats = []
                for threat in threats:
                    relationship_uses = Relationship(
                        relationship_type='uses',
                        created_by_ref=author,
                        source_ref=threat.id,
                        target_ref=attack_pattern.id,
                        description=attribute['comment'],
                        object_marking_refs=attribute_markings,
                        custom_properties={
                            'x_opencti_first_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_last_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_weight': self.helper.connect_confidence_level,
                            'x_opencti_ignore_dates': True
                        }
                    )
                    relationships.append(relationship_uses)
                    relationship_indicates = Relationship(
                        relationship_type='indicates',
                        created_by_ref=author,
                        source_ref=indicator.id,
                        target_ref='malware--fa42a846-8d90-4e51-bc29-71d5b4802168',  # Fake
                        description=attribute['comment'],
                        object_marking_refs=attribute_markings,
                        custom_properties={
                            'x_opencti_first_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_last_seen': datetime.utcfromtimestamp(int(attribute['timestamp'])).strftime(
                                '%Y-%m-%dT%H:%M:%SZ'),
                            'x_opencti_weight': self.helper.connect_confidence_level,
                            'x_opencti_source_ref': indicator.id,
                            'x_opencti_target_ref': relationship_uses.id,
                            'x_opencti_ignore_dates': True
                        }
                    )
                    relationships.append(relationship_indicates)

            return {
                'indicator': indicator,
                'relationships': relationships,
                'attribute_elements': attribute_elements,
                'markings': attribute_markings
            }
コード例 #27
0
        try:
            title, pattern = ioc_to_title_and_pattern(ioc)
        except Exception as e:
            logging.error(f"Skipping indicator: {e}")
            continue
        description = " ".join(
            title.split()[:2]) + f" involved with {args.threat_name}"
        indicator = Indicator(labels="malicious-activity",
                              pattern_type='stix',
                              pattern=pattern,
                              valid_from=datetime.now(),
                              description=description,
                              name=title,
                              created_by_ref=identity)
        relationship = Relationship(relationship_type='indicates',
                                    source_ref=indicator.id,
                                    target_ref=malware.id)
        objects.append(indicator)
        objects.append(relationship)
        for ap in aps:
            relationship = Relationship(relationship_type='indicates',
                                        source_ref=indicator.id,
                                        target_ref=ap.id)
            objects.append(relationship)

    bundle = Bundle(objects=objects)

    if args.output:
        with open(args.output, 'w') as f:
            f.write(str(bundle))
    else:
コード例 #28
0
    def process_yara_rules(self) -> None:
        try:
            rules_json = self.valhalla_client.get_rules_json()
            response = ApiResponse.parse_obj(rules_json)
        except Exception as err:
            self.helper.log_error(f"error downloading rules: {err}")
            return None

        for yr in response.rules:
            # Handle reference URLs supplied by the Valhalla API
            refs = []
            if yr.reference is not None and yr.reference != "" and yr.reference != "-":
                try:
                    san_url = urlparse(yr.reference)
                    ref = ExternalReference(
                        source_name="Nextron Systems Valhalla API",
                        url=san_url.geturl(),
                        description="Rule Reference: " + san_url.geturl(),
                    )
                    refs.append(ref)
                except Exception:
                    self.helper.log_error(
                        f"error parsing ref url: {yr.reference}")
                    continue

            indicator = Indicator(
                name=yr.name,
                description=yr.cti_description,
                pattern_type="yara",
                pattern=yr.content,
                labels=yr.tags,
                valid_from=yr.cti_date,
                valid_until=datetime.utcnow() + relativedelta(years=2),
                object_marking_refs=[self.default_marking],
                created_by_ref=self.organization,
                confidence=self.confidence_level,
                external_references=refs,
                custom_properties={
                    "x_opencti_main_observable_type": "StixFile",
                    "x_opencti_detection": True,
                    "x_opencti_score": yr.score,
                },
            )

            self.bundle_objects.append(indicator)

            # Handle Tags - those include MITRE ATT&CK tags that we want to
            # create relationships for
            for tag in yr.tags:
                # handle Mitre ATT&CK relation indicator <-> attack-pattern
                if re.search(r"^T\d{4}$", tag):
                    attack_pattern_id = self._ATTACK_MAPPING.get(tag)

                    if attack_pattern_id is None or attack_pattern_id == "":
                        self.helper.log_info(
                            f"no attack_pattern found for {tag}")
                        return None

                    ap_rel = Relationship(
                        relationship_type="indicates",
                        source_ref=indicator,
                        target_ref=attack_pattern_id,
                        description="Yara Rule from Valhalla API",
                        created_by_ref=self.organization,
                        confidence=self.confidence_level,
                        object_marking_refs=[self.default_marking],
                    )
                    self.bundle_objects.append(ap_rel)

                # handle Mitre ATT&CK group relation indicator <-> intrusion-set
                if re.search(r"^G\d{4}$", tag):
                    intrusion_set_id = self._ATTACK_MAPPING.get(tag)

                    if intrusion_set_id == "" or intrusion_set_id is None:
                        self.helper.log_info(
                            f"no intrusion_set found for {tag}")
                        return None

                    is_rel = Relationship(
                        relationship_type="indicates",
                        source_ref=indicator,
                        target_ref=intrusion_set_id,
                        description="Yara Rule from Valhalla API",
                        created_by_ref=self.organization,
                        confidence=self.confidence_level,
                        object_marking_refs=[self.default_marking],
                    )
                    self.bundle_objects.append(is_rel)
コード例 #29
0
    def _process_results(self, observable, results):
        bundle_objects = []
        unpack_id = results["id"]

        # Create external reference
        analysis_url = f"https://www.unpac.me/results/{unpack_id}"
        external_reference = self.helper.api.external_reference.create(
            source_name="UnpacMe Results",
            url=analysis_url,
            description="UnpacMe Results",
        )
        self.helper.api.stix_cyber_observable.add_external_reference(
            id=observable["id"],
            external_reference_id=external_reference["id"],
        )

        # Create default labels
        extracted_label = self.helper.api.label.create(
            value="extracted", color=self.default_tag_color)

        # Parse the results
        label_ids = []
        for result_dict in results["results"]:
            sha256 = result_dict["hashes"]["sha256"]

            # If less noise, check to ensure the files were identified as malware
            if self.less_noise:
                self.helper.log_info("Less noise is enabled.")
                if not result_dict["malware_id"]:
                    self.helper.log_info(
                        f"Skipping upload of {sha256} as it had no matching family."
                    )
                    continue

            # Download the file
            file_contents = self.unpacme_client.download(sha256=sha256)

            # Upload as Artifact to OpenCTI
            mime_type = magic.from_buffer(file_contents, mime=True)

            kwargs = {
                "file_name": sha256,
                "data": file_contents,
                "mime_type": mime_type,
                "x_opencti_description": "UnpacMe extracted file.",
            }
            response = self.helper.api.stix_cyber_observable.upload_artifact(
                **kwargs)

            # Create Relationship between original and newly uploaded Artifact
            relationship = Relationship(
                id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
                relationship_type="related-to",
                created_by_ref=self.identity,
                source_ref=response["standard_id"],
                target_ref=observable["standard_id"],
            )
            bundle_objects.append(relationship)

            # Attach default "extracted" label
            if response["id"] != observable["id"]:
                self.helper.api.stix_cyber_observable.add_label(
                    id=response["id"], label_id=extracted_label["id"])

            # If found malware ids, attach as labels
            for malware_id_dict in result_dict["malware_id"]:
                family_label = self.helper.api.label.create(
                    value=malware_id_dict["name"], color=self.family_color)
                self.helper.api.stix_cyber_observable.add_label(
                    id=response["id"], label_id=family_label["id"])
                label_ids.append(family_label["id"])

        # Attach all identified tags to the Artifact
        for label_id in label_ids:
            self.helper.api.stix_cyber_observable.add_label(
                id=observable["id"], label_id=family_label["id"])

        # Serialize and send all bundles
        if bundle_objects:
            bundle = Bundle(objects=bundle_objects,
                            allow_custom=True).serialize()
            bundles_sent = self.helper.send_stix2_bundle(bundle)
            return f"Sent {len(bundles_sent)} stix bundle(s) for worker import"
        else:
            return "Nothing to attach"
コード例 #30
0
def update_list(bundle_id: str, raw_companies_file: str, companies: dict, sectors: dict) -> Bundle:
    bundles = []

    with open(raw_companies_file) as csv_file:
        csv_dict_reader = DictReader(csv_file, delimiter=',')
        
        for row in csv_dict_reader:
            if row['createdBy'] == "ANSSI":
                creator = anssi
            else:
                creator = row['createdBy']  # has to be a STIX ID

            entity_id = None
            entity_creation_date = None
            if row['name'] in companies:
                entity_id = companies[row['name']]['id']
                entity_creation_date = companies[row['name']]['created']
               
            if row['x_opencti_aliases']:
                aliases = row['x_opencti_aliases'].split(',')
            else:
                aliases = []
            
            if row['other_stix_ids']:
                stix_ids = row['x_opencti_stix_ids'].split(',')
            else:
                stix_ids = []

            markings = row['objectMarking'].split(',')
                    
            company = Identity(
                id=entity_id,
                name=row['name'],
                created=entity_creation_date,
                description=row['description'],
                contact_information=row['contact_information'],
                roles="",   # There's no real point for having a role here. Only companies/entities here, no people
                identity_class='organization',
                created_by_ref=creator,
                object_marking_refs=[TLP_WHITE],
                custom_properties={
                    'x_opencti_aliases': aliases,
                    'x_opencti_organization_type': row['x_opencti_organization_type'],
                    'x_opencti_stix_ids': stix_ids,
                }
            )
            bundles.append(company)
            
            company_sectors = row['sectors'].split(',')
            for company_sector in company_sectors:
                if company_sector == '':
                    print(f"Error: Organization {row['name']} has no Sector assigned!!")
                    return []
                
                relevant_sector = sectors.get(company_sector, None)
                # search through aliases
                if relevant_sector is None:
                    for sector_name, sector in sectors.items():
                        aliases = sector.get('x_opencti_aliases', [])
                        if company_sector in aliases:
                            relevant_sector = sector

                if relevant_sector is None:
                    print(f"Sector '{company_sector}' for company '{row['name']}' can't be found")
                    continue

                relationship_id = None
                relationship_name = f"{company.id}_{relevant_sector['id']}"
                relationship_creation_date = None
                if relationship_name in companies:
                    relationship_id = companies[relationship_name]['id']
                    relationship_creation_date = companies[relationship_name]['created']

                sector_relationship = Relationship(
                    id=relationship_id,
                    created=relationship_creation_date,
                    relationship_type='part-of',
                    source_ref=company.id,
                    target_ref=relevant_sector['id'],
                    description=f"Company '{row['name']}' is part of sector '{company_sector}'",
                    confidence=100,
                    created_by_ref=creator,
                    object_marking_refs=[TLP_WHITE],
                )
                
                bundles.append(sector_relationship)

    if bundle_id:
        bundle = Bundle(
            objects=bundles,
            id=bundle_id,
            allow_custom=True
        )
    else:
        bundle = Bundle(
            objects=bundles,
            allow_custom=True
        )
            
    return bundle