Exemple #1
0
 def case_vulnerability_import() -> Dict:
     return {
         "data": [
             {
                 "type": IdentityTypes.ORGANIZATION.value,
                 "name": "Testing aaaaa",
                 "description": "OpenCTI Test Org",
                 "class": Identity,
                 "id":
                 OpenCTIStix2Utils.generate_random_stix_id("identity"),
             },
             {
                 "type":
                 "Vulnerability",
                 "name":
                 "CVE-1979-1234",
                 "description":
                 "evil evil evil",
                 "class":
                 Vulnerability,
                 "id":
                 OpenCTIStix2Utils.generate_random_stix_id("vulnerability"),
             },
         ],
         "config":
         "tests/data/external_import_config.yml",
     }
Exemple #2
0
 def setup(self):
     self.ipv4 = self.api_client.stix_cyber_observable.create(
         simple_observable_id=OpenCTIStix2Utils.generate_random_stix_id(
             "x-opencti-simple-observable"),
         simple_observable_key="IPv4-Addr.value",
         simple_observable_value="198.51.100.3",
     )
     self.domain = self.api_client.stix_cyber_observable.create(
         simple_observable_id=OpenCTIStix2Utils.generate_random_stix_id(
             "x-opencti-simple-observable"),
         simple_observable_key="Domain-Name.value",
         simple_observable_value="example.com",
     )
Exemple #3
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()
Exemple #4
0
    def _process_message(self, data: Dict) -> str:
        file_fetch = data["file_fetch"]
        file_uri = self.helper.opencti_url + file_fetch

        # Downloading and saving file to connector
        self.helper.log_info("Importing the file " + file_uri)

        observable = SimpleObservable(
            id=OpenCTIStix2Utils.generate_random_stix_id(
                "x-opencti-simple-observable"),
            key=self.data["simple_observable_key"],
            value=self.data["simple_observable_value"],
        )

        bundle_objects = [observable]
        entity_id = data.get("entity_id", None)
        report = self.helper.api.report.read(id=entity_id)

        report = Report(
            id=report["standard_id"],
            name=report["name"],
            description=report["description"],
            published=self.helper.api.stix2.format_date(report["published"]),
            report_types=report["report_types"],
            object_refs=bundle_objects,
        )

        bundle_objects.append(report)
        # create stix bundle
        bundle = Bundle(objects=bundle_objects).serialize()
        # send data
        self.helper.send_stix2_bundle(bundle=bundle)
        return "foo"
 def _process_message(self, data):
     file_fetch = data["file_fetch"]
     file_uri = self.helper.opencti_url + file_fetch
     file_name = os.path.basename(file_fetch)
     entity_id = data["entity_id"]
     # Get context
     is_context = entity_id is not None and len(entity_id) > 0
     if self.helper.get_only_contextual() and not is_context:
         raise ValueError(
             "No context defined, connector is get_only_contextual true"
         )
     self.helper.log_info("Importing the file " + file_uri)
     # Get the file
     file_content = self.helper.api.fetch_opencti_file(file_uri, True)
     # Write the file
     f = open(file_name, "wb")
     f.write(file_content)
     f.close()
     # Parse
     bundle_objects = []
     i = 0
     parser = iocp.IOC_Parser(None, "pdf", True, "pdfminer", "json")
     parsed = parser.parse(file_name)
     os.remove(file_name)
     if parsed != []:
         for file in parsed:
             if file != None:
                 for page in file:
                     if page != []:
                         for match in page:
                             resolved_match = self.resolve_match(match)
                             if resolved_match:
                                 observable = SimpleObservable(
                                     id=OpenCTIStix2Utils.generate_random_stix_id(
                                         "x-opencti-simple-observable"
                                     ),
                                     key=resolved_match["type"],
                                     value=resolved_match["value"],
                                     x_opencti_create_indicator=self.create_indicator,
                                 )
                                 bundle_objects.append(observable)
                                 i += 1
     else:
         self.helper.log_error("Could not parse the report!")
     if is_context:
         entity = self.helper.api.stix_domain_object.read(id=entity_id)
         if entity is not None:
             if entity["entity_type"] == "Report" and len(bundle_objects) > 0:
                 report = Report(
                     id=entity["standard_id"],
                     name=entity["name"],
                     description=entity["description"],
                     published=self.helper.api.stix2.format_date(entity["created"]),
                     report_types=entity["report_types"],
                     object_refs=bundle_objects,
                 )
                 bundle_objects.append(report)
     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"
    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"
