ruby-stix2 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +7 -1
  3. data/README.md +49 -3
  4. data/lib/stix2/base.rb +7 -0
  5. data/lib/stix2/common.rb +80 -15
  6. data/lib/stix2/confidence_scale.rb +106 -0
  7. data/lib/stix2/custom_object.rb +20 -0
  8. data/lib/stix2/cyberobservable_objects/email_message.rb +1 -1
  9. data/lib/stix2/cyberobservable_objects/network_traffic.rb +1 -1
  10. data/lib/stix2/cyberobservable_objects/process.rb +17 -0
  11. data/lib/stix2/cyberobservable_objects/user_account.rb +4 -4
  12. data/lib/stix2/cyberobservable_objects/x509_certificate.rb +3 -1
  13. data/lib/stix2/domain_objects/malware.rb +1 -1
  14. data/lib/stix2/enum.rb +59 -0
  15. data/lib/stix2/extension_definition.rb +10 -0
  16. data/lib/stix2/extensions/alternate_data_stream_type.rb +9 -0
  17. data/lib/stix2/extensions/archive_file.rb +8 -0
  18. data/lib/stix2/extensions/http_request.rb +12 -0
  19. data/lib/stix2/extensions/icmp.rb +8 -0
  20. data/lib/stix2/extensions/ntfs.rb +10 -0
  21. data/lib/stix2/extensions/pdf.rb +11 -0
  22. data/lib/stix2/extensions/raster_image.rb +10 -0
  23. data/lib/stix2/extensions/socket.rb +13 -0
  24. data/lib/stix2/extensions/tcp.rb +8 -0
  25. data/lib/stix2/extensions/unix_account.rb +10 -0
  26. data/lib/stix2/extensions/windows_pe_optional_header_type.rb +37 -0
  27. data/lib/stix2/extensions/windows_pe_section_type.rb +10 -0
  28. data/lib/stix2/extensions/windows_pebinary.rb +21 -0
  29. data/lib/stix2/extensions/windows_process.rb +13 -0
  30. data/lib/stix2/extensions/windows_service.rb +14 -0
  31. data/lib/stix2/external_reference.rb +1 -5
  32. data/lib/stix2/identifier.rb +2 -12
  33. data/lib/stix2/kill_chain_phase.rb +3 -7
  34. data/lib/stix2/languages.rb +236 -0
  35. data/lib/stix2/meta_objects/data_markings/base.rb +1 -4
  36. data/lib/stix2/meta_objects/data_markings/granular_marking.rb +1 -5
  37. data/lib/stix2/meta_objects/data_markings/object_marking.rb +2 -12
  38. data/lib/stix2/meta_objects/language_content.rb +1 -1
  39. data/lib/stix2/ov.rb +6 -0
  40. data/lib/stix2/relationship_objects/sighting.rb +1 -1
  41. data/lib/stix2/storage.rb +21 -15
  42. data/lib/stix2/version.rb +1 -1
  43. data/lib/stix2.rb +35 -7
  44. data/ruby-stix2.gemspec +9 -5
  45. metadata +40 -6
  46. data/lib/stix2/boolean.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 123ddb57694307c96be2fbdf9a9d9f8c9ac55fbbbf35dc7f71c196aadad728b6
4
- data.tar.gz: fff53b71f98c23069d7c3dd0da2a4ca3799f424a162f10629029361b0624800e
3
+ metadata.gz: f69ada6e1bf635fb01ca7cfed49ed184447e14e8b85c2b5ff14e1640d1f18738
4
+ data.tar.gz: 56712374f185dc57787679dd8060eb32320cbff393fada2d5285a924bc48b3a1
5
5
  SHA512:
6
- metadata.gz: e7aae57f5bf2b8415431df88dd2999ed85cfbf56f9f1634e750a0f00a53375c6dff96060ae96a4052eb2efca4471d38ac8244f1824f7f8f03df18ac883430517
7
- data.tar.gz: 63a3575a2886265784846dccb94fe8e32f300ca4c3c8006311f27acb19c0dc3a87c792b2aa4530c73b5ce5e1a2fd8064a2bcf50c051778dd743e7f4fa6831d2a
6
+ metadata.gz: cc04f1a76a4e79f2e57365201e1fdadaa4f29eecb1c61f2e4f7a4be4d9201b238ee36aac3f5c6bd094acc77ae2be8720b41d0e0a8a2b62a52279304c4fc8bb64
7
+ data.tar.gz: 852ae67a130e1a0338fd0d44af58746caab042d92b7b2bbd3c09c4edba2b0860eb0ff4a2c76a9346c802b8b7a47150e4bfae2b6039b31c082fed9f4da3b7e8ea
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-stix2 (0.1.0)
4
+ ruby-stix2 (0.1.1)
5
5
  hashie (~> 5.0.0)
6
6
 
7
7
  GEM
@@ -11,6 +11,9 @@ GEM
11
11
  coderay (1.1.3)
12
12
  docile (1.4.0)
13
13
  hashie (5.0.0)
14
+ io-console (0.6.0)
15
+ irb (1.7.0)
16
+ reline (>= 0.3.0)
14
17
  method_source (1.0.0)
15
18
  minitest (5.18.1)
16
19
  pry (0.13.1)
@@ -20,6 +23,8 @@ GEM
20
23
  byebug (~> 11.0)
21
24
  pry (>= 0.13, < 0.15)
22
25
  rake (13.0.6)
26
+ reline (0.3.5)
27
+ io-console (~> 0.5)
23
28
  simplecov (0.22.0)
24
29
  docile (~> 1.1)
25
30
  simplecov-html (~> 0.11)
@@ -32,6 +37,7 @@ PLATFORMS
32
37
 
33
38
  DEPENDENCIES
34
39
  bundler (~> 2.3)
40
+ irb (~> 1.7.0)
35
41
  minitest (~> 5.18.1)
36
42
  pry (~> 0.13.0)
37
43
  pry-byebug (~> 3.10.1)
data/README.md CHANGED
@@ -12,7 +12,7 @@ gem install ruby-stix2
12
12
  or as part of the bundle
13
13
 
14
14
  ```
15
- bundle add typhoeus
15
+ bundle add ruby-stix2
16
16
  ```
17
17
 
18
18
  # Usage
@@ -69,7 +69,7 @@ Stix2 message.
69
69
  # Storage
70
70
 
71
71
  The Stix2 standard has several object types, some of which are containers of other objects (like `Bundle`). However we
72
- may want to save and retrieve Stix2 objects in a fast way. The gem provides a `storage` support for that.
72
+ may want to save and retrieve Stix2 objects in a fast way. The gem provides a `Stix::Storage` support for that.
73
73
 
74
74
  For any Stix2 attribute that is an `identifier` (`Stix2::Identifier` in the gem) the class gives one more method called
75
75
  `_instance` to retrieve the actual instance. If we have a `threat-actor` like this
@@ -98,7 +98,7 @@ we know that this object has been created by an identity `identity--f431f809-377
98
98
  retrieve the other object if already seen
99
99
 
100
100
  ```ruby
101
- Stix2.storage_activate # Activate the storage
101
+ Stix2::Storage.activate # Activate the storage
102
102
 
103
103
  identity = Stix2::DomainObject::Identity.new(id: 'identity--f431f809-377b-45e0-aa1c-6a4751cae5ff', ...)
104
104
  threat_actor = Stix2::DomainObject::ThreatActor.new(created_by_ref: 'identity--f431f809-377b-45e0-aa1c-6a4751cae5ff', ...)
@@ -107,6 +107,48 @@ threat_actor.created_by_ref # this gives the identifier => identity--f431f809-37
107
107
  threat_actor.created_by_ref_instance # this gives the actual object => Stix2::DomainObject::Identity
