class Observable(models.Model):
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    namespace = models.ManyToManyField('Namespace', blank=True)
    indicators = models.ManyToManyField(Indicator, blank=True)
    compositions = models.ManyToManyField(ObservableComposition, blank=True)
    observable_type = models.CharField(max_length=255, null=True, blank=True)
    observable_id = models.CharField(max_length=255, unique=True)

    def __unicode__(self):
        return u"%s" % (self.name) class Indicator(models.Model):
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    indicator_id = models.CharField(max_length=255)
    namespace = models.ManyToManyField('Namespace', blank=True)
    indicator_types = models.ManyToManyField(Indicator_Type, blank=True)
    confidence = models.ManyToManyField(Confidence, blank=True)
    related_indicators = models.ManyToManyField('self', blank=True)
    indicator_composition_operator = models.CharField(max_length=3, default="OR")
    ttps = models.ManyToManyField('TTP', blank=True)
    produced_time = models.DateTimeField(null=True, blank=True)
    kill_chain_phases = models.ManyToManyField(Indicator_Kill_Chain_Phase, blank=True)

    def __unicode__(self):
        return u"%s" % (self.name) class Indicator_Type(models.Model):
    itype = models.CharField(max_length=255, unique=True)

    def __unicode__(self):
        return u"%s" % (self.itype) class Confidence(models.Model):
    value = models.CharField(max_length=255)
    description = models.TextField(null=True, blank=True)

    def __unicode__(self):
        return u"%s" % (self.value) class ThreatActor(models.Model):
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    namespace = models.ManyToManyField('Namespace', blank=True)
    campaigns = models.ManyToManyField(Campaign, blank=True)
    associated_threat_actors = models.ManyToManyField('self', blank=True)
    threat_actor_id = models.CharField(max_length=255)
    observed_ttps = models.ManyToManyField(TTP, through='ObservedTTP', symmetrical=False, related_name='ttp_observed_at_ta', blank=True)

    def add_observed_ttp(self, ttp, relationship):
        obs_ttp, obs_ttp_created = ObservedTTP.objects.get_or_create(
            ta=self,
            ttp=ttp,
            relationship=relationship
        )
        return obs_ttp

    def __unicode__(self):
        return u"%s" % (self.name) class TA_Alias(models.Model):
    alias = models.CharField(max_length=255)
    namespace = models.ManyToManyField('Namespace', blank=True)
    actor = models.ForeignKey(ThreatActor, on_delete=models.CASCADE)
    alias_type = models.CharField(max_length=255, default='UnofficialName')

    def __unicode__(self):
        return u"%s" % (self.alias)

    class Meta:
        unique_together = (("alias", "actor"),) class TA_Roles(models.Model):
    role = models.CharField(max_length=255)
    actor = models.ForeignKey(ThreatActor, on_delete=models.CASCADE)

    def __unicode__(self):
        return u"%s" % (self.role)

    class Meta:
        unique_together = (("role", "actor"),) class TA_Types(models.Model):
    ta_type = models.CharField(max_length=255)
    actor = models.ForeignKey(ThreatActor, on_delete=models.CASCADE)

    def __unicode__(self):
        return u"%s -> %s" % (self.actor.name, self.ta_type)

    class Meta:
        unique_together = (("ta_type", "actor"),) class Package(models.Model):
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    namespace = models.ManyToManyField('Namespace', blank=True)
    version = models.CharField(max_length=255)
    package_id = models.CharField(max_length=255)
    source = models.CharField(max_length=255)
    produced_time = models.DateTimeField(null=True, blank=True)
    threat_actors = models.ManyToManyField('ThreatActor', blank=True)
    campaigns = models.ManyToManyField('Campaign', blank=True)
    indicators = models.ManyToManyField('Indicator', blank=True)
    observables = models.ManyToManyField('Observable', blank=True)
    ttps = models.ManyToManyField('TTP', blank=True)

    def __unicode__(self):
        return u"%s" % (self.name) class Package_Intent(models.Model):
    intent = models.CharField(max_length=255)
    package = models.ForeignKey(Package, on_delete=models.CASCADE)

    def __unicode__(self):
        return u"%s" % (self.intent) class Package_Reference(models.Model):
    reference = models.CharField(max_length=1024)
    package = models.ForeignKey(Package, on_delete=models.CASCADE)

    def __unicode__(self):
        return u"%s" % (self.reference) class ObservableComposition(models.Model):
    name = models.CharField(max_length=255)
    operator = models.CharField(max_length=3, default='OR')
    indicator = models.ManyToManyField(Indicator, blank=True)
    observables = models.ManyToManyField('Observable', blank=True)
    observable_compositions = models.ManyToManyField('self', blank=True)

    def __unicode__(self):
        return u"%s" % (self.name) class Related_Object(models.Model):
    relationship = models.CharField(max_length=255, default='contains')
    object_one_id = models.IntegerField()
    object_one_type = models.CharField(max_length=255)
    object_two_id = models.IntegerField()
    object_two_type = models.CharField(max_length=255)

    def __unicode__(self):
        return u"%s:%s -> %s:%s" % (self.object_one_id, self.object_one_type, self.object_two_id, self.object_two_type)

    class Meta:
        unique_together = (("relationship", "object_one_id", "object_two_id", "object_one_type", "object_two_type"),)
        index_together = (("object_one_id", "object_one_type"), ("object_two_id", "object_two_type")) class File_Object(models.Model):
    file_meta = models.ManyToManyField(File_Meta_Object, blank=True)
    file_custom = models.ManyToManyField(File_Custom_Properties, blank=True)
    md5_hash = models.CharField(max_length=32, null=True, blank=True)
    sha256_hash = models.CharField(max_length=64, null=True, blank=True)
    observables = models.ManyToManyField(Observable)

    def __unicode__(self):
        if self.md5_hash:
            return u"%s" % (self.md5_hash)
        elif self.sha256_hash:
            return u"%s" % (self.sha256_hash)
        else:
            return u"File Object"

    class Meta:
        index_together = (("md5_hash", "sha256_hash"),) class File_Meta_Object(models.Model):
    file_name = models.CharField(max_length=255, null=True, blank=True)
    file_path = models.CharField(max_length=255, null=True, blank=True)
    file_extension = models.CharField(max_length=255, null=True, blank=True)
    file_size = models.IntegerField(default=0)

    def __unicode__(self):
        if self.file_name:
            return u"%s" % (self.file_name)
        else:
            return u"File Meta Object"

    class Meta:
        unique_together = (("file_name", "file_path", "file_extension", "file_size"),) class File_Custom_Properties(models.Model):
    property_name = models.CharField(max_length=255, null=True, blank=True)
    property_value = models.CharField(max_length=255, null=True, blank=True)

    def __unicode__(self):
        return u"%s - %s" % (self.property_name, self.property_value)

    class Meta:
        unique_together = (("property_name", "property_value"),) class URI_Object(models.Model):
    uri_value = models.CharField(max_length=255)
    uri_type = models.CharField(max_length=255)
    condition = models.CharField(max_length=255, default="equals")
    observables = models.ManyToManyField(Observable)

    def __unicode__(self):
        if self.uri_value:
            return u"%s" % (self.uri_value)
        else:
            return u"URI Object"

    class Meta:
        unique_together = (("uri_value", "uri_type", "condition"),) class Address_Object(models.Model):
    address_value = models.CharField(max_length=255)
    category = models.CharField(max_length=255, default="ipv4-addr")
    condition = models.CharField(max_length=255, default="equals")
    observables = models.ManyToManyField(Observable)

    def __unicode__(self):
        if self.address_value:
            return u"%s" % (self.address_value)
        else:
            return u"Address Object"

    class Meta:
        unique_together = (("address_value", "category", "condition"),) class Mutex_Object(models.Model):
    mutex_name = models.CharField(max_length=255)
    condition = models.CharField(max_length=255, default="equals")
    observables = models.ManyToManyField(Observable)

    def __unicode__(self):
        if self.mutex_name:
            return u"%s" % (self.mutex_name)
        else:
            return u"Mutex Object"

    class Meta:
        unique_together = (("mutex_name", "condition"),) class Code_Object(models.Model):
    custom_value = models.CharField(max_length=255)
    custom_condition = models.CharField(max_length=255, default="equals")
    purpose = models.CharField(max_length=255, null=True, blank=True)
    code_language = models.CharField(max_length=255, null=True, blank=True)
    code_segment = models.TextField(null=True, blank=True)
    observables = models.ManyToManyField(Observable)

    def __unicode__(self):
        if self.custom_value:
            return u"%s" % (self.custom_value)
        else:
            return u"Code Object"

    class Meta:
        unique_together = (("custom_value", "custom_condition"),) class Driver_Object(models.Model):
    driver_name = models.CharField(max_length=255)
    condition = models.CharField(max_length=255, default="contains")
    observables = models.ManyToManyField(Observable)

    def __unicode__(self):
        if self.driver_name:
            return u"%s" % (self.driver_name)
        else:
            return u"Driver Object"

    class Meta:
        unique_together = (("driver_name", "condition"),) class Link_Object(models.Model):
    link = models.CharField(max_length=1024)
    link_type = models.CharField(max_length=255)
    url_label = models.CharField(max_length=1024)
    condition = models.CharField(max_length=255, default="contains")
    observables = models.ManyToManyField(Observable)

    def __unicode__(self):
        if self.link:
            return u"%s" % (self.link)
        elif self.url_label:
            return u"%s" % (self.url_label)
        else:
            return u"Link Object"

    class Meta:
        unique_together = (("link", "url_label", "condition", "link_type"),) class Win_Registry_Object(models.Model):
    key = models.CharField(max_length=1024)
    hive = models.CharField(max_length=255)
    data = models.CharField(max_length=1024)
    data_name = models.CharField(max_length=255)
    observables = models.ManyToManyField(Observable)

    def __unicode__(self):
        if self.key and self.hive:
            return u"%s - %s" % (self.hive, self.key)
        elif self.key:
            return u"%s" % (self.key)
        else:
            return u"Registry Observable"

    class Meta:
        unique_together = (("key", "hive", "data", "data_name"),) class EmailMessage_Object(models.Model):
    raw_body = models.TextField(null=True, blank=True)
    raw_header = models.TextField(null=True, blank=True)
    subject = models.CharField(max_length=255, null=True, blank=True)
    sender = models.ManyToManyField(EmailMessage_sender, blank=True)
    from_string = models.ManyToManyField(EmailMessage_from, blank=True)
    recipients = models.ManyToManyField(EmailMessage_recipient, blank=True)
    recipients_cc = models.ManyToManyField(EmailMessage_recipient_cc, blank=True)
    recipients_bcc = models.ManyToManyField(EmailMessage_recipient_bcc, blank=True)
    links = models.ManyToManyField(EmailMessage_link, blank=True)
    attachments = models.ManyToManyField(File_Object, blank=True)
    email_date = models.DateTimeField(null=True, blank=True)
    message_id = models.CharField(max_length=255, null=True, blank=True)
    content_type = models.CharField(max_length=255, null=True, blank=True)
    mime_version = models.CharField(max_length=255, null=True, blank=True)
    user_agent = models.CharField(max_length=255, null=True, blank=True)
    x_mailer = models.CharField(max_length=255, null=True, blank=True)
    observables = models.ManyToManyField(Observable)

    def __unicode__(self):
        if self.subject:
            return u"%s" % (self.subject)
        else:
            return u"EmailMessage Object"

    class Meta:
        unique_together = (("raw_body", "raw_header", "subject", "message_id", "x_mailer", "user_agent", "mime_version", "content_type", "email_date"),) class EmailMessage_from(models.Model):
    sender = models.CharField(max_length=255, unique=True)
    is_spoofed = models.BooleanField(default=False)
    condition = models.CharField(max_length=255, default="equals") class EmailMessage_recipient(models.Model):
    recipient = models.CharField(max_length=255, unique=True)
    is_spoofed = models.BooleanField(default=False)
    condition = models.CharField(max_length=255, default="equals") class HTTPSession_Object(models.Model):
    client_request = models.ForeignKey(HTTPClientRequest, null=True, blank=True, on_delete=models.CASCADE)
    # http server response not implemented
    observables = models.ManyToManyField(Observable) class HTTPClientRequest(models.Model):
    raw_header = models.TextField(null=True, blank=True)
    message_body = models.TextField(null=True, blank=True)
    request_method = models.CharField(max_length=10, null=True, blank=True)
    request_uri = models.CharField(max_length=1024, null=True, blank=True)
    request_version = models.CharField(max_length=10, null=True, blank=True)
    user_agent = models.CharField(max_length=255, null=True, blank=True)
    domain_name = models.ForeignKey(URI_Object, null=True, blank=True, on_delete=models.CASCADE)
    port = models.ForeignKey(Port_Object, null=True, blank=True, on_delete=models.CASCADE)

    def __unicode__(self):
        if self.request_uri and self.domain_name:
            return u"%s" % (self.request_uri)
        else:
            return u"HTTPClientRequest Object" class DNSQuery_Object(models.Model):
    successful = models.BooleanField(default=False)
    question = models.ForeignKey(DNSQuestion, on_delete=models.CASCADE)
    observables = models.ManyToManyField(Observable) class DNSQuestion(models.Model):
    qname = models.ForeignKey(URI_Object, on_delete=models.CASCADE)
    qtype = models.CharField(max_length=255, null=True, blank=True)
    qclass = models.CharField(max_length=255, null=True, blank=True)

    def __unicode__(self):
        return u"%s" % (self.qname.uri_value) class TTP(models.Model):
    """ Tools, Tactics, and Procedures
    """
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    namespace = models.ManyToManyField('Namespace', blank=True)
    ttp_id = models.CharField(max_length=255)
    related_ttps = models.ManyToManyField('self', through='RelatedTTP', symmetrical=False, related_name='ttp_related_to_ttp', blank=True)

    def add_related_ttp(self, ttp, relationship):
        rel_ttp, rel_ttp_created = RelatedTTP.objects.get_or_create(from_ttp=self, to_ttp=ttp, relationship=relationship)
        return rel_ttp

    def __unicode__(self):
        return u"%s" % (self.name) class RelatedTTP(models.Model):
    from_ttp = models.ForeignKey(TTP, related_name='from_ttp', on_delete=models.CASCADE)
    to_ttp = models.ForeignKey(TTP, related_name='to_ttp', on_delete=models.CASCADE)
    relationship = models.CharField(max_length=255) class MalwareInstance(models.Model):
    ttp_ref = models.ForeignKey(TTP, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)

    def __unicode__(self):
        return u"%s" % (self.name) class MalwareInstanceNames(models.Model):
    instance_ref = models.ForeignKey(MalwareInstance, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)

    def __unicode__(self):
        return u"%s" % (self.name) class MalwareInstanceTypes(models.Model):
    instance_ref = models.ForeignKey(MalwareInstance, on_delete=models.CASCADE)
    _type = models.CharField(max_length=255)

    def __unicode__(self):
        return u"%s" % (self._type) class AttackPattern(models.Model):
    ttp_ref = models.ForeignKey(TTP, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    capec_id = models.CharField(max_length=255) class Campaign(models.Model):
    name = models.CharField(max_length=255)
    creation_time = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.CharField(max_length=255, null=True, blank=True)
    namespace = models.ManyToManyField('Namespace', blank=True)
    status = models.CharField(max_length=255, default='Ongoing')
    campaign_id = models.CharField(max_length=255)
    confidence = models.ManyToManyField(Confidence, blank=True)
    related_indicators = models.ManyToManyField('Indicator', blank=True)
    related_ttps = models.ManyToManyField(TTP, through='RelationCampaignTTP', symmetrical=False, related_name='ttp_related_to_campaign', blank=True)
    associated_campaigns = models.ManyToManyField('self', blank=True)

    def add_related_ttp(self, ttp, relationship):
        rel_ttp, rel_ttp_created = RelationCampaignTTP.objects.get_or_create(
            campaign=self,
            ttp=ttp,
            relationship=relationship
        )
        return rel_ttp

    def __unicode__(self):
        return u"%s" % (self.name) class RelationCampaignTTP(models.Model):
    campaign = models.ForeignKey(Campaign, on_delete=models.CASCADE)
    ttp = models.ForeignKey(TTP, on_delete=models.CASCADE)
    relationship = models.CharField(max_length=255) class Namespace(models.Model):
    namespace = models.CharField(max_length=255, default='nospace', unique=True)
    description = models.TextField(null=True, blank=True)

    def __unicode__(self):
        return u"%s" % (self.namespace)

    class Meta:
        ordering = ['namespace'] class Indicator_Kill_Chain_Phase(models.Model):
    name = models.CharField(max_length=255, unique=True)
    ordinality = models.IntegerField(null=True, blank=True)

    def __unicode__(self):
        return u"%s" % (self.name) class WindowsExecutable_Object(models.Model):
    pe_type = models.CharField(max_length=255, default="executable")
    object_id = models.CharField(max_length=255)
    imports = models.ManyToManyField(PEImports)
    exports = models.ManyToManyField(PEExports)
    sections = models.ManyToManyField(PESections)
    observables = models.ManyToManyField(Observable) class PEImports(models.Model):
    file_name = models.CharField(max_length=255)
    virtual_address = models.CharField(max_length=255, null=True, blank=True)
    imported_functions = models.ManyToManyField(ImportedFunction) class ImportedFunction(models.Model):
    function_name = models.CharField(max_length=255)
    virtual_address = models.CharField(max_length=255, null=True, blank=True) class PEExports(models.Model):
    name = models.CharField(max_length=255)
    exported_functions = models.ManyToManyField(ExportedFunction) class ExportedFunction(models.Model):
    function_name = models.CharField(max_length=255)
    entry_point = models.CharField(max_length=255, null=True, blank=True) class PESections(models.Model):
    section_name = models.CharField(max_length=255)
    entropy = models.FloatField(null=True, blank=True)
    virtual_size = models.CharField(max_length=255, null=True, blank=True)
    virtual_address = models.CharField(max_length=255, null=True, blank=True)
    size_of_raw_data = models.CharField(max_length=255, null=True, blank=True) def handle_file_object(file_obj):
    """extract all relevant information from a cybox file object
    @file_obj: cybox file object in json format
    returns: dictionary with file object information
    """
    file_custom_properties_lst = []
    file_meta_dict = {
        'file_name': 'No Name',
        'file_extension': 'No Extension',
        'file_path': 'No Path',
        'file_size': 0
    }
    file_dict = {
        'md5_hash': 'No MD5',
        'sha256_hash': 'No SHA256'
    }
    # extract custom properties
    if 'custom_properties' in file_obj:
        for prop in file_obj['custom_properties']:
            property_dict = {
                'property_name': prop['name'],
                'property_value': prop['value']
            }
            file_custom_properties_lst.append(property_dict)
    # extract meta information
    if 'file_name' in file_obj:
        if isinstance(file_obj['file_name'], dict):
            file_meta_dict['file_name'] = file_obj['file_name'].get('value', 'No Name')
        else:
            file_meta_dict['file_name'] = file_obj['file_name']
    if 'file_path' in file_obj:
        if isinstance(file_obj['file_path'], dict):
            file_meta_dict['file_path'] = file_obj['file_path'].get('value', 'No Path')
        else:
            file_meta_dict['file_path'] = file_obj['file_path']
    if 'file_extension' in file_obj:
        if file_obj['file_extension'].startswith('.'):
            file_meta_dict['file_extension'] = file_obj['file_extension'][1:]
        else:
            file_meta_dict['file_extension'] = file_obj['file_extension']
    if 'size_in_bytes' in file_obj:
        if isinstance(file_obj['size_in_bytes'], dict):
            size_value = file_obj['size_in_bytes'].get('value', 0)
            if isinstance(size_value, (tuple, list, dict, set)):
                # ignore size in between items, too unspecific
                pass
            else:
                file_meta_dict['file_size'] = size_value
        else:
            file_meta_dict['file_size'] = int(file_obj['size_in_bytes'])
    # extract MD5 and SHA256 from Object
    if 'hashes' in file_obj:
        for hash_dict in file_obj['hashes']:
            if isinstance(hash_dict['type'], dict):
                if hash_dict['type']['value'] == 'MD5':
                    if 'value' in hash_dict['simple_hash_value']:
                        file_dict['md5_hash'] = hash_dict['simple_hash_value']['value'].lower()
                    else:
                        file_dict['md5_hash'] = hash_dict['simple_hash_value'].lower()
                elif hash_dict['type']['value'] == 'SHA256':
                    if 'value' in hash_dict['simple_hash_value']:
                        file_dict['sha256_hash'] = hash_dict['simple_hash_value']['value'].lower()
                    else:
                        file_dict['sha256_hash'] = hash_dict['simple_hash_value'].lower()
            else:
                if hash_dict['type'] == 'MD5':
                    if 'value' in hash_dict['simple_hash_value']:
                        file_dict['md5_hash'] = hash_dict['simple_hash_value']['value'].lower()
                    else:
                        file_dict['md5_hash'] = hash_dict['simple_hash_value'].lower()
                elif hash_dict['type'] == 'SHA256':
                    if 'value' in hash_dict['simple_hash_value']:
                        file_dict['sha256_hash'] = hash_dict['simple_hash_value']['value'].lower()
                    else:
                        file_dict['sha256_hash'] = hash_dict['simple_hash_value'].lower()
    return file_dict, file_meta_dict, file_custom_properties_lst def handle_uri_object(uri_obj):
    """extract all relevant information from a cybox uri object
    @uri_obj: cybox uri object in json format
    returns: dictionary with uri object information
    """
    uri_dict = {
        'uri_value': 'No Value',
        'uri_type': 'No Type',
        'condition': 'equals'
    }
    uri_dict['uri_type'] = uri_obj.get('type', 'Domain Name')
    if 'value' in uri_obj and isinstance(uri_obj['value'], (tuple, list, dict, set)):
        uri_dict['uri_value'] = uri_obj['value'].get('value', 'No Value')
        uri_dict['condition'] = uri_obj['value'].get('condition', 'equals').lower()
    else:
        uri_dict['uri_value'] = uri_obj.get('value', 'No Value')
        uri_dict['condition'] = 'equals'
    return uri_dict def handle_address_object(adr_obj):
    """extract all relevant information from a cybox address object
    @adr_obj: cybox address object in json format
    returns: a list of dictionaries containing address object information
    """
    address_list = []
    if 'address_value' in adr_obj and isinstance(adr_obj['address_value'], (tuple, list, dict, set)):
        address_value = adr_obj['address_value'].get('value', 'NotSet')
        if isinstance(address_value, (tuple, list, dict, set)):
            for item in address_value:
                adr_dict = {
                    'address_value': 'No Address',
                    'category': 'ipv4-addr',
                    'condition': 'equals'
                }
                adr_dict['address_value'] = item
                adr_dict['category'] = adr_obj.get('category', 'ipv4-addr')
                adr_dict['condition'] = adr_obj['address_value'].get('condition', 'equals').lower()
                address_list.append(adr_dict)
            return address_list
        else:
            adr_dict = {
                'address_value': 'No Address',
                'category': 'ipv4-addr',
                'condition': 'equals'
            }
            adr_dict['address_value'] = adr_obj['address_value'].get('value', 'No Address')
            adr_dict['category'] = adr_obj.get('category', 'ipv4-addr')
            adr_dict['condition'] = adr_obj['address_value'].get('condition', 'equals').lower()
            return [adr_dict]
    else:
        adr_dict = {
            'address_value': 'No Address',
            'category': 'ipv4-addr',
            'condition': 'equals'
        }
        adr_dict['address_value'] = adr_obj['address_value']
        adr_dict['category'] = adr_obj.get('category', 'ipv4-addr')
        adr_dict['condition'] = 'equals'
        return [adr_dict]
    return [] def handle_mutex_object(mu_obj):
    """extract all relevant information from a cybox mutex object
    @mu_obj: cybox mutex object in json format
    returns: a dictionary containing mutex object information
    """
    mutex_dict = {
        'mutex_name': 'No Mutex',
        'condition': 'equals'
    }
    if 'name' in mu_obj and isinstance(mu_obj['name'], (tuple, list, dict, set)):
        mutex_dict['mutex_name'] = mu_obj['name'].get('value', 'No Mutex')
        mutex_dict['condition'] = mu_obj['name'].get('condition', 'equals').lower()
    else:
        mutex_dict['mutex_name'] = mu_obj['name']
        mutex_dict['condition'] = 'equals'
    return mutex_dict def handle_code_object(co_obj):
    """extract all relevant information from a cybox code object
    @co_obj: cybox code object in json format
    returns: a list of dictionaries containing code object information
    """
    code_list = []
    if 'custom_properties' in co_obj:
        for custom_property in co_obj['custom_properties']:
            code_dict = {
                'custom_value': 'No Value',
                'custom_condition': 'equals',
                'purpose': 'No Purpose',
                'code_language': 'No Language',
                'code_segment': 'No Segment'
            }
            code_dict['custom_value'] = custom_property.get('value', 'No Value')
            code_dict['custom_condition'] = custom_property.get('condition', 'equals').lower()
            code_dict['code_segment'] = co_obj.get('code_segment', 'No Segment')
            code_dict['code_language'] = co_obj.get('code_language', 'No Language')
            code_dict['purpose'] = co_obj.get('purpose', 'No Purpose')
            code_list.append(code_dict)
    return code_list def handle_driver_object(dr_obj):
    """extract all relevant information from a cybox driver object
    @co_obj: cybox driver object in json format
    returns: a dictionaries containing driver object information
    """
    driver_dict = {
        'driver_name': 'No Name',
        'condition': 'equals'
    }
    if 'driver_name' in dr_obj:
        driver_dict['driver_name'] = dr_obj['driver_name'].get('value', 'No Name')
        driver_dict['condition'] = dr_obj['driver_name'].get('condition', 'equals').lower()
    return driver_dict def handle_link_object(li_obj):
    """extract all relevant information from a cybox link object
    @co_obj: cybox link object in json format
    returns: a dictionaries containing link object information
    """
    link_dict = {
        'link': 'No Link',
        'link_type': 'No Type',
        'url_label': 'No Label',
        'condition': 'equals'
    }
    if 'value' in li_obj:
        if isinstance(li_obj['value'], dict):
            link_dict['link'] = li_obj['value'].get('value', 'No Link')
            link_dict['condition'] = li_obj['value'].get('condition', 'equals').lower()
    if 'url_label' in li_obj:
        if isinstance(li_obj['url_label'], dict):
            link_dict['url_label'] = li_obj['url_label'].get('value', 'No Label')
    if 'type' in li_obj:
        link_dict['link_type'] = li_obj.get('type', 'No Type')
    return link_dict def handle_win_registry_object(re_obj):
    """extract all relevant information from a cybox windows registry object
    @re_obj: cybox windows registry object in json format
    returns: a dictionaries containing windows registry object information
    """
    reg_list = []
    if 'values' in re_obj:
        for item in re_obj['values']:
            reg_dict = {
                'key': 'No Key',
                'hive': 'No Hive',
                'data': 'No Data',
                'data_name': ' No Data Name'
            }
            if 'data' in item:
                if isinstance(item['data'], dict):
                    reg_dict['data'] = item['data'].get('value', 'No Data')
                else:
                    reg_dict['data'] = item['data']
            if 'name' in item:
                if isinstance(item['name'], dict):
                    reg_dict['data_name'] = item['name'].get('value', 'No Data Name')
                else:
                    reg_dict['data_name'] = item['name']
            if 'hive' in re_obj:
                if isinstance(re_obj['hive'], dict):
                    reg_dict['hive'] = re_obj['hive'].get('value', 'No Hive')
            if 'key' in re_obj:
                if isinstance(re_obj['key'], dict):
                    reg_dict['key'] = re_obj['key'].get('value', 'No Key')
            reg_list.append(reg_dict)
    else:
        reg_dict = {
            'key': 'No Key',
            'hive': 'No Hive',
            'data': 'No Data',
            'data_name': ' No Data Name'
        }
        if 'key' in re_obj:
            if isinstance(re_obj['key'], dict):
                reg_dict['key'] = re_obj['key'].get('value', 'No Key')
        if 'hive' in re_obj:
            if isinstance(re_obj['hive'], dict):
                reg_dict['hive'] = re_obj['hive'].get('value', 'No Hive')
        reg_list.append(reg_dict)
    return reg_list def handle_email_object(email_obj):
    """extract all relevant information from a cybox email object
    @email_obj: cybox email object in json format
    returns: dictionary with email object information
    """
    email_dict = {
        'raw_body': 'No Raw Body',
        'raw_header': 'No Raw Header',
        'subject': 'No Subject',
        'email_date': None,
        'message_id': 'No Message ID',
        'content_type': 'No Content Type',
        'mime_version': 'No Mime Version',
        'user_agent': 'No User Agent',
        'x_mailer': 'No X-Mailer',
        'attachments': [],
        'from': None,
        'to': []
    }
    if 'attachments' in email_obj and isinstance(email_obj['attachments'], list):
        for item in email_obj['attachments']:
            if 'object_reference' in item:
                email_dict['attachments'].append(item['object_reference'])
    if 'raw_body' in email_obj:
        email_dict['raw_body'] = email_obj['raw_body']
    if 'raw_header' in email_obj:
        email_dict['raw_header'] = email_obj['raw_header']
    if 'header' in email_obj:
        if 'subject' in email_obj['header']:
            if isinstance(email_obj['header']['subject'], dict):
                email_dict['subject'] = email_obj['header']['subject'].get('value', 'No Subject')
            else:
                email_dict['subject'] = email_obj['header']['subject']
        if 'message_id' in email_obj['header']:
            if isinstance(email_obj['header']['message_id'], dict):
                email_dict['message_id'] = email_obj['header']['message_id'].get('value', 'No Message ID')
            else:
                email_dict['message_id'] = email_obj['header']['message_id']
        if 'content_type' in email_obj['header']:
            if isinstance(email_obj['header']['content_type'], dict):
                email_dict['content_type'] = email_obj['header']['content_type'].get('value', 'No Content Type')
            else:
                email_dict['content_type'] = email_obj['header']['content_type']
        if 'date' in email_obj['header']:
            datetime_object = dateutil.parser.parse(email_obj['header']['date'])
            # add UTC timezone if timezone information is missing
            if not datetime_object.tzinfo:
                datetime_object = datetime_object.replace(tzinfo=pytz.utc)
            email_dict['email_date'] = datetime_object
        if 'mime_version' in email_obj['header']:
            if isinstance(email_obj['header']['mime_version'], dict):
                email_dict['mime_version'] = email_obj['header']['mime_version'].get('value', 'No Mime Version')
            else:
                email_dict['mime_version'] = email_obj['header']['mime_version']
        if 'x_mailer' in email_obj['header']:
            if isinstance(email_obj['header']['x_mailer'], dict):
                email_dict['x_mailer'] = email_obj['header']['x_mailer'].get('value', 'No X-Mailer')
            else:
                email_dict['x_mailer'] = email_obj['header']['x_mailer']
        if 'user_agent' in email_obj['header']:
            if isinstance(email_obj['header']['user_agent'], dict):
                email_dict['user_agent'] = email_obj['header']['user_agent'].get('value', 'No User Agent')
            else:
                email_dict['user_agent'] = email_obj['header']['user_agent']
        if 'from' in email_obj['header'] and 'address_value' in email_obj['header']['from']:
            email_from_dict = {
                'sender': 'No Sender',
                'is_spoofed': False,
                'condition': 'equals'
            }
            if isinstance(email_obj['header']['from']['address_value'], dict):
                from_string = email_obj['header']['from']['address_value'].get('value', None)
                if from_string:
                    email_from_dict['sender'] = from_string
                    email_from_dict['condition'] = email_obj['header']['from']['address_value'].get('condition', 'equals').lower()
                    email_from_dict['is_spoofed'] = email_obj['header']['from']['address_value'].get('is_spoofed', False)
            else:
                email_from_dict['sender'] = email_obj['header']['from']['address_value']
            email_dict['from'] = email_from_dict
        if 'to' in email_obj['header'] and isinstance(email_obj['header']['to'], list):
            for item in email_obj['header']['to']:
                if 'address_value' in item:
                    email_rec_dict = {
                        'recipient': 'No recipient',
                        'is_spoofed': False,
                        'condition': 'equals'
                    }
                    if isinstance(item['address_value'], dict):
                        recipient_string = item['address_value'].get('value', None)
                        if recipient_string:
                            email_rec_dict['recipient'] = recipient_string
                            email_rec_dict['condition'] = item['address_value'].get('condition', 'equals').lower()
                            email_rec_dict['is_spoofed'] = item['address_value'].get('is_spoofed', False)
                    else:
                        email_rec_dict['recipient'] = item['address_value']
                    email_dict['to'].append(email_rec_dict)
    return email_dict def handle_http_session_object(http_obj):
    """extract relevant information from a cybox http session object
    @http_obj: cybox http session object in json format
    returns: list of dictionaries
    """
    client_dict_list = []
    if 'http_request_response' in http_obj:
        for request in http_obj['http_request_response']:
            client_dict = {
                'raw_header': None,
                'message_body': None,
                'request_method': 'GET',
                'request_uri': '/',
                'request_version': '1.1',
                'user_agent': None,
                'domain_name': None,
                'port': None,
            }
            # get message body
            if 'http_client_request' in request and 'http_message_body' in request['http_client_request']:
                client_dict['message_body'] = request['http_client_request']['http_message_body'].get('message_body', None)
            # get raw header
            if 'http_client_request' in request and 'http_request_header' in request['http_client_request']:
                client_dict['raw_header'] = request['http_client_request']['http_request_header'].get('raw_header', None)
                # get host information
                if 'parsed_header' in request['http_client_request']['http_request_header']:
                    host = request['http_client_request']['http_request_header']['parsed_header'].get('host', None)
                    if host:
                        if 'domain_name' in host:
                            uri_dict = {
                                'uri_value': host['domain_name'].get('value', 'No Value'),
                                'uri_type': 'Domain Name',
                                'condition': 'equals'
                            }
                            uri_object, uri_object_created = URI_Object.objects.get_or_create(**uri_dict)
                            client_dict['domain_name'] = uri_object
                        if 'port' in host:
                            port_dict = {
                                'port': host['port'].get('port_value', 'No Value')
                            }
                            port_object, port_object_created = Port_Object.objects.get_or_create(**port_dict)
                            client_dict['port'] = port_object
                    # get user agent information
                    user_agent_value = request['http_client_request']['http_request_header']['parsed_header'].get('user_agent', None)
                    if isinstance(user_agent_value, dict):
                        client_dict['user_agent'] = user_agent_value['value']
                    else:
                        client_dict['user_agent'] = user_agent_value
            if 'http_client_request' in request and 'http_request_line' in request['http_client_request']:
                client_dict['request_method'] = request['http_client_request']['http_request_line'].get('http_method', 'GET')
                client_dict['request_uri'] = request['http_client_request']['http_request_line'].get('value', '/')
                client_dict['request_version'] = request['http_client_request']['http_request_line'].get('version', '1.1')
            client_dict_list.append(client_dict)
    return client_dict_list def handle_dns_query_object(dns_obj):
    query_dict = {
        'qname': None,
        'qtype': None,
        'qclass': None,
    }
    if 'question' in dns_obj:
        query_dict['qclass'] = dns_obj['question'].get('qclass', None)
        query_dict['qtype'] = dns_obj['question'].get('qtype', None)
        qname = dns_obj['question'].get('qname', None)
        if isinstance(qname, dict):
            uri_dict = {
                'uri_value': qname.get('value', 'No Value'),
                'uri_type': 'Domain Name',
                'condition': 'equals'
            }
        else:
            uri_dict = {
                'uri_value': qname,
                'uri_type': 'Domain Name',
                'condition': 'equals'
            }
        uri_object, uri_object_created = URI_Object.objects.get_or_create(**uri_dict)
        query_dict['qname'] = uri_object
    return query_dict def handle_windows_executable_object(ex_obj, ex_obj_id):
    """extract all relevant information from a cybox windows executable object
    @ex_obj: cybox windows executable object in json format
    returns: a dictionary containing windows executable object information
    """
    #print json.dumps(ex_obj, indent=4, sort_keys=True)
    executable_dict = {
        'pe_type': 'executable',
        'object_id': ex_obj_id,
        'imports': [],
        'exports': [],
        'sections': []
    }
    if 'imports' in ex_obj:
        for imp in ex_obj['imports']:
            imports_dict = {'file_name': None, 'virtual_address': None, 'imported_functions': []}
            imports_dict['file_name'] = imp.get('file_name', None)
            for impfunction in imp['imported_functions']:
                imports_dict['imported_functions'].append({'function_name': impfunction.get('function_name', 'None'), 'virtual_address': impfunction.get('virtual_address', None)})
            executable_dict['imports'].append(imports_dict)
    if 'exports' in ex_obj:
        for emp in ex_obj['exports']:
            exports_dict = {'name': None, 'exported_functions': []}
            exports_dict['name'] = emp.get('name', None)
            for empfunction in emp['exported_functions']:
                exports_dict['exported_functions'].append({'function_name': empfunction.get('function_name', 'None'), 'entry_point': empfunction.get('entry_point', 'None')})
            executable_dict['exports'].append(exports_dict)
    if 'sections' in ex_obj:
        for section in ex_obj['sections']:
            sections_dict = {'section_name': 'None', 'entropy': None, 'virtual_size': None, 'virtual_address': None, 'size_of_raw_data': None}
            if 'entropy' in section:
                sections_dict['entropy'] = section['entropy'].get('value', 0.0)
            if 'section_header' in section:
                sections_dict['section_name'] = section['section_header'].get('name', 'None')
                sections_dict['virtual_size'] = section['section_header'].get('virtual_size', None)
                sections_dict['virtual_address'] = section['section_header'].get('virtual_address', None)
                sections_dict['size_of_raw_data'] = section['section_header'].get('size_of_raw_data', None)
            executable_dict['sections'].append(sections_dict)
    return executable_dict
import sys, json, re, pytz, os, time, shutil
from dateutil.parser import parse as date_parser
from django.core.management.base import BaseCommand, CommandError
from django.conf import settings
from stix.utils.parser import EntityParser
from kraut_parser.models import Observable, Indicator, Indicator_Type, Confidence, ThreatActor, TA_Alias, TA_Roles, TA_Types, Package, Package_Intent, Package_Reference, ObservableComposition
from kraut_parser.models import Related_Object, File_Object, File_Meta_Object, File_Custom_Properties, URI_Object, Address_Object, Mutex_Object, Code_Object, Driver_Object, Link_Object, Win_Registry_Object, EmailMessage_Object, EmailMessage_from, EmailMessage_recipient, HTTPSession_Object, HTTPClientRequest, DNSQuery_Object, DNSQuestion
from kraut_parser.models import TTP, RelatedTTP, MalwareInstance, MalwareInstanceNames, MalwareInstanceTypes, AttackPattern
from kraut_parser.models import Campaign, RelationCampaignTTP
from kraut_parser.models import Namespace, Indicator_Kill_Chain_Phase
from kraut_parser.models import WindowsExecutable_Object, PEImports, ImportedFunction, PEExports, ExportedFunction, PESections
from kraut_parser.cybox_functions import handle_file_object, handle_uri_object, handle_address_object, handle_mutex_object, handle_code_object, handle_driver_object, handle_link_object, handle_win_registry_object, handle_email_object, handle_http_session_object, handle_dns_query_object
from kraut_parser.cybox_functions import handle_windows_executable_object
                from lxml import etree
                from io import StringIO
        self.stdout.write('--> performing version check ... ', ending='')
        sys.stdout.flush()
        if 'version' in stix_json:
            if not self.__check_version(stix_json['version']):
                self.stdout.write('found %s ... [FAIL]' % (stix_json['version']))
                return False
        else:
            self.stdout.write('not found ... [FAIL]')
            return False
        self.stdout.write('found %s ... [DONE]' % (stix_json['version']))
        return True

    def get_database_object(self, object_id, object_type):
        """get the corresponding database entry for the given object id and type
        @object_id: id of the database entry to retrieve
        @object_type: type of the object that we want to retrieve
        returns: database object of the requested type and id
        """
        db_object = None
        if object_type == 'FileObjectType':
            db_object = File_Object.objects.get(id=object_id)
        elif object_type == 'URIObjectType' or object_type == 'DomainNameObjectType':
            db_object = URI_Object.objects.get(id=object_id)
        elif object_type == 'AddressObjectType':
            db_object = Address_Object.objects.get(id=object_id)
        elif object_type == 'MutexObjectType':
            db_object = Mutex_Object.objects.get(id=object_id)
        elif object_type == 'CodeObjectType':
            db_object = Code_Object.objects.get(id=object_id)
        elif object_type == 'WindowsDriverObjectType':
            db_object = Driver_Object.objects.get(id=object_id)
        elif object_type == 'LinkObjectType':
            db_object = Link_Object.objects.get(id=object_id)
        elif object_type == 'WindowsRegistryKeyObjectType':
            db_object = Win_Registry_Object.objects.get(id=object_id)
        elif object_type == 'EmailMessageObjectType':
            db_object = EmailMessage_Object.objects.get(id=object_id)
        elif object_type == 'HTTPSessionObjectType':
            db_object = HTTPSession_Object.objects.get(id=object_id)
        elif object_type == 'DNSQueryObjectType':
            db_object = DNSQuery_Object.objects.get(id=object_id)
        elif object_type == 'WindowsExecutableFileObjectType':
            db_object = WindowsExecutable_Object.objects.get(id=object_id)
        else:
            print('No DB Object found?!')
        return db_object

    def determine_create_object(self, observable_object, object_type, object_data, object_id):
        """get or create sitx database object based on given type and information
        @observable_object: database object of the observable the object belongs to
        @object_type: type of the object that we want to create
        @object_data: stix object data in json format
        @object_id: xml indentifier of the given object
        returns: list of database objects
        """
        object_list = []
        if object_type == 'FileObjectType':
            # create file object
            file_dict, file_meta_dict, file_custom_properties_lst = handle_file_object(object_data)
            # create meta information object
            file_meta_object, file_meta_created = File_Meta_Object.objects.get_or_create(**file_meta_dict)
            # items that have a hash should be checked for existance
            if file_dict['md5_hash'] != 'No MD5' or file_dict['sha256_hash'] != 'No SHA256':
                file_object, file_created = File_Object.objects.get_or_create(**file_dict)
            else:
                try:
                    file_object = File_Object.objects.get(
                        md5_hash=file_dict['md5_hash'],
                        sha256_hash=file_dict['sha256_hash'],
                        file_meta=file_meta_object,
                        observables=observable_object)
                except File_Object.DoesNotExist:
                    file_object = File_Object(**file_dict)
                    file_object.save()
                file_created = False
            # add meta information to file object
            file_object.file_meta.add(file_meta_object)
            # create custom properties
            for custom_dict in file_custom_properties_lst:
                file_custom_object, file_custom_created = File_Custom_Properties.objects.get_or_create(**custom_dict)
                file_object.file_custom.add(file_custom_object)
            file_object.save()
            # add observable
            file_object.observables.add(observable_object)
            file_object.save()
            # create object ID mapping
            if object_id in self.id_mapping['objects']:
                self.id_mapping['objects'][object_id].append({'object_id': file_object.id, 'object_type': object_type})
            else:
                self.id_mapping['objects'][object_id] = [{'object_id': file_object.id, 'object_type': object_type}]
            object_list.append(file_object)
        elif object_type == 'URIObjectType' or object_type == 'DomainNameObjectType':
            # create uri object
            uri_dict = handle_uri_object(object_data)
            uri_object, uri_object_created = URI_Object.objects.get_or_create(**uri_dict)
            # add observable
            uri_object.observables.add(observable_object)
            uri_object.save()
            # create object ID mapping
            if object_id in self.id_mapping['objects']:
                self.id_mapping['objects'][object_id].append({'object_id': uri_object.id, 'object_type': object_type})
            else:
                self.id_mapping['objects'][object_id] = [{'object_id': uri_object.id, 'object_type': object_type}]
            object_list.append(uri_object)
        elif object_type == 'AddressObjectType':
            # create address object
            address_dict_list = handle_address_object(object_data)
            for address_dict in address_dict_list:
                address_object, address_object_created = Address_Object.objects.get_or_create(**address_dict)
                # add observable
                address_object.observables.add(observable_object)
                address_object.save()
                # create object ID mapping
                if object_id in self.id_mapping['objects']:
                    self.id_mapping['objects'][object_id].append({'object_id': address_object.id, 'object_type': object_type})
                else:
                    self.id_mapping['objects'][object_id] = [{'object_id': address_object.id, 'object_type': object_type}]
                object_list.append(address_object)
        elif object_type == 'MutexObjectType':
            # create mutex object

            mutex_dict = handle_mutex_object(object_data)