Update v21 properties to latest spec changes
parent
281dbfb0f4
commit
bdfc221cb0
|
@ -18,8 +18,8 @@ from .utils import _get_dict, get_class_hierarchy_names, parse_into_datetime
|
|||
|
||||
# This uses the regular expression for a RFC 4122, Version 4 UUID. In the
|
||||
# 8-4-4-4-12 hexadecimal representation, the first hex digit of the third
|
||||
# component must be a 4, and the first hex digit of the fourth component must be
|
||||
# 8, 9, a, or b (10xx bit pattern).
|
||||
# component must be a 4, and the first hex digit of the fourth component
|
||||
# must be 8, 9, a, or b (10xx bit pattern).
|
||||
ID_REGEX = re.compile("^[a-z0-9][a-z0-9-]+[a-z0-9]--" # object type
|
||||
"[0-9a-fA-F]{8}-"
|
||||
"[0-9a-fA-F]{4}-"
|
||||
|
@ -39,14 +39,15 @@ class Property(object):
|
|||
``__init__()``.
|
||||
|
||||
Args:
|
||||
required (bool): If ``True``, the property must be provided when creating an
|
||||
object with that property. No default value exists for these properties.
|
||||
(Default: ``False``)
|
||||
required (bool): If ``True``, the property must be provided when
|
||||
creating an object with that property. No default value exists for
|
||||
these properties. (Default: ``False``)
|
||||
fixed: This provides a constant default value. Users are free to
|
||||
provide this value explicity when constructing an object (which allows
|
||||
you to copy **all** values from an existing object to a new object), but
|
||||
if the user provides a value other than the ``fixed`` value, it will raise
|
||||
an error. This is semantically equivalent to defining both:
|
||||
provide this value explicity when constructing an object (which
|
||||
allows you to copy **all** values from an existing object to a new
|
||||
object), but if the user provides a value other than the ``fixed``
|
||||
value, it will raise an error. This is semantically equivalent to
|
||||
defining both:
|
||||
|
||||
- a ``clean()`` function that checks if the value matches the fixed
|
||||
value, and
|
||||
|
@ -57,29 +58,31 @@ class Property(object):
|
|||
- ``def clean(self, value) -> any:``
|
||||
- Return a value that is valid for this property. If ``value`` is not
|
||||
valid for this property, this will attempt to transform it first. If
|
||||
``value`` is not valid and no such transformation is possible, it should
|
||||
raise a ValueError.
|
||||
``value`` is not valid and no such transformation is possible, it
|
||||
should raise a ValueError.
|
||||
- ``def default(self):``
|
||||
- provide a default value for this property.
|
||||
- ``default()`` can return the special value ``NOW`` to use the current
|
||||
time. This is useful when several timestamps in the same object need
|
||||
to use the same default value, so calling now() for each property--
|
||||
likely several microseconds apart-- does not work.
|
||||
time. This is useful when several timestamps in the same object
|
||||
need to use the same default value, so calling now() for each
|
||||
property-- likely several microseconds apart-- does not work.
|
||||
|
||||
Subclasses can instead provide a lambda function for ``default`` as a keyword
|
||||
argument. ``clean`` should not be provided as a lambda since lambdas cannot
|
||||
raise their own exceptions.
|
||||
Subclasses can instead provide a lambda function for ``default`` as a
|
||||
keyword argument. ``clean`` should not be provided as a lambda since
|
||||
lambdas cannot raise their own exceptions.
|
||||
|
||||
When instantiating Properties, ``required`` and ``default`` should not be
|
||||
used together. ``default`` implies that the property is required in the
|
||||
specification so this function will be used to supply a value if none is
|
||||
provided. ``required`` means that the user must provide this; it is
|
||||
required in the specification and we can't or don't want to create a
|
||||
default value.
|
||||
|
||||
When instantiating Properties, ``required`` and ``default`` should not be used
|
||||
together. ``default`` implies that the property is required in the specification
|
||||
so this function will be used to supply a value if none is provided.
|
||||
``required`` means that the user must provide this; it is required in the
|
||||
specification and we can't or don't want to create a default value.
|
||||
"""
|
||||
|
||||
def _default_clean(self, value):
|
||||
if value != self._fixed_value:
|
||||
raise ValueError("must equal '{0}'.".format(self._fixed_value))
|
||||
raise ValueError("must equal '{}'.".format(self._fixed_value))
|
||||
return value
|
||||
|
||||
def __init__(self, required=False, fixed=None, default=None):
|
||||
|
@ -186,7 +189,7 @@ class IDProperty(Property):
|
|||
|
||||
def clean(self, value):
|
||||
if not value.startswith(self.required_prefix):
|
||||
raise ValueError("must start with '{0}'.".format(self.required_prefix))
|
||||
raise ValueError("must start with '{}'.".format(self.required_prefix))
|
||||
if not ID_REGEX.match(value):
|
||||
raise ValueError(ERROR_INVALID_ID)
|
||||
return value
|
||||
|
@ -219,8 +222,8 @@ class BooleanProperty(Property):
|
|||
if isinstance(value, bool):
|
||||
return value
|
||||
|
||||
trues = ['true', 't']
|
||||
falses = ['false', 'f']
|
||||
trues = ['true', 't', '1']
|
||||
falses = ['false', 'f', '0']
|
||||
try:
|
||||
if value.lower() in trues:
|
||||
return True
|
||||
|
@ -302,7 +305,7 @@ class HashesProperty(DictionaryProperty):
|
|||
if key in HASHES_REGEX:
|
||||
vocab_key = HASHES_REGEX[key][1]
|
||||
if not re.match(HASHES_REGEX[key][0], v):
|
||||
raise ValueError("'%s' is not a valid %s hash" % (v, vocab_key))
|
||||
raise ValueError("'{0}' is not a valid {1} hash".format(v, vocab_key))
|
||||
if k != vocab_key:
|
||||
clean_dict[vocab_key] = clean_dict[k]
|
||||
del clean_dict[k]
|
||||
|
@ -342,7 +345,7 @@ class ReferenceProperty(Property):
|
|||
value = str(value)
|
||||
if self.type:
|
||||
if not value.startswith(self.type):
|
||||
raise ValueError("must start with '{0}'.".format(self.type))
|
||||
raise ValueError("must start with '{}'.".format(self.type))
|
||||
if not ID_REGEX.match(value):
|
||||
raise ValueError(ERROR_INVALID_ID)
|
||||
return value
|
||||
|
@ -378,7 +381,7 @@ class EmbeddedObjectProperty(Property):
|
|||
if type(value) is dict:
|
||||
value = self.type(**value)
|
||||
elif not isinstance(value, self.type):
|
||||
raise ValueError("must be of type %s." % self.type.__name__)
|
||||
raise ValueError("must be of type {}.".format(self.type.__name__))
|
||||
return value
|
||||
|
||||
|
||||
|
@ -393,7 +396,7 @@ class EnumProperty(StringProperty):
|
|||
def clean(self, value):
|
||||
value = super(EnumProperty, self).clean(value)
|
||||
if value not in self.allowed:
|
||||
raise ValueError("value '%s' is not valid for this enumeration." % value)
|
||||
raise ValueError("value '{}' is not valid for this enumeration.".format(value))
|
||||
return self.string_type(value)
|
||||
|
||||
|
||||
|
@ -483,7 +486,7 @@ class ExtensionsProperty(DictionaryProperty):
|
|||
else:
|
||||
raise CustomContentError("Can't parse unknown extension type: {}".format(key))
|
||||
else:
|
||||
raise ValueError("The enclosing type '%s' has no extensions defined" % self.enclosing_type)
|
||||
raise ValueError("The enclosing type '{}' has no extensions defined".format(self.enclosing_type))
|
||||
return dictified
|
||||
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class ExternalReference(_STIXBase):
|
|||
('source_name', StringProperty(required=True)),
|
||||
('description', StringProperty()),
|
||||
('url', StringProperty()),
|
||||
('hashes', HashesProperty()),
|
||||
('hashes', HashesProperty(spec_version='2.1')),
|
||||
('external_id', StringProperty()),
|
||||
])
|
||||
|
||||
|
|
|
@ -31,7 +31,9 @@ class Artifact(_Observable):
|
|||
('mime_type', StringProperty()),
|
||||
('payload_bin', BinaryProperty()),
|
||||
('url', StringProperty()),
|
||||
('hashes', HashesProperty()),
|
||||
('hashes', HashesProperty(spec_version='2.1')),
|
||||
('encryption_algorithm', StringProperty()),
|
||||
('decryption_key', StringProperty()),
|
||||
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
|
||||
])
|
||||
|
||||
|
@ -182,7 +184,7 @@ class AlternateDataStream(_STIXBase):
|
|||
|
||||
_properties = OrderedDict([
|
||||
('name', StringProperty(required=True)),
|
||||
('hashes', HashesProperty()),
|
||||
('hashes', HashesProperty(spec_version='2.1')),
|
||||
('size', IntegerProperty()),
|
||||
])
|
||||
|
||||
|
@ -269,7 +271,7 @@ class WindowsPEOptionalHeaderType(_STIXBase):
|
|||
('size_of_heap_commit', IntegerProperty()),
|
||||
('loader_flags_hex', HexProperty()),
|
||||
('number_of_rva_and_sizes', IntegerProperty()),
|
||||
('hashes', HashesProperty()),
|
||||
('hashes', HashesProperty(spec_version='2.1')),
|
||||
])
|
||||
|
||||
def _check_object_constraints(self):
|
||||
|
@ -287,7 +289,7 @@ class WindowsPESection(_STIXBase):
|
|||
('name', StringProperty(required=True)),
|
||||
('size', IntegerProperty()),
|
||||
('entropy', FloatProperty()),
|
||||
('hashes', HashesProperty()),
|
||||
('hashes', HashesProperty(spec_version='2.1')),
|
||||
])
|
||||
|
||||
|
||||
|
@ -308,7 +310,7 @@ class WindowsPEBinaryExt(_Extension):
|
|||
('number_of_symbols', IntegerProperty()),
|
||||
('size_of_optional_header', IntegerProperty()),
|
||||
('characteristics_hex', HexProperty()),
|
||||
('file_header_hashes', HashesProperty()),
|
||||
('file_header_hashes', HashesProperty(spec_version='2.1')),
|
||||
('optional_header', EmbeddedObjectProperty(type=WindowsPEOptionalHeaderType)),
|
||||
('sections', ListProperty(EmbeddedObjectProperty(type=WindowsPESection))),
|
||||
])
|
||||
|
@ -323,7 +325,7 @@ class File(_Observable):
|
|||
_type = 'file'
|
||||
_properties = OrderedDict([
|
||||
('type', TypeProperty(_type)),
|
||||
('hashes', HashesProperty()),
|
||||
('hashes', HashesProperty(spec_version='2.1')),
|
||||
('size', IntegerProperty()),
|
||||
('name', StringProperty()),
|
||||
('name_enc', StringProperty()),
|
||||
|
@ -334,9 +336,6 @@ class File(_Observable):
|
|||
('modified', TimestampProperty()),
|
||||
('accessed', TimestampProperty()),
|
||||
('parent_directory_ref', ObjectReferenceProperty(valid_types='directory')),
|
||||
('is_encrypted', BooleanProperty()),
|
||||
('encryption_algorithm', StringProperty()),
|
||||
('decryption_key', StringProperty()),
|
||||
('contains_refs', ListProperty(ObjectReferenceProperty)),
|
||||
('content_ref', ObjectReferenceProperty(valid_types='artifact')),
|
||||
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
|
||||
|
@ -344,7 +343,6 @@ class File(_Observable):
|
|||
|
||||
def _check_object_constraints(self):
|
||||
super(File, self)._check_object_constraints()
|
||||
self._check_properties_dependency(['is_encrypted'], ['encryption_algorithm', 'decryption_key'])
|
||||
self._check_at_least_one_property(['hashes', 'name'])
|
||||
|
||||
|
||||
|
@ -551,7 +549,7 @@ class WindowsServiceExt(_Extension):
|
|||
|
||||
_type = 'windows-service-ext'
|
||||
_properties = OrderedDict([
|
||||
('service_name', StringProperty(required=True)),
|
||||
('service_name', StringProperty()),
|
||||
('descriptions', ListProperty(StringProperty)),
|
||||
('display_name', StringProperty()),
|
||||
('group_name', StringProperty()),
|
||||
|
@ -601,7 +599,7 @@ class Process(_Observable):
|
|||
('environment_variables', DictionaryProperty(spec_version='2.1')),
|
||||
('opened_connection_refs', ListProperty(ObjectReferenceProperty(valid_types='network-traffic'))),
|
||||
('creator_user_ref', ObjectReferenceProperty(valid_types='user-account')),
|
||||
('binary_ref', ObjectReferenceProperty(valid_types='file')),
|
||||
('image_ref', ObjectReferenceProperty(valid_types='file')),
|
||||
('parent_ref', ObjectReferenceProperty(valid_types='process')),
|
||||
('child_refs', ListProperty(ObjectReferenceProperty('process'))),
|
||||
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
|
||||
|
@ -678,7 +676,8 @@ class UserAccount(_Observable):
|
|||
_type = 'user-account'
|
||||
_properties = OrderedDict([
|
||||
('type', TypeProperty(_type)),
|
||||
('user_id', StringProperty(required=True)),
|
||||
('user_id', StringProperty()),
|
||||
('credential', StringProperty()),
|
||||
('account_login', StringProperty()),
|
||||
('account_type', StringProperty()), # open vocab
|
||||
('display_name', StringProperty()),
|
||||
|
@ -688,7 +687,7 @@ class UserAccount(_Observable):
|
|||
('is_disabled', BooleanProperty()),
|
||||
('account_created', TimestampProperty()),
|
||||
('account_expires', TimestampProperty()),
|
||||
('password_last_changed', TimestampProperty()),
|
||||
('credential_last_changed', TimestampProperty()),
|
||||
('account_first_login', TimestampProperty()),
|
||||
('account_last_login', TimestampProperty()),
|
||||
('extensions', ExtensionsProperty(spec_version='2.1', enclosing_type=_type)),
|
||||
|
@ -703,7 +702,7 @@ class WindowsRegistryValueType(_STIXBase):
|
|||
|
||||
_type = 'windows-registry-value-type'
|
||||
_properties = OrderedDict([
|
||||
('name', StringProperty(required=True)),
|
||||
('name', StringProperty()),
|
||||
('data', StringProperty()),
|
||||
('data_type', EnumProperty(allowed=[
|
||||
"REG_NONE",
|
||||
|
@ -732,7 +731,7 @@ class WindowsRegistryKey(_Observable):
|
|||
_type = 'windows-registry-key'
|
||||
_properties = OrderedDict([
|
||||
('type', TypeProperty(_type)),
|
||||
('key', StringProperty(required=True)),
|
||||
('key', StringProperty()),
|
||||
('values', ListProperty(EmbeddedObjectProperty(type=WindowsRegistryValueType))),
|
||||
# this is not the modified timestamps of the object itself
|
||||
('modified', TimestampProperty()),
|
||||
|
@ -784,7 +783,7 @@ class X509Certificate(_Observable):
|
|||
_properties = OrderedDict([
|
||||
('type', TypeProperty(_type)),
|
||||
('is_self_signed', BooleanProperty()),
|
||||
('hashes', HashesProperty()),
|
||||
('hashes', HashesProperty(spec_version='2.1')),
|
||||
('version', StringProperty()),
|
||||
('serial_number', StringProperty()),
|
||||
('signature_algorithm', StringProperty()),
|
||||
|
|
|
@ -143,13 +143,14 @@ class Indicator(STIXDomainObject):
|
|||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||
('name', StringProperty()),
|
||||
('indicator_types', ListProperty(StringProperty, required=True)),
|
||||
('description', StringProperty()),
|
||||
('pattern', PatternProperty(required=True)),
|
||||
('valid_from', TimestampProperty(default=lambda: NOW)),
|
||||
('valid_until', TimestampProperty()),
|
||||
('kill_chain_phases', ListProperty(KillChainPhase)),
|
||||
('revoked', BooleanProperty(default=lambda: False)),
|
||||
('labels', ListProperty(StringProperty, required=True)),
|
||||
('labels', ListProperty(StringProperty)),
|
||||
('confidence', IntegerProperty()),
|
||||
('lang', StringProperty()),
|
||||
('external_references', ListProperty(ExternalReference)),
|
||||
|
@ -263,17 +264,11 @@ class Malware(STIXDomainObject):
|
|||
('created_by_ref', ReferenceProperty(type='identity')),
|
||||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||
('is_family', BooleanProperty(required=True)),
|
||||
('name', StringProperty(required=True)),
|
||||
('malware_types', ListProperty(StringProperty, required=True)),
|
||||
('description', StringProperty()),
|
||||
('kill_chain_phases', ListProperty(KillChainPhase)),
|
||||
('revoked', BooleanProperty(default=lambda: False)),
|
||||
('labels', ListProperty(StringProperty, required=True)),
|
||||
('confidence', IntegerProperty()),
|
||||
('lang', StringProperty()),
|
||||
('external_references', ListProperty(ExternalReference)),
|
||||
('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))),
|
||||
('granular_markings', ListProperty(GranularMarking)),
|
||||
('is_family', BooleanProperty(required=True)),
|
||||
('first_seen', TimestampProperty()),
|
||||
('last_seen', TimestampProperty()),
|
||||
('os_execution_envs', ListProperty(StringProperty)),
|
||||
|
@ -283,7 +278,14 @@ class Malware(STIXDomainObject):
|
|||
('static_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))),
|
||||
('dynamic_analysis_results', ListProperty(EmbeddedObjectProperty(AnalysisType))),
|
||||
('av_results', ListProperty(EmbeddedObjectProperty(AVResultsType))),
|
||||
('capabilities', ListProperty(StringProperty))
|
||||
('capabilities', ListProperty(StringProperty)),
|
||||
('revoked', BooleanProperty(default=lambda: False)),
|
||||
('labels', ListProperty(StringProperty)),
|
||||
('confidence', IntegerProperty()),
|
||||
('lang', StringProperty()),
|
||||
('external_references', ListProperty(ExternalReference)),
|
||||
('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))),
|
||||
('granular_markings', ListProperty(GranularMarking))
|
||||
])
|
||||
|
||||
|
||||
|
@ -398,11 +400,12 @@ class Report(STIXDomainObject):
|
|||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||
('name', StringProperty(required=True)),
|
||||
('report_types', ListProperty(StringProperty, required=True)),
|
||||
('description', StringProperty()),
|
||||
('published', TimestampProperty(required=True)),
|
||||
('object_refs', ListProperty(ReferenceProperty, required=True)),
|
||||
('revoked', BooleanProperty(default=lambda: False)),
|
||||
('labels', ListProperty(StringProperty, required=True)),
|
||||
('labels', ListProperty(StringProperty)),
|
||||
('confidence', IntegerProperty()),
|
||||
('lang', StringProperty()),
|
||||
('external_references', ListProperty(ExternalReference)),
|
||||
|
@ -426,6 +429,7 @@ class ThreatActor(STIXDomainObject):
|
|||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||
('name', StringProperty(required=True)),
|
||||
('threat_actor_types', ListProperty(StringProperty, required=True)),
|
||||
('description', StringProperty()),
|
||||
('aliases', ListProperty(StringProperty)),
|
||||
('roles', ListProperty(StringProperty)),
|
||||
|
@ -436,7 +440,7 @@ class ThreatActor(STIXDomainObject):
|
|||
('secondary_motivations', ListProperty(StringProperty)),
|
||||
('personal_motivations', ListProperty(StringProperty)),
|
||||
('revoked', BooleanProperty(default=lambda: False)),
|
||||
('labels', ListProperty(StringProperty, required=True)),
|
||||
('labels', ListProperty(StringProperty)),
|
||||
('confidence', IntegerProperty()),
|
||||
('lang', StringProperty()),
|
||||
('external_references', ListProperty(ExternalReference)),
|
||||
|
@ -460,11 +464,12 @@ class Tool(STIXDomainObject):
|
|||
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
|
||||
('name', StringProperty(required=True)),
|
||||
('tool_types', ListProperty(StringProperty, required=True)),
|
||||
('description', StringProperty()),
|
||||
('kill_chain_phases', ListProperty(KillChainPhase)),
|
||||
('tool_version', StringProperty()),
|
||||
('revoked', BooleanProperty(default=lambda: False)),
|
||||
('labels', ListProperty(StringProperty, required=True)),
|
||||
('labels', ListProperty(StringProperty)),
|
||||
('confidence', IntegerProperty()),
|
||||
('lang', StringProperty()),
|
||||
('external_references', ListProperty(ExternalReference)),
|
||||
|
|
Loading…
Reference in New Issue