Exemple #7
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"
Exemple #8
0
    def _process_parsing_results(
        self, parsed: List[Dict]
    ) -> (List[SimpleObservable], List[str]):
        observables = []
        entities = []
        for match in parsed:
            if match[RESULT_FORMAT_TYPE] == OBSERVABLE_CLASS:
                # Hardcoded exceptions since SimpleObservable doesn't support those types yet
                if match[RESULT_FORMAT_CATEGORY] == "Vulnerability.name":
                    observable = self.helper.api.vulnerability.read(
                        filters={"key": "name", "values": [match[RESULT_FORMAT_MATCH]]}
                    )
                    if observable is None:
                        self.helper.log_info(
                            f"Vulnerability with name '{match[RESULT_FORMAT_MATCH]}' could not be "
                            f"found. Is the CVE Connector activated?"
                        )
                        continue
                elif match[RESULT_FORMAT_CATEGORY] == "Attack-Pattern.x_mitre_id":
                    observable = self.helper.api.attack_pattern.read(
                        filters={
                            "key": "x_mitre_id",
                            "values": [match[RESULT_FORMAT_MATCH]],
                        }
                    )
                    if observable is None:
                        self.helper.log_info(
                            f"AttackPattern with MITRE ID '{match[RESULT_FORMAT_MATCH]}' could not be "
                            f"found. Is the MITRE Connector activated?"
                        )
                        continue

                else:
                    observable = self.helper.api.stix_cyber_observable.create(
                        simple_observable_id=OpenCTIStix2Utils.generate_random_stix_id(
                            "x-opencti-simple-observable"
                        ),
                        simple_observable_key=match[RESULT_FORMAT_CATEGORY],
                        simple_observable_value=match[RESULT_FORMAT_MATCH],
                        createIndicator=self.create_indicator,
                    )

                observables.append(observable["id"])

            elif match[RESULT_FORMAT_TYPE] == ENTITY_CLASS:
                entities.append(match[RESULT_FORMAT_MATCH])
            else:
                self.helper.log_info("Odd data received: {}".format(match))

        return observables, entities
Exemple #9
0
def _create_random_identifier(identifier_type: str) -> str:
    return OpenCTIStix2Utils.generate_random_stix_id(identifier_type)
Exemple #10
0
    def _process_parsing_results(
            self, parsed: List[Dict],
            context_entity: Dict) -> (List[SimpleObservable], List[str]):
        observables = []
        entities = []
        if context_entity is not None:
            object_markings = [
                x["standard_id"]
                for x in context_entity.get("objectMarking", [])
            ]
            # external_references = [x['standard_id'] for x in report.get('externalReferences', [])]
            # labels = [x['standard_id'] for x in report.get('objectLabel', [])]
            author = context_entity.get("createdBy")
        else:
            object_markings = []
            author = None
        if author is not None:
            author = author.get("standard_id", None)
        for match in parsed:
            if match[RESULT_FORMAT_TYPE] == OBSERVABLE_CLASS:
                if match[RESULT_FORMAT_CATEGORY] == "Vulnerability.name":
                    entity = self.helper.api.vulnerability.read(
                        filters={
                            "key": "name",
                            "values": [match[RESULT_FORMAT_MATCH]]
                        })
                    if entity is None:
                        self.helper.log_info(
                            f"Vulnerability with name '{match[RESULT_FORMAT_MATCH]}' could not be "
                            f"found. Is the CVE Connector activated?")
                        continue

                    entities.append(entity["standard_id"])
                elif match[
                        RESULT_FORMAT_CATEGORY] == "Attack-Pattern.x_mitre_id":
                    entity = self.helper.api.attack_pattern.read(
                        filters={
                            "key": "x_mitre_id",
                            "values": [match[RESULT_FORMAT_MATCH]],
                        })
                    if entity is None:
                        self.helper.log_info(
                            f"AttackPattern with MITRE ID '{match[RESULT_FORMAT_MATCH]}' could not be "
                            f"found. Is the MITRE Connector activated?")
                        continue

                    entities.append(entity["standard_id"])
                else:
                    observable = SimpleObservable(
                        id=OpenCTIStix2Utils.generate_random_stix_id(
                            "x-opencti-simple-observable"),
                        key=match[RESULT_FORMAT_CATEGORY],
                        value=match[RESULT_FORMAT_MATCH],
                        x_opencti_create_indicator=self.create_indicator,
                        object_marking_refs=object_markings,
                        created_by_ref=author,
                        # labels=labels,
                        # external_references=external_references
                    )
                    observables.append(observable)

            elif match[RESULT_FORMAT_TYPE] == ENTITY_CLASS:
                entities.append(match[RESULT_FORMAT_MATCH])
            else:
                self.helper.log_info("Odd data received: {}".format(match))

        return observables, entities