108
108
  ```
109
109
 
110
+ # Spec versions
111
+
112
+ This gem implements the spec version `2.1`. However older version (especially 2.0) can be compatible. To force the gem
113
+ to accept another spec version, just add them to the `SPEC_VERSIONS` variable.
114
+
115
+ ```ruby
116
+ Stix2::SPEC_VERSIONS << '2.0'
117
+ ```
118
+
119
+ # Custom Definitions
120
+
121
+ The Stix2 standard includes several extensions to base objects. All extensions are widely described in the standard
122
+ itself, please refer to it. However two of them need more attention for how they are implemented in this gem.
123
+
124
+ ## Extension Definition
125
+
126
+ This object allows the definition of new properties. One special property is `toplevel-property-extension` that allows
127
+ the definition of properties on the top-level of an object. According to the standard thos properties should be
128
+ defined solely on the object that is actually using the property. However due to the `hashie`-based implementation
129
+ the gem declares the new properties on the class itself. This is a known limitation of the current implementation and
130
+ it may be fixed in the future.
131
+
132
+ ## Custom Object
133
+
134
+ A `CustomObject` can also be used within the Gem. The standard defines the rules that must be fulfilled for a custom
135
+ object. Since those rules are several, the code stacks all the errors altogether and raises an exception when some
136
+ errors happen. The exception is RuntimeError, that gives the user a string. It is suboptimal to have multiple errors
137
+ in a string, and it may be fixed in the future.
138
+
139
+ # Confidence
140
+
141
+ A Stix2 object can have the property `confidence` set. This value can be expressed according to several conficence
142
+ scales. To make this conversion smooth, an object offers the method `confidence_scale` that is an instance of
143
+ `Stix2::ConfidenceScale`. This class offers method for all the scales the standard includes.
144
+
145
+ ```ruby
146
+ indicator = Stix2::DomainObject::Indicator.new(confidence: i)
147
+ indicator.confidence # This is the raw integer
148
+ indicator.confidence_scale.to_admiralty_credibility # this is a string in this scale
149
+ indicator.confidence_scale.to_admiralty_credibility_strix # this is a string in stix mode
150
+ ```
151
+
110
152
  # Contribution
111
153
 
112
154
  You can contribute to this project in 2 ways:
@@ -114,3 +156,7 @@ You can contribute to this project in 2 ways:
114
156
  - with a PR: just follow the standard github workflow
115
157
  - by pointing out missing support: open an issue and please provide a json containing the missing support, to simplify
116
158
  the development
159
+
160
+ # See also
161
+
162
+ Ruby Stix2: https://github.com/crondaemon/ruby-taxii2
data/lib/stix2/base.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Stix2
2
+ class Base < Hashie::Dash
3
+ include Hashie::Extensions::Dash::PredefinedValues
4
+ include Hashie::Extensions::IndifferentAccess
5
+ include Hashie::Extensions::Dash::Coercion
6
+ end
7
+ end
data/lib/stix2/common.rb CHANGED
@@ -1,44 +1,55 @@
1
1
  module Stix2
2
- class Common < Hashie::Dash
3
- include Hashie::Extensions::Dash::PredefinedValues
4
- include Hashie::Extensions::IndifferentAccess
5
- include Hashie::Extensions::Dash::Coercion
2
+ SPEC_VERSIONS = ['2.1']
6
3
 
4
+ class Common < Stix2::Base
7
5
  property :type, required: true, coerce: String
8
- property :spec_version, coerce: String, values: ['2.1']
6
+ property :spec_version, coerce: String, values: Stix2::SPEC_VERSIONS
9
7
  property :id, coerce: Identifier
10
8
  property :created_by_ref, coerce: Identifier
11
9
  property :created, coerce: Time
12
10
  property :modified, coerce: Time
13
- property :revoked, coerce: Stix2::Boolean
11
+ property :revoked, coerce: ->(value){ Stix2.to_bool(value) }
14
12
  property :labels, coerce: Array[String]
15
- property :confidence, coerce: Integer
13
+ property :confidence, coerce: ->(value){ int = Integer(value) ; [0..100].include?(int) ; int }
16
14
  property :lang, coerce: String
17
15
  property :external_references, coerce: Array[ExternalReference]
18
16
  property :object_marking_refs, coerce: Array[Stix2::MetaObject::DataMarking::ObjectMarking]
19
17
  property :granular_markings, coerce: Array[MetaObject::DataMarking::GranularMarking]
20
- property :defanged, coerce: Stix2::Boolean
18
+ property :defanged, coerce: ->(value){ Stix2.to_bool(value) }
21
19
  property :extensions, coerce: Hash
22
20
 
23
21
  def initialize(options = {})
24
22
  Hashie.symbolize_keys!(options)
25
23
  type = to_dash(self.class.name.split('::').last)
26
24
  if options[:type]
27
- raise("Property 'type' must be '#{type}'") if options[:type] != type
25
+ if !options[:type].start_with?('x-') && options[:type] != type
26
+ raise("Property 'type' must be '#{type}'")
27
+ end
28
28
  else
29
29
  options[:type] = type
30
30
  end
31
+ process_toplevel_property_extension(options[:extensions])
31
32
  super(options)
32
- Stix2.storage_add(self)
33
+ process_extensions(options)
34
+ Stix2::Storage.add(self)
33
35
  end
34
36
 
35
37
  def method_missing(m, *args, &block)
36
- super(m, args, block) if !m.to_s.end_with?('_instance')
38
+ if !m.to_s.end_with?('_instance')
39
+ # :nocov:
40
+ super(m, args, block)
41
+ return
42
+ # :nocov:
43
+ end
37
44
  # Retrieve the original method
38
45
  ref_method = m.to_s.gsub(/_instance$/, '')
39
46
  obj = send(ref_method)
40
47
  raise("Can't get a Stix2::Identifier from #{ref_method}") if !obj.is_a?(Stix2::Identifier)
41
- Stix2.storage_find(obj)
48
+ Stix2::Storage.find(obj)
49
+ end
50
+
51
+ def confidence_scale
52
+ Stix2::ConfidenceScale.new(confidence)
42
53
  end
43
54
 
44
55
  private
@@ -48,15 +59,69 @@ module Stix2
48
59
  end
49
60
 
50
61
  def self.validate_array(list, valid_values)
51
- excess = (Array(list) - valid_values)
62
+ excess = (Array(list).map(&:to_s) - valid_values.map(&:to_s))
52
63
  excess.empty? || raise("Invalid values: #{excess}")
53
64
  list
54
65
  end
55
66
 
56
67
  def self.hash_dict(hsh)
57
- invalids = hsh.keys.map(&:to_s) - HASH_ALGORITHM_OV
58
- invalids.empty? || raise("Invalid values: #{invalids}")
68
+ validate_array(hsh.keys, HASH_ALGORITHM_OV)
59
69
  hsh
60
70
  end
71
+
72
+ def process_toplevel_property_extension(extensions)
73
+ extension_definition = extensions&.find{ |key, val| key.to_s.start_with?('extension-definition') }
74
+ return if !extension_definition
75
+
76
+ id = extension_definition.first
77
+ type = extension_definition.last[:extension_type]
78
+ if type == 'toplevel-property-extension'
79
+ Stix2::Storage.active? || raise('Stix.storage must be active to use toplevel-property-extension')
80
+ ext = Stix2::Storage.find(id)
81
+ ext.extension_properties.each do |prop|
82
+ self.class.class_eval do
83
+ property prop
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def process_extensions(options)
90
+ options[:extensions]&.each do |id, value|
91
+ case id.to_s
92
+ when /[A-Z]/
93
+ raise('Invalid extension name format.')
94
+ when 'archive-ext'
95
+ extensions[id] = Stix2::Extensions::ArchiveFile.new(value)
96
+ when /^extension-definition/
97
+ # Ignore it, already processes
98
+ when 'socket-ext'
99
+ extensions[id] = Stix2::Extensions::Socket.new(value)
100
+ when 'icmp-ext'
101
+ extensions[id] = Stix2::Extensions::Icmp.new(value)
102
+ when 'http-request-ext'
103
+ extensions[id] = Stix2::Extensions::HttpRequest.new(value)
104
+ when 'ntfs-ext'
105
+ extensions[id] = Stix2::Extensions::Ntfs.new(value)
106
+ when 'tcp-ext'
107
+ extensions[id] = Stix2::Extensions::Tcp.new(value)
108
+ when 'windows-process-ext'
109
+ extensions[id] = Stix2::Extensions::WindowsProcess.new(value)
110
+ when 'windows-service-ext'
111
+ extensions[id] = Stix2::Extensions::WindowsService.new(value)
112
+ when 'unix-account-ext'
113
+ extensions[id] = Stix2::Extensions::UnixAccount.new(value)
114
+ when 'pdf-ext'
115
+ extensions[id] = Stix2::Extensions::Pdf.new(value)
116
+ when 'raster-image-ext'
117
+ extensions[id] = Stix2::Extensions::RasterImage.new(value)
118
+ when 'windows-pebinary-ext'
119
+ extensions[id] = Stix2::Extensions::WindowsPebinary.new(value)
120
+ else
121
+ # Ensure we have a hash
122
+ value.is_a?(Hash) || raise("Custom extension must be Hash: #{value}")
123
+ end
124
+ end
125
+ end
61
126
  end
62
127
  end
@@ -0,0 +1,106 @@
1
+ module Stix2
2
+ class ConfidenceScale
3
+ SCALE_NONE_LOW_MED_HIGH = {
4
+ 0..0 => { scale: 'None', stix: 0 },
5
+ 1..29 => { scale: 'Low', stix: 15 },
6
+ 30..69 => { scale: 'Med', stix: 50 },
7
+ 70..100 => { scale: 'High', stix: 85 }
8
+ }.freeze
9
+
10
+ SCALE_0_10 = {
11
+ 0..4 => { scale: 0, stix: 0 },
12
+ 5..14 => { scale: 1, stix: 10 },
13
+ 15..24 => { scale: 2, stix: 20 },
14
+ 25..34 => { scale: 3, stix: 30 },
15
+ 35..44 => { scale: 4, stix: 40 },
16
+ 45..54 => { scale: 5, stix: 50 },
17
+ 55..64 => { scale: 6, stix: 60 },
18
+ 65..74 => { scale: 7, stix: 70 },
19
+ 75..84 => { scale: 8, stix: 80 },
20
+ 85..94 => { scale: 9, stix: 90 },
21
+ 95..100 => { scale: 10, stix: 100 }
22
+ }.freeze
23
+
24
+ SCALE_ADMIRALTY_CREDIBILITY = {
25
+ 0..19 => { scale: 5, stix: 10 },
26
+ 20..39 => { scale: 4, stix: 30 },
27
+ 40..59 => { scale: 3, stix: 50 },
28
+ 60..79 => { scale: 2, stix: 70 },
29
+ 80..100 => { scale: 1, stix: 90 }
30
+ }.freeze
31
+
32
+ SCALE_WEP = {
33
+ 0..0 => { scale: 'Impossible', stix: 0 },
34
+ 1..19 => { scale: 'Highly Unlikely/Almost Certainly Not', stix: 10 },
35
+ 20..39 => { scale: 'Unlikely/Probably Not', stix: 30 },
36
+ 40..59 => { scale: 'Even Chance', stix: 50 },
37
+ 60..79 => { scale: 'Likely/Probable', stix: 70 },
38
+ 80..99 => { scale: 'Highly likely/Almost Certain', stix: 90 },
39
+ 100..100 => { scale: 'Certain', stix: 100 }
40
+ }.freeze
41
+
42
+ SCALE_DNI = {
43
+ 0..9 => { scale: 'Almost No Chance / Remote' , stix: 5 },
44
+ 10..19 => { scale: 'Very Unlikely / Highly Improbable', stix: 15 },
45
+ 20..39 => { scale: 'Unlikely / Improbable', stix: 30 },
46
+ 40..59 => { scale: 'Roughly Even Chance / Roughly Even Odds', stix: 50 },
47
+ 60..79 => { scale: 'Likely / Probable', stix: 70 },
48
+ 80..89 => { scale: 'Very Likely / Highly Probable', stix: 85 },
49
+ 90..100 => { scale: 'Almost Certain / Nearly Certain', stix: 95 }
50
+ }.freeze
51
+
52
+ def initialize(value = nil)
53
+ @value = value
54
+ end
55
+
56
+ def to_none_low_med_high
57
+ !@value && 'Not Specified'
58
+ find_range(SCALE_NONE_LOW_MED_HIGH, :scale)
59
+ end
60
+
61
+ def to_none_low_med_high_stix
62
+ !@value && 'Not Specified'
63
+ find_range(SCALE_NONE_LOW_MED_HIGH, :stix)
64
+ end
65
+
66
+ def to_0_10
67
+ !@value && 6
68
+ find_range(SCALE_0_10, :scale)
69
+ end
70
+
71
+ def to_0_10_stix
72
+ find_range(SCALE_0_10, :stix)
73
+ end
74
+
75
+ def to_admiralty_credibility
76
+ find_range(SCALE_ADMIRALTY_CREDIBILITY, :scale)
77
+ end
78
+
79
+ def to_admiralty_credibility_stix
80
+ find_range(SCALE_ADMIRALTY_CREDIBILITY, :stix)
81
+ end
82
+
83
+ def to_wep
84
+ find_range(SCALE_WEP, :scale)
85
+ end
86
+
87
+ def to_wep_stix
88
+ find_range(SCALE_WEP, :stix)
89
+ end
90
+
91
+ def to_dni_scale
92
+ find_range(SCALE_DNI, :scale)
93
+ end
94
+
95
+ def to_dni_scale_stix
96
+ find_range(SCALE_DNI, :stix)
97
+ end
98
+
99
+ private
100
+
101
+ def find_range(constant, type)
102
+ !@value || 'Not Specified'
103
+ constant.find{ |k,v| k.cover?(@value) }.last[type]
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,20 @@
1
+ module Stix2
2
+ class CustomObject < Stix2::Common
3
+ include Hashie::Extensions::IgnoreUndeclared
4
+
5
+ property :id, coerce: Identifier
6
+
7
+ def initialize(options)
8
+ Hashie.symbolize_keys!(options)
9
+ raise('A CustomObject must have at least one property') if options[:type] && options.count == 1
10
+ errors = Hash.new{ |k, v| k[v] = [] }
11
+ options.each do |key, value|
12
+ errors['Too short'] << key if key != :id && key.size < 3
13
+ errors['Invalid name'] << key if !key.match?(/^[a-z0-9_]*$/)
14
+ errors['Too long'] << key if key.size > 250
15
+ end
16
+ raise("Error creating CustomObject: #{errors}") if !errors.empty?
17
+ super(options)
18
+ end
19
+ end
20
+ end
@@ -1,7 +1,7 @@
1
1
  module Stix2
2
2
  module CyberobservableObject
3
3
  class EmailMessage < Base
4
- property :is_multipart, required: true, coerce: Stix2::Boolean
4
+ property :is_multipart, required: true, coerce: ->(value){ Stix2.to_bool(value) }
5
5
  property :date, coerce: Time
6
6
  property :content_type, coerce: String
7
7
  property :from_ref, coerce: Identifier
@@ -3,7 +3,7 @@ module Stix2
3
3
  class NetworkTraffic < Base
4
4
  property :start, coerce: Time
5
5
  property :end, coerce: Time
6
- property :is_active, coerce: ->(v){ boolean(v) }
6
+ property :is_active, coerce: ->(v){ Stix2.to_bool(v) }
7
7
  property :src_ref, coerce: Identifier
8
8
  property :dst_ref, coerce: Identifier
9
9
  property :src_port, coerce: Integer
@@ -0,0 +1,17 @@
1
+ module Stix2
2
+ module CyberobservableObject
3
+ class Process < Base
4
+ property :is_hidden, coerce: ->(value){ Stix2.to_bool(value) }
5
+ property :pid, coerce: Integer
6
+ property :created_time, coerce: Time
7
+ property :cwd, coerce: String
8
+ property :command_line, coerce: String
9
+ property :environment_variables, coerce: Hash
10
+ property :opened_connection_refs, coerce: Array[Identifier]
11
+ property :creator_user_ref, coerce: Identifier
12
+ property :image_ref, coerce: Identifier
13
+ property :parent_ref, coerce: Identifier
14
+ property :child_refs, coerce: Array[Identifier]
15
+ end
16
+ end
17
+ end
@@ -6,10 +6,10 @@ module Stix2
6
6
  property :account_login, coerce: String
7
7
  property :account_type, values: ACCOUNT_TYPE_OV
8
8
  property :display_name, coerce: String
9
- property :is_service_account, coerce: Stix2::Boolean
10
- property :is_privileged, coerce: Stix2::Boolean
11
- property :can_escalate_privs, coerce: Stix2::Boolean
12
- property :is_disabled, coerce: Stix2::Boolean
9
+ property :is_service_account, coerce: ->(value){ Stix2.to_bool(value) }
10
+ property :is_privileged, coerce: ->(value){ Stix2.to_bool(value) }
11
+ property :can_escalate_privs, coerce: ->(value){ Stix2.to_bool(value) }
12
+ property :is_disabled, coerce: ->(value){ Stix2.to_bool(value) }
13
13
  property :account_created, coerce: Time
14
14
  property :account_expires, coerce: Time
15
15
  property :credential_last_changed, coerce: Time
@@ -1,7 +1,9 @@
1
+ require 'stix2/cyberobservable_objects/x509_v3_extension_type'
2
+
1
3
  module Stix2
2
4
  module CyberobservableObject
3
5
  class X509Certificate < Base
4
- property :is_self_signed, coerce: ->(v){ boolean(v) }
6
+ property :is_self_signed, coerce: ->(v){ Stix2.to_bool(v) }
5
7
  property :hashes, coerce: ->(hsh){ hash_dict(hsh) }
6
8
  property :version, coerce: String
7
9
  property :serial_number, coerce: String
@@ -4,7 +4,7 @@ module Stix2
4
4
  property :name, coerce: String
5
5
  property :description, coerce: String
6
6
  property :malware_types, coerce: ->(v){ validate_array(v, Stix2::MALWARE_TYPE_OV) }
7
- property :is_family, coerce: ->(v){ is_boolean?(v) }
7
+ property :is_family, coerce: ->(v){ Stix2.to_bool(v) }
8
8
  property :aliases, coerce: Array[String]
9
9
  property :kill_chain_phases, coerce: Array[KillChainPhase]
10
10
  property :first_seen, coerce: Time
data/lib/stix2/enum.rb CHANGED
@@ -29,4 +29,63 @@ module Stix2
29
29
  'REG_QWORD',
30
30
  'REG_INVALID_TYPE'
31
31
  ].freeze
32
+
33
+ EXTENSION_TYPE_ENUM = [
34
+ 'new-sdo',
35
+ 'new-sco',
36
+ 'new-sro',
37
+ 'property-extension',
38
+ 'toplevel-property-extension'
39
+ ].freeze
40
+
41
+ NETWORK_SOCKET_ADDRESS_FAMILY_ENUM = [
42
+ 'AF_UNSPEC',
43
+ 'AF_INET',
44
+ 'AF_IPX',
45
+ 'AF_APPLETALK',
46
+ 'AF_NETBIOS',
47
+ 'AF_INET6',
48
+ 'AF_IRDA',
49
+ 'AF_BTH'
50
+ ].freeze
51
+
52
+ NETWORK_SOCKET_TYPE_ENUM = [
53
+ 'SOCK_STREAM',
54
+ 'AF_ISOCK_DGRAMNET',
55
+ 'SOCK_RAW',
56
+ 'SOCK_RDM',
57
+ 'SOCK_SEQPACKET'
58
+ ].freeze
59
+
60
+ WINDOWS_INTEGRITY_LEVEL_ENUM = [
61
+ 'low',
62
+ 'medium',
63
+ 'high',
64
+ 'system'
65
+ ].freeze
66
+
67
+ WINDOWS_SERVICE_START_TYPE_ENUM = [
68
+ 'SERVICE_AUTO_START',
69
+ 'SERVICE_BOOT_START',
70
+ 'SERVICE_DEMAND_START',
71
+ 'SERVICE_DISABLED',
72
+ 'SERVICE_SYSTEM_ALERT'
73
+ ].freeze
74
+
75
+ WINDOWS_SERVICE_TYPE_ENUM = [
76
+ 'SERVICE_KERNEL_DRIVER',
77
+ 'SERVICE_FILE_SYSTEM_DRIVER',
78
+ 'SERVICE_WIN32_OWN_PROCESS',
79
+ 'SERVICE_WIN32_SHARE_PROCESS'
80
+ ].freeze
81
+
82
+ WINDOWS_SERVICE_STATUS_ENUM = [
83
+ 'SERVICE_CONTINUE_PENDING',
84
+ 'SERVICE_PAUSE_PENDING',
85
+ 'SERVICE_PAUSED',
86
+ 'SERVICE_RUNNING',
87
+ 'SERVICE_START_PENDING',
88
+ 'SERVICE_STOP_PENDING',
89
+ 'SERVICE_STOPPED'
90
+ ].freeze
32
91
  end
@@ -0,0 +1,10 @@
1
+ module Stix2
2
+ class ExtensionDefinition < Stix2::Common
3
+ property :name, required: true, coerce: String
4
+ property :description, coerce: String
5
+ property :schema, required: true, coerce: String
6
+ property :version, required: true, coerce: String
7
+ property :extension_types, required: true, coerce: ->(values){ validate_array(values, EXTENSION_TYPE_ENUM) }
8
+ property :extension_properties, coerce: Array[String]
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Stix2
2
+ module Extensions
3
+ class AlternateDataStreamType < Stix2::Base
4
+ property :name, required: true, coerce: String
5
+ property :hashes, coerce: ->(hsh){ hash_dict(hsh) }
6
+ property :size, coerce: Integer
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Stix2
2
+ module Extensions
3
+ class ArchiveFile < Stix2::Base
4
+ property :contains_refs, required: true, coerce: Array[Identifier]
5
+ property :comment, coerce: String
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ module Stix2
2
+ module Extensions
3
+ class HttpRequest < Stix2::Base
4
+ property :request_method, required: true, coerce: String
5
+ property :request_value, required: true, coerce: String
6
+ property :request_version, coerce: String
7
+ property :request_header, coerce: Hash
8
+ property :message_body_length, coerce: Integer
9
+ property :message_body_data_ref, coerce: Identifier
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module Stix2
2
+ module Extensions
3
+ class Icmp < Stix2::Base
4
+ property :icmp_type_hex, required: true, coerce: ->(value){ Stix2.is_hex?(value) && value }
5
+ property :icmp_code_hex, required: true, coerce: ->(value){ Stix2.is_hex?(value) && value }
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ require 'stix2/extensions/alternate_data_stream_type'
2
+
3
+ module Stix2
4
+ module Extensions
5
+ class Ntfs < Stix2::Base
6
+ property :sid, coerce: String
7
+ property :alternate_data_streams, coerce: Array[AlternateDataStreamType]
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Stix2
2
+ module Extensions
3
+ class Pdf < Stix2::Base
4
+ property :version, coerce: String
5
+ property :is_optimized, coerce: ->(value){ Stix2.to_bool(value) }
6
+ property :document_info_dict, Hash[String => String]
7
+ property :pdfid0, coerce: String
8
+ property :pdfid1, coerce: String
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module Stix2
2
+ module Extensions
3
+ class RasterImage < Stix2::Base
4
+ property :image_height, coerce: Integer
5
+ property :image_width, coerce: Integer
6
+ property :bits_per_pixel, coerce: Integer
7
+ property :exif_tags, coerce: Hash
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module Stix2
2
+ module Extensions
3
+ class Socket < Stix2::Base
4
+ property :address_family, required: true, values: NETWORK_SOCKET_ADDRESS_FAMILY_ENUM
5
+ property :is_blocking, coerce: ->(value){ Stix2.to_bool(value) }
6
+ property :is_listening, coerce: ->(value){ Stix2.to_bool(value) }
7
+ property :options, coerce: ->(hsh){ hsh.keys.all?{ |k| k.is_a?(Integer) } && hsh }
8
+ property :socket_type, values: NETWORK_SOCKET_TYPE_ENUM
9
+ property :socket_descriptor, coerce: Integer
10
+ property :socket_handle, coerce: Integer
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ module Stix2
2
+ module Extensions
3
+ class Tcp < Stix2::Base
4
+ property :src_flags_hex, coerce: ->(value) { Stix2.is_hex?(value) && value }
5
+ property :dst_flags_hex, coerce: ->(value) { Stix2.is_hex?(value) && value }
6
+ end
7
+ end
8
+ end