STIX helper module

FIXME

validate_stix_id(uuid: str, object_type: str = '') bool

Test whether a string is a STIX standard ID ([object-type]–[UUID])

Examples:

>>> validate_stix_id('indicator--167565fe-69da-5e2f-a1c1-0542736f9f9a')
True
>>> validate_stix_id('marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da', 'marking-definition')
True
>>> validate_stix_id('marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da', 'ipv4-addr')
False
pydantic model SCOBundle

Show JSON schema
{
   "title": "SCOBundle",
   "type": "object",
   "properties": {
      "sco": {
         "anyOf": [],
         "title": "Sco"
      },
      "nested_objs": {
         "default": [],
         "items": {
            "anyOf": []
         },
         "title": "Nested Objs",
         "type": "array"
      }
   },
   "required": [
      "sco"
   ]
}

Config:
  • arbitrary_types_allowed: bool = True

Fields:
  • nested_objs (list[stix2.v21.observables.Artifact | stix2.v21.observables.AutonomousSystem | stix2.v21.observables.Directory | stix2.v21.observables.DomainName | stix2.v21.observables.EmailAddress | stix2.v21.observables.EmailMessage | stix2.v21.observables.File | stix2.custom._custom_observable_builder.

  • sco (stix2.v21.observables.Artifact | stix2.v21.observables.AutonomousSystem | stix2.v21.observables.Directory | stix2.v21.observables.DomainName | stix2.v21.observables.EmailAddress | stix2.v21.observables.EmailMessage | stix2.v21.observables.File | stix2.custom._custom_observable_builder.

field nested_objs: list[~stix2.v21.observables.Artifact | ~stix2.v21.observables.AutonomousSystem | ~stix2.v21.observables.Directory | ~stix2.v21.observables.DomainName | ~stix2.v21.observables.EmailAddress | ~stix2.v21.observables.EmailMessage | ~stix2.v21.observables.File | ~stix2.custom._custom_observable_builder.<locals>._CustomObservable | ~stix2.v21.observables.IPv4Address | ~stix2.v21.observables.IPv6Address | ~stix2.v21.observables.MACAddress | ~stix2.v21.observables.Mutex | ~stix2.v21.observables.NetworkTraffic | ~stix2.v21.observables.Process | ~stix2.v21.observables.Software | ~stix2.v21.observables.URL | ~stix2.v21.observables.UserAccount | ~stix2.custom._custom_observable_builder.<locals>._CustomObservable | ~stix2.v21.observables.WindowsRegistryKey | ~stix2.v21.observables.X509Certificate] = []
field sco: X509Certificate [Required]
objects() list[~stix2.v21.observables.Artifact | ~stix2.v21.observables.AutonomousSystem | ~stix2.v21.observables.Directory | ~stix2.v21.observables.DomainName | ~stix2.v21.observables.EmailAddress | ~stix2.v21.observables.EmailMessage | ~stix2.v21.observables.File | ~stix2.custom._custom_observable_builder.<locals>._CustomObservable | ~stix2.v21.observables.IPv4Address | ~stix2.v21.observables.IPv6Address | ~stix2.v21.observables.MACAddress | ~stix2.v21.observables.Mutex | ~stix2.v21.observables.NetworkTraffic | ~stix2.v21.observables.Process | ~stix2.v21.observables.Software | ~stix2.v21.observables.URL | ~stix2.v21.observables.UserAccount | ~stix2.custom._custom_observable_builder.<locals>._CustomObservable | ~stix2.v21.observables.WindowsRegistryKey | ~stix2.v21.observables.X509Certificate]
tlp_marking_from_string(tlp_string: str | None)

Map a TLP string to a corresponding marking definition, or None

Any characters up to and including “:” are stripped and case is ignored.

Examples:

>>> tlp_marking_from_string('white')
'marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9'
>>> tlp_marking_from_string('TLP:amBEr')
'marking-definition--f88d31f6-486f-44da-b317-01333bde0b82'
>>> tlp_marking_from_string('foo')
Traceback (most recent call last):
...
ValueError: foo is not a valid marking definition
tlp_allowed(entity: dict, max_tlp: Literal['TLP:CLEAR', 'TLP:WHITE', 'TLP:GREEN', 'TLP:AMBER', 'TLP:AMBER+STRICT', 'TLP:RED']) bool

If the entity has a TLP marking definition, ensure it is within a maximum allowed TLP

entity_value(entity: dict) str | None

Return an observable’s (or vulnerability’s) value

entity_values(entity: dict) list[Any]

Return an observable’s (or vulnerability’s) values

entity_name_value(entity: dict)

Return the name and value of an entity, space separated

incident_entity_relation_type(entity: dict)

Return the expected relationship type for the entity in the incident

remove_unref_objs(bundle: ~typing.Sequence[~stix2.v21.observables.Artifact | ~stix2.v21.observables.AutonomousSystem | ~stix2.v21.observables.Directory | ~stix2.v21.observables.DomainName | ~stix2.v21.observables.EmailAddress | ~stix2.v21.observables.EmailMessage | ~stix2.v21.observables.File | ~stix2.custom._custom_observable_builder.<locals>._CustomObservable | ~stix2.v21.observables.IPv4Address | ~stix2.v21.observables.IPv6Address | ~stix2.v21.observables.MACAddress | ~stix2.v21.observables.Mutex | ~stix2.v21.observables.NetworkTraffic | ~stix2.v21.observables.Process | ~stix2.v21.observables.Software | ~stix2.v21.observables.URL | ~stix2.v21.observables.UserAccount | ~stix2.custom._custom_observable_builder.<locals>._CustomObservable | ~stix2.v21.observables.WindowsRegistryKey | ~stix2.v21.observables.X509Certificate | ~stix2.v21.sdo.AttackPattern | ~stix2.v21.sdo.Campaign | ~stix2.v21.sdo.CourseOfAction | ~stix2.v21.sdo.Grouping | ~stix2.v21.sdo.Identity | ~stix2.v21.sdo.Incident | ~stix2.v21.sdo.Indicator | ~stix2.v21.sdo.Infrastructure | ~stix2.v21.sdo.IntrusionSet | ~stix2.v21.sdo.Location | ~stix2.v21.sdo.Malware | ~stix2.v21.sdo.MalwareAnalysis | ~stix2.v21.sdo.Note | ~stix2.v21.sdo.ObservedData | ~stix2.v21.sdo.Opinion | ~stix2.v21.sdo.Report | ~stix2.v21.sdo.ThreatActor | ~stix2.v21.sdo.Tool | ~stix2.v21.sdo.Vulnerability | ~stix2.v21.sro.Relationship | ~stix2.v21.sro.Sighting]) Sighting]

Return a new bundle only with SCOs/SDOs that are referenced in SROs

All observables and domain objects that are referenced by relationships or sightings (not as nested objects) are kept in the list, in order. All unreferenced objects are removed.

Examples:

>>> f1 = stix2.File(name='foo', allow_custom=True, test_id='file_foo')
>>> f2 = stix2.File(name='bar', allow_custom=True, test_id='file_bar')
>>> f3 = stix2.File(name='baz', allow_custom=True, test_id='file_baz')
>>> r1 = stix2.Relationship(relationship_type='related-to', source_ref=f1, target_ref=f2, allow_custom=True, test_id='rel')
>>> i1 = stix2.Indicator(pattern="[file:name = 'foo']", pattern_type='stix', valid_from='2024-04-04T15:46:03.282304Z', allow_custom=True, test_id='ind')
>>> id1 = stix2.Identity(name='id1', allow_custom=True, test_id='id1')
>>> id2 = stix2.Identity(name='id2', allow_custom=True, test_id='id2')
>>> id3 = stix2.Identity(name='id3', allow_custom=True, test_id='id3')
>>> s1 = stix2.Sighting(sighting_of_ref=i1.id, where_sighted_refs=[id1, id2], allow_custom=True, test_id='sight')
>>> bundle = [f1, r1, f2, f3, id1, i1, id2, s1, id3]
>>> [o.test_id for o in remove_unref_objs(bundle)]
['file_foo', 'rel', 'file_bar', 'id1', 'ind', 'id2', 'sight']
find_hashes(obj: Mapping, fields: list[list[str]], overwrite: bool = False) dict[str, dict[str, str]]

Return a dict suitable for the argument ‘hashes’ in stix2.File from hash properties in an alert

The hash keys will be transformed into the keys expected by STIX, e.g. ‘sha256_after’ will be replaced with ‘SHA-256’. Any field containing ‘sha256’ or ‘sha-256’ in any case will be matched. The hashes themselves are not verified.

The fields is a list of list of fields, where the outer list determines the order of preference. The overwrite parameter determines whether a hash member found in a previous field list will be replaced or not.

Examples:

>>> alert = {"syscheck": { "md5_before": "11ee6b89a2500aa326d45bc0f0d93821", "sha256_before": "87b3bfb07fa641adf426961c9d5e8a81c321fd03c32d9afb0f761a2c876cb6a1", "sha1_after": "950c5897c1e1b8b7686b976472d19fd815beccd7", "md5_after": "502ad4209d3eb3267d08708f0807de1c", "sha1_before": "ff916c71058daa68e2951a50bed8b3e5bfd7aff3", "sha256_after": "6f2a43b4d954d9984701a23513bb4476736dd4aed5b5ec47ad99e7943eacd7bf"}}
>>> find_hashes(alert, [['syscheck.sha256_after', 'syscheck.md5_after', 'syscheck.sha1_after'], ['syscheck.sha256_before']])
{'SHA-256': '6f2a43b4d954d9984701a23513bb4476736dd4aed5b5ec47ad99e7943eacd7bf', 'MD5': '502ad4209d3eb3267d08708f0807de1c', 'SHA-1': '950c5897c1e1b8b7686b976472d19fd815beccd7'}
>>> find_hashes(alert, [['syscheck.sha256_after', 'syscheck.md5_after', 'syscheck.sha1_after'], ['syscheck.sha256_before']], overwrite=True)
{'SHA-256': '87b3bfb07fa641adf426961c9d5e8a81c321fd03c32d9afb0f761a2c876cb6a1', 'MD5': '502ad4209d3eb3267d08708f0807de1c', 'SHA-1': '950c5897c1e1b8b7686b976472d19fd815beccd7'}
pydantic model StixHelper

Helper class to simplify creation of STIX entities

Show JSON schema
{
   "title": "StixHelper",
   "description": "Helper class to simplify creation of STIX entities",
   "type": "object",
   "properties": {
      "common_properties": {
         "default": {},
         "title": "Common Properties",
         "type": "object"
      },
      "sco_labels": {
         "default": [],
         "items": {
            "type": "string"
         },
         "title": "Sco Labels",
         "type": "array"
      },
      "filename_behaviour": {
         "default": [
            "create-dir"
         ],
         "items": {
            "$ref": "#/$defs/FilenameBehaviour"
         },
         "title": "Filename Behaviour",
         "type": "array",
         "uniqueItems": true
      }
   },
   "$defs": {
      "FilenameBehaviour": {
         "enum": [
            "create-dir",
            "remove-path"
         ],
         "title": "FilenameBehaviour",
         "type": "string"
      }
   }
}

Fields:
Validators:
field common_properties: dict[str, Any] = {}
field filename_behaviour: set[FilenameBehaviour] = {FilenameBehaviour.CreateDir}
Validated by:
field sco_labels: list[str] = []
create_account_from_username(username: str | None, **stix_properties)

Create a User-Account from a string that may contain a username or both a username and a user ID

If the username is of the form “name(uid=digits)”, the uid is extracted and the resulting UserAccount will have both account_login and user_id set, otherwise account_login will be used.

Examples:

>>> h = StixHelper()
>>> h.create_account_from_username('foo', custom_prop='bar')
UserAccount(type='user-account', spec_version='2.1', id='user-account--234499e1-7802-5681-87df-a7667d8e3b6e', account_login='foo', defanged=False, custom_prop='bar')
>>> h.create_account_from_username('foo(uid=1000)')
UserAccount(type='user-account', spec_version='2.1', id='user-account--7d128e22-4162-5b1e-8df6-d6b8644c6949', user_id='1000', account_login='foo', defanged=False)
>>> h.create_account_from_username(username=None,user_id='1000')
UserAccount(type='user-account', spec_version='2.1', id='user-account--4b8a1e8e-e7c7-5c91-b832-b1bdad612c36', user_id='1000', defanged=False)
create_addr_sco(address: str, **properties) IPv4Address | IPv6Address

Create either an IPv4Address or IPv6Address, depending on the address type

create_file(names: list[str], *, sha256: str | None = None, **properties) SCOBundle

Create a STIX file

If sha256 is non-empty, it will be inserted into a hash object. If names contain more than one string, the first name will be used as “name”, and the rest will be used as x_opencti_additional_names.

If filename_behaviour contains CreateDir, a Directory object is created and referenced in parent_directory_ref. The path is extracted from the one of the filenames that contains a path. If filename_behaviour contains RemovePath, the path component of filenames will be removed.

Examples:

>>> h = StixHelper(filename_behaviour='')
>>> h.create_file(names=['filename1', 'filename2'])
SCOBundle(sco=File(type='file', spec_version='2.1', id='file--f83c036d-56f6-5246-8585-1616d42c7669', name='filename1', defanged=False, x_opencti_additional_names=['filename2']), nested_objs=[])
>>> h.create_file(names=['/tmp/filename1', '/filename2'])
SCOBundle(sco=File(type='file', spec_version='2.1', id='file--09765542-1408-5026-8674-8128438fc940', name='/tmp/filename1', defanged=False, x_opencti_additional_names=['/filename2']), nested_objs=[])
>>> h = StixHelper(filename_behaviour='create-dir')
>>> h.create_file(names=['/tmp/filename1', '/home/foo/Downloads/filename2'])
SCOBundle(sco=File(type='file', spec_version='2.1', id='file--ed282b5e-3ebe-5d5f-81e3-d52b629abb46', name='/tmp/filename1', parent_directory_ref='directory--b7ed5105-3a80-559d-9bd6-ec208b6d813e', defanged=False, x_opencti_additional_names=['/home/foo/Downloads/filename2']), nested_objs=[Directory(type='directory', spec_version='2.1', id='directory--b7ed5105-3a80-559d-9bd6-ec208b6d813e', path='/home/foo/Downloads', defanged=False)])
>>> h = StixHelper(filename_behaviour='create-dir,remove-path')
>>> h.create_file(names=['filename1', '/home/foo/Downloads/filename2'])
SCOBundle(sco=File(type='file', spec_version='2.1', id='file--901c064f-7d08-5092-b84e-851f68c67a73', name='filename1', parent_directory_ref='directory--b7ed5105-3a80-559d-9bd6-ec208b6d813e', defanged=False, x_opencti_additional_names=['filename2']), nested_objs=[Directory(type='directory', spec_version='2.1', id='directory--b7ed5105-3a80-559d-9bd6-ec208b6d813e', path='/home/foo/Downloads', defanged=False)])
create_sco(sco_type: str, value: str | None, **properties) SCOBundle

Create a SCO from its type name and properties

If value is None, properties must contain the observable value.

create_tool(name: str)
validator parse_behaviour_string  »  filename_behaviour