Exemple #11
0
def convert(filename, output="output.json"):
    # Create the default author
    author = Identity(name="The MITRE Corporation",
                      identity_class="organization")
    count = 0
    with open(filename) as json_file:
        vulnerabilities_bundle = [author]
        data = json.load(json_file)
        for cves in data["CVE_Items"]:
            count += 1
            # Get the name
            name = cves["cve"]["CVE_data_meta"]["ID"]

            # Create external references
            external_reference = ExternalReference(
                source_name="NIST NVD",
                url="https://nvd.nist.gov/vuln/detail/" + name)
            external_references = [external_reference]
            for reference in cves["cve"]["references"]["reference_data"]:
                external_reference = ExternalReference(
                    source_name=reference["refsource"], url=reference["url"])
                external_references.append(external_reference)

            # Getting the different fields
            description = cves["cve"]["description"]["description_data"][0][
                "value"]
            base_score = (cves["impact"]["baseMetricV3"]["cvssV3"]["baseScore"]
                          if "baseMetricV3" in cves["impact"] else None)
            base_severity = (
                cves["impact"]["baseMetricV3"]["cvssV3"]["baseSeverity"]
                if "baseMetricV3" in cves["impact"] else None)
            attack_vector = (
                cves["impact"]["baseMetricV3"]["cvssV3"]["attackVector"]
                if "baseMetricV3" in cves["impact"] else None)
            integrity_impact = (
                cves["impact"]["baseMetricV3"]["cvssV3"]["integrityImpact"]
                if "baseMetricV3" in cves["impact"] else None)
            availability_impact = (
                cves["impact"]["baseMetricV3"]["cvssV3"]["availabilityImpact"]
                if "baseMetricV3" in cves["impact"] else None)
            cdate = datetime.datetime.strptime(cves["publishedDate"],
                                               "%Y-%m-%dT%H:%MZ")
            mdate = datetime.datetime.strptime(cves["lastModifiedDate"],
                                               "%Y-%m-%dT%H:%MZ")

            # Creating the vulnerability with the extracted fields
            vuln = Vulnerability(
                id=OpenCTIStix2Utils.generate_random_stix_id("vulnerability"),
                name=name,
                created=cdate,
                modified=mdate,
                description=description,
                created_by_ref=author,
                external_references=external_references,
                custom_properties={
                    "x_opencti_base_score": base_score,
                    "x_opencti_base_severity": base_severity,
                    "x_opencti_attack_vector": attack_vector,
                    "x_opencti_integrity_impact": integrity_impact,
                    "x_opencti_availability_impact": availability_impact,
                },
            )
            # Adding the vulnerability to the list of vulnerabilities
            vulnerabilities_bundle.append(vuln)
    # Creating the bundle from the list of vulnerabilities
    bundle = Bundle(vulnerabilities_bundle)
    bundle_json = bundle.serialize()

    # Write to file
    with open(output, "w") as f:
        f.write(bundle_json)
    def _process_overview_report(self, observable, overview_dict, sample_id):
        bundle_objects = []

        # Create external reference
        # Analysis URL
        external_reference = self.helper.api.external_reference.create(
            source_name="Hatching Triage Sandbox Analysis",
            url=f"https://tria.ge/{sample_id}/",
            description="Hatching Triage Sandbox Analysis",
        )
        self.helper.api.stix_cyber_observable.add_external_reference(
            id=observable["id"],
            external_reference_id=external_reference["id"],
        )

        # Create labels from the tags
        if "tags" in overview_dict["analysis"]:
            for tag in overview_dict["analysis"]["tags"]:

                # Set the label color depending on tag type
                # Note: Only certain tags are separated by a colon
                # Those are the tags we are colorizing
                tag_split = tag.split(":")
                tag_value = tag
                label_color = self.default_tag_color
                if len(tag_split) == 2:
                    if "family" == tag_split[0]:
                        label_color = self.family_color
                    elif "botnet" == tag_split[0]:
                        label_color = self.botnet_color
                    elif "campaign" == tag_split[0]:
                        label_color = self.campaign_color
                    tag_value = tag_split[1]

                # Create and add the label
                label = self.helper.api.label.create(value=tag_value, color=label_color)
                self.helper.api.stix_cyber_observable.add_label(
                    id=observable["id"], label_id=label["id"]
                )

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

        # Process extracted key
        extracted_list = overview_dict.get("extracted", [])
        for extracted_dict in extracted_list:

            # Handle config
            if "config" in extracted_dict:

                if "rule" not in extracted_dict["config"]:
                    self.helper.api.log_info("rule key not found, skipping...")
                    continue

                # Create a Note
                config_json = json.dumps(extracted_dict, indent=2)
                config_rule = extracted_dict["config"]["rule"]
                note = Note(
                    abstract=f"{config_rule} Config",
                    content=f"```\n{config_json}\n```",
                    created_by_ref=self.identity,
                    object_refs=[observable["standard_id"]],
                )
                bundle_objects.append(note)

                # Create Observables and Relationships for C2s
                c2_list = extracted_dict.get("config").get("c2", [])
                for c2 in c2_list:
                    # Differentiate between C2 IP and URL
                    parsed = c2.split(":")[0]
                    key = "Url"
                    relationship_type = "communicates-with"
                    if self._is_ipv4_address(parsed):
                        key = "IPv4-Addr"
                    else:
                        parsed = c2
                        relationship_type = "related-to"

                    host_stix = SimpleObservable(
                        id=OpenCTIStix2Utils.generate_random_stix_id(
                            "x-opencti-simple-observable"
                        ),
                        labels=[config_rule, "c2 server"],
                        key=f"{key}.value",
                        value=parsed,
                        created_by_ref=self.identity,
                    )
                    relationship = Relationship(
                        id=OpenCTIStix2Utils.generate_random_stix_id("relationship"),
                        relationship_type=relationship_type,
                        created_by_ref=self.identity,
                        source_ref=observable["standard_id"],
                        target_ref=host_stix.id,
                        allow_custom=True,
                    )
                    bundle_objects.append(host_stix)
                    bundle_objects.append(relationship)

                # Create Observables and Relationships for credentials
                creds_list = extracted_dict.get("config").get("credentials", [])
                for cred_dict in creds_list:
                    host = cred_dict.get("host", None)
                    username = cred_dict.get("username")
                    protocol = cred_dict.get("protocol")

                    if host:
                        # Add Host Observable
                        host_stix = SimpleObservable(
                            id=OpenCTIStix2Utils.generate_random_stix_id(
                                "x-opencti-simple-observable"
                            ),
                            labels=[config_rule, "credentials"],
                            key="X-OpenCTI-Hostname.value",
                            value=host,
                            created_by_ref=self.identity,
                        )

                        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=host_stix.id,
                            allow_custom=True,
                        )

                        bundle_objects.append(host_stix)
                        bundle_objects.append(relationship)

                    if protocol == "smtp" and username:
                        # Add Email Address Observable
                        email_stix = SimpleObservable(
                            id=OpenCTIStix2Utils.generate_random_stix_id(
                                "x-opencti-simple-observable"
                            ),
                            labels=[config_rule, "credentials"],
                            key="Email-Addr.value",
                            value=username,
                            created_by_ref=self.identity,
                        )

                        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=email_stix.id,
                            allow_custom=True,
                        )

                        bundle_objects.append(email_stix)
                        bundle_objects.append(relationship)

                # Download task file, wait for it to become available
                # Give up after 5 tries
                task_id = extracted_dict["tasks"][0]
                filename = extracted_dict["dumped_file"]
                file_contents = self.triage_client.sample_task_file(
                    sample_id, task_id, filename
                )

                for x in range(5):
                    # Sample not yet available, sleep
                    if b"NOT_AVAILABLE" in file_contents[:30]:
                        time.sleep(10)
                        continue

                    file_contents = self.triage_client.sample_task_file(
                        sample_id, task_id, filename
                    )

                if b"NOT_AVAILABLE" in file_contents[:30]:
                    self.helper.api.log_info(
                        "Maximum attempts tried to obtain extracted file, skipping..."
                    )
                    continue

                # Upload task file to OpenCTI
                mime_type = magic.from_buffer(file_contents, mime=True)

                kwargs = {
                    "file_name": f"{sample_id}_{filename}",
                    "data": file_contents,
                    "mime_type": mime_type,
                    "x_opencti_description": f"Extracted file from sample ID {sample_id} and task ID {task_id}.",
                }
                response = self.helper.api.stix_cyber_observable.upload_artifact(
                    **kwargs
                )

                # Create Relationship between original Observable and the extracted
                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"],
                    allow_custom=True,
                )
                bundle_objects.append(relationship)

                # Create and apply labels to extracted file
                label = self.helper.api.label.create(
                    value=config_rule, color=self.family_color
                )
                self.helper.api.stix_cyber_observable.add_label(
                    id=response["id"], label_id=label["id"]
                )
                self.helper.api.stix_cyber_observable.add_label(
                    id=response["id"], label_id=extracted_label["id"]
                )

            # Handle dropper
            if "dropper" in extracted_dict:
                dropper_dict = extracted_dict["dropper"]

                # Create Url Observables and Relationships
                dropper_urls = dropper_dict["urls"]
                for url_dict in dropper_urls:
                    dropper_type = url_dict["type"]
                    url = url_dict["url"]
                    url_stix = SimpleObservable(
                        id=OpenCTIStix2Utils.generate_random_stix_id(
                            "x-opencti-simple-observable"
                        ),
                        labels=[dropper_type],
                        key="Url.value",
                        value=url.rstrip(),
                        created_by_ref=self.identity,
                        object_marking_refs=[TLP_WHITE],
                    )
                    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=url_stix.id,
                        allow_custom=True,
                    )
                    bundle_objects.append(url_stix)
                    bundle_objects.append(relationship)

                    # Create dropper type label
                    self.helper.api.label.create(
                        value=dropper_type, color=self.default_tag_color
                    )

        # Attach domains
        domains = [
            task_dict.get("iocs", {}).get("domains", [])
            for task_dict in overview_dict["targets"]
        ]
        for domain in domains[0]:
            domain_stix = SimpleObservable(
                id=OpenCTIStix2Utils.generate_random_stix_id(
                    "x-opencti-simple-observable"
                ),
                labels=["dynamic"],
                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=observable["standard_id"],
                target_ref=domain_stix.id,
                allow_custom=True,
            )
            bundle_objects.append(domain_stix)
            bundle_objects.append(relationship)

        # Attach IP addresses
        ips = [
            task_dict.get("iocs", {}).get("ips", [])
            for task_dict in overview_dict["targets"]
        ]
        for ip in ips[0]:

            # Filter out non-global and known DNS IPs
            if not ipaddress.ip_address(ip).is_global:
                continue
            if ip in ["8.8.8.8", "8.8.4.4"]:
                continue

            host_stix = SimpleObservable(
                id=OpenCTIStix2Utils.generate_random_stix_id(
                    "x-opencti-simple-observable"
                ),
                labels=["dynamic"],
                key="IPv4-Addr.value",
                value=ip,
                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=observable["standard_id"],
                target_ref=host_stix.id,
                allow_custom=True,
            )
            bundle_objects.append(host_stix)
            bundle_objects.append(relationship)

        # Attach the TTPs
        if "signatures" in overview_dict:
            for signature_dict in overview_dict["signatures"]:

                # Skip any dicts without a ttps key
                if "ttp" not in signature_dict:
                    continue

                name = signature_dict["name"]
                ttps = signature_dict["ttp"]

                for ttp in ttps:

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

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

        # 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"
    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"
Exemple #14
0
 def run(self):
     self.helper.log_info("Fetching URLhaus dataset...")
     while True:
         try:
             # Get the current timestamp and check
             timestamp = int(time.time())
             current_state = self.helper.get_state()
             if current_state is not None and "last_run" in current_state:
                 last_run = current_state["last_run"]
                 self.helper.log_info(
                     "Connector last run: "
                     + datetime.utcfromtimestamp(last_run).strftime(
                         "%Y-%m-%d %H:%M:%S"
                     )
                 )
             else:
                 last_run = None
                 self.helper.log_info("Connector has never run")
             # If the last_run is more than interval-1 day
             if last_run is None or (
                 (timestamp - last_run)
                 > ((int(self.urlhaus_interval) - 1) * 60 * 60 * 24)
             ):
                 self.helper.log_info("Connector will run!")
                 now = datetime.utcfromtimestamp(timestamp)
                 friendly_name = "URLhaus run @ " + now.strftime("%Y-%m-%d %H:%M:%S")
                 work_id = self.helper.api.work.initiate_work(
                     self.helper.connect_id, friendly_name
                 )
                 try:
                     response = urllib.request.urlopen(
                         self.urlhaus_csv_url,
                         context=ssl.create_default_context(cafile=certifi.where()),
                     )
                     image = response.read()
                     with open(
                         os.path.dirname(os.path.abspath(__file__)) + "/data.csv",
                         "wb",
                     ) as file:
                         file.write(image)
                     fp = open(
                         os.path.dirname(os.path.abspath(__file__)) + "/data.csv",
                         "r",
                     )
                     rdr = csv.reader(filter(lambda row: row[0] != "#", fp))
                     bundle_objects = []
                     for row in rdr:
                         if row[3] == "online" or self.urlhaus_import_offline:
                             external_reference = ExternalReference(
                                 source_name="Abuse.ch URLhaus",
                                 url=row[6],
                                 description="URLhaus repository URL",
                             )
                             stix_observable = SimpleObservable(
                                 id=OpenCTIStix2Utils.generate_random_stix_id(
                                     "x-opencti-simple-observable"
                                 ),
                                 key="Url.value",
                                 value=row[2],
                                 description=row[4],
                                 x_opencti_score=80,
                                 object_marking_refs=[TLP_WHITE],
                                 labels=row[5].split(","),
                                 created_by_ref=self.identity["standard_id"],
                                 x_opencti_create_indicator=True,
                                 external_references=[external_reference],
                             )
                             bundle_objects.append(stix_observable)
                     fp.close()
                     bundle = Bundle(objects=bundle_objects).serialize()
                     self.helper.send_stix2_bundle(
                         bundle,
                         entities_types=self.helper.connect_scope,
                         update=self.update_existing_data,
                         work_id=work_id,
                     )
                     if os.path.exists(
                         os.path.dirname(os.path.abspath(__file__)) + "/data.csv"
                     ):
                         os.remove(
                             os.path.dirname(os.path.abspath(__file__)) + "/data.csv"
                         )
                 except Exception as e:
                     self.helper.log_error(str(e))
                 # Store the current timestamp as a last run
                 message = "Connector successfully run, storing last_run as " + str(
                     timestamp
                 )
                 self.helper.log_info(message)
                 self.helper.set_state({"last_run": timestamp})
                 self.helper.api.work.to_processed(work_id, message)
                 self.helper.log_info(
                     "Last_run stored, next run in: "
                     + str(round(self.get_interval() / 60 / 60 / 24, 2))
                     + " days"
                 )
                 time.sleep(60)
             else:
                 new_interval = self.get_interval() - (timestamp - last_run)
                 self.helper.log_info(
                     "Connector will not run, next run in: "
                     + str(round(new_interval / 60 / 60 / 24, 2))
                     + " days"
                 )
                 time.sleep(60)
         except (KeyboardInterrupt, SystemExit):
             self.helper.log_info("Connector stop")
             exit(0)
         except Exception as e:
             self.helper.log_error(str(e))
             time.sleep(60)
 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"
Exemple #16
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"
Exemple #17
0
 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
Exemple #18
0
    def _process_message(self, data):
        file_fetch = data["file_fetch"]
        file_uri = self.helper.opencti_url + file_fetch
        file_name = os.path.basename(file_fetch)
        entity_id = data.get("entity_id", None)
        self.helper.log_info(entity_id)
        # Get context
        is_context = entity_id is not None and len(entity_id) > 0
        self.helper.log_info("Context: {}".format(is_context))
        self.helper.log_info(
            "get_only_contextual: {}".format(self.helper.get_only_contextual())
        )
        if self.helper.get_only_contextual() and not is_context:
            raise ValueError(
                "No context defined, connector is get_only_contextual true"
            )
        self.helper.log_info("Importing the file " + file_uri)
        # Get the file
        file_content = self.helper.api.fetch_opencti_file(file_uri, True)
        # Write the file
        f = open(file_name, "wb")
        f.write(file_content)
        f.close()
        # Parse
        bundle_objects = []
        stix_objects = set()
        i = 0
        custom_indicators = self._get_entities()
        mime_type = self._get_mime_type(file_name)
        print(mime_type)
        if mime_type is None:
            raise ValueError("Invalid file format of {}".format(file_name))

        parser = iocp.IOC_Parser(
            None,
            mime_type,
            True,
            "pdfminer",
            "json",
            custom_indicators=custom_indicators,
        )
        parsed = parser.parse(file_name)
        os.remove(file_name)
        if parsed != []:
            for file in parsed:
                if file != None:
                    for page in file:
                        if page != []:
                            for match in page:
                                resolved_match = self._resolve_match(match)
                                if resolved_match:
                                    # For the creation of relationships
                                    if resolved_match[
                                        "type"
                                    ] not in self.types.values() and self._is_uuid(
                                        resolved_match["value"]
                                    ):
                                        stix_objects.add(resolved_match["value"])
                                    # For CVEs since SimpleObservable doesn't support Vulnerabilities yet
                                    elif resolved_match["type"] == "Vulnerability.name":
                                        vulnerability = Vulnerability(
                                            name=resolved_match["value"]
                                        )
                                        bundle_objects.append(vulnerability)
                                    # Other observables
                                    elif resolved_match["type"] in self.types.values():
                                        observable = SimpleObservable(
                                            id=OpenCTIStix2Utils.generate_random_stix_id(
                                                "x-opencti-simple-observable"
                                            ),
                                            key=resolved_match["type"],
                                            value=resolved_match["value"],
                                            x_opencti_create_indicator=self.create_indicator,
                                        )
                                        bundle_objects.append(observable)
                                    else:
                                        self.helper.log_info(
                                            "Odd data received: {}".format(
                                                resolved_match
                                            )
                                        )
                                    i += 1
        else:
            self.helper.log_error("Could not parse the report!")

        if is_context:
            entity = self.helper.api.stix_domain_object.read(id=entity_id)
            if entity is not None:
                if entity["entity_type"] == "Report" and len(bundle_objects) > 0:
                    report = Report(
                        id=entity["standard_id"],
                        name=entity["name"],
                        description=entity["description"],
                        published=self.helper.api.stix2.format_date(entity["created"]),
                        report_types=entity["report_types"],
                        object_refs=bundle_objects,
                    )
                    bundle_objects.append(report)

        bundles_sent = []
        if len(bundle_objects) > 0:
            bundle = Bundle(objects=bundle_objects).serialize()
            bundles_sent = self.helper.send_stix2_bundle(bundle)

        if len(stix_objects) > 0 and entity_id is not None:
            report = self.helper.api.report.read(id=entity_id)
            if report:
                for stix_object in stix_objects:
                    self.helper.log_info(stix_object)
                    self.helper.api.report.add_stix_object_or_stix_relationship(
                        id=report["id"], stixObjectOrStixRelationshipId=stix_object
                    )

        return "Sent " + str(len(bundles_sent)) + " stix bundle(s) for worker import"