contrast-agent 3.15.0 → 3.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/lib/contrast/agent.rb +2 -9
  3. data/lib/contrast/agent/assess/contrast_event.rb +142 -70
  4. data/lib/contrast/agent/assess/events/source_event.rb +1 -1
  5. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +10 -3
  6. data/lib/contrast/agent/assess/policy/policy_node.rb +15 -10
  7. data/lib/contrast/agent/assess/policy/policy_scanner.rb +7 -1
  8. data/lib/contrast/agent/assess/policy/propagator/insert.rb +1 -1
  9. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +0 -3
  10. data/lib/contrast/agent/assess/policy/propagator/select.rb +1 -3
  11. data/lib/contrast/agent/assess/policy/propagator/splat.rb +0 -5
  12. data/lib/contrast/agent/assess/policy/propagator/split.rb +12 -13
  13. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +21 -14
  14. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +4 -5
  15. data/lib/contrast/agent/assess/policy/trigger_method.rb +39 -14
  16. data/lib/contrast/agent/assess/policy/trigger_node.rb +31 -37
  17. data/lib/contrast/agent/assess/property/evented.rb +5 -18
  18. data/lib/contrast/agent/assess/property/tagged.rb +9 -3
  19. data/lib/contrast/agent/assess/property/updated.rb +0 -5
  20. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +58 -5
  21. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +23 -8
  22. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +82 -14
  23. data/lib/contrast/agent/assess/tag.rb +1 -1
  24. data/lib/contrast/agent/at_exit_hook.rb +5 -5
  25. data/lib/contrast/agent/patching/policy/after_load_patch.rb +5 -5
  26. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +20 -20
  27. data/lib/contrast/agent/patching/policy/module_policy.rb +10 -10
  28. data/lib/contrast/agent/patching/policy/policy.rb +16 -2
  29. data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +3 -5
  30. data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +1 -1
  31. data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +1 -0
  32. data/lib/contrast/agent/request.rb +34 -34
  33. data/lib/contrast/agent/static_analysis.rb +6 -6
  34. data/lib/contrast/agent/version.rb +1 -1
  35. data/lib/contrast/api/communication/socket_client.rb +36 -1
  36. data/lib/contrast/api/decorators/address.rb +13 -13
  37. data/lib/contrast/api/decorators/message.rb +1 -0
  38. data/lib/contrast/api/decorators/trace_event.rb +20 -18
  39. data/lib/contrast/components/app_context.rb +39 -30
  40. data/lib/contrast/components/contrast_service.rb +9 -9
  41. data/lib/contrast/components/settings.rb +20 -23
  42. data/lib/contrast/config/service_configuration.rb +4 -2
  43. data/lib/contrast/configuration.rb +1 -1
  44. data/lib/contrast/extension/assess/array.rb +7 -3
  45. data/lib/contrast/extension/assess/erb.rb +5 -0
  46. data/lib/contrast/extension/assess/eval_trigger.rb +6 -6
  47. data/lib/contrast/extension/assess/exec_trigger.rb +1 -1
  48. data/lib/contrast/extension/assess/fiber.rb +3 -3
  49. data/lib/contrast/extension/assess/hash.rb +3 -3
  50. data/lib/contrast/extension/assess/kernel.rb +18 -20
  51. data/lib/contrast/extension/assess/marshal.rb +8 -4
  52. data/lib/contrast/extension/assess/regexp.rb +3 -3
  53. data/lib/contrast/extension/assess/string.rb +13 -11
  54. data/lib/contrast/extension/protect/kernel.rb +3 -3
  55. data/lib/contrast/framework/base_support.rb +1 -1
  56. data/lib/contrast/framework/manager.rb +3 -3
  57. data/lib/contrast/framework/rack/patch/session_cookie.rb +9 -9
  58. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +13 -13
  59. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +10 -10
  60. data/lib/contrast/framework/rails/patch/support.rb +1 -1
  61. data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +11 -11
  62. data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +12 -12
  63. data/lib/contrast/framework/rails/rewrite/active_record_named.rb +3 -3
  64. data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +12 -12
  65. data/lib/contrast/framework/sinatra/patch/base.rb +11 -11
  66. data/lib/contrast/framework/sinatra/support.rb +4 -4
  67. data/lib/contrast/logger/log.rb +7 -2
  68. data/lib/contrast/utils/invalid_configuration_util.rb +2 -5
  69. data/resources/assess/policy.json +31 -12
  70. data/ruby-agent.gemspec +4 -3
  71. data/service_executables/VERSION +1 -1
  72. data/service_executables/linux/contrast-service +0 -0
  73. data/service_executables/mac/contrast-service +0 -0
  74. metadata +31 -17
@@ -14,6 +14,7 @@ module ERBPropagator
14
14
  binding_variable_set = used_binding.local_variables
15
15
 
16
16
  erb_pre_result = preshift.object.src
17
+ parent_events = []
17
18
  binding_variable_set.each do |bound_var_symbol|
18
19
  bound_variable_value = used_binding.local_variable_get(bound_var_symbol)
19
20
  next unless Contrast::Agent::Assess::Tracker.tracked?(bound_variable_value)
@@ -23,6 +24,8 @@ module ERBPropagator
23
24
  next if start_index.nil?
24
25
 
25
26
  properties.copy_from(bound_variable_value, ret, start_index)
27
+ parent_event = Contrast::Agent::Assess::Tracker.properties(bound_variable_value)&.event
28
+ parent_events << parent_event if parent_event
26
29
  end
27
30
  properties.build_event(
28
31
  patcher,
@@ -31,6 +34,8 @@ module ERBPropagator
31
34
  ret,
32
35
  preshift.args,
33
36
  1)
37
+ properties.event.instance_variable_set(:@_parent_events, parent_events)
38
+
34
39
  ret
35
40
  end
36
41
  end
@@ -45,9 +45,9 @@ module Contrast
45
45
 
46
46
  def instrument_basic_object_track
47
47
  @_instrument_basic_object_track ||= begin
48
- require 'cs__assess_basic_object/cs__assess_basic_object'
49
- true
50
- end
48
+ require 'cs__assess_basic_object/cs__assess_basic_object'
49
+ true
50
+ end
51
51
  rescue StandardError, LoadError => e
52
52
  logger.error('Error loading basic object track patch', e)
53
53
  false
@@ -55,9 +55,9 @@ module Contrast
55
55
 
56
56
  def instrument_module_track
57
57
  @_instrument_module_track ||= begin
58
- require 'cs__assess_module/cs__assess_module'
59
- true
60
- end
58
+ require 'cs__assess_module/cs__assess_module'
59
+ true
60
+ end
61
61
  rescue StandardError, LoadError => e
62
62
  logger.error('Error loading module track patch', e)
63
63
  false
@@ -27,7 +27,7 @@ module Contrast
27
27
  source,
28
28
  Kernel,
29
29
  nil,
30
- source)
30
+ [source])
31
31
  # Exec replaces the current process, if we occur in a forked process
32
32
  # our appendage of this finding will not make it to TS
33
33
  Contrast::Agent::AtExitHook.on_exit
@@ -99,9 +99,9 @@ module Contrast
99
99
 
100
100
  def instrument_fiber_track
101
101
  @_instrument_fiber_variables ||= begin
102
- require 'cs__assess_fiber_track/cs__assess_fiber_track' if Funchook.available?
103
- true
104
- end
102
+ require 'cs__assess_fiber_track/cs__assess_fiber_track' if Funchook.available?
103
+ true
104
+ end
105
105
  rescue StandardError, LoadError => e
106
106
  logger.error('Error loading fiber track patch', e)
107
107
  false
@@ -26,9 +26,9 @@ module Contrast
26
26
 
27
27
  def instrument_hash_track
28
28
  @_instrument_hash_track ||= begin
29
- require 'cs__assess_hash/cs__assess_hash'
30
- true
31
- end
29
+ require 'cs__assess_hash/cs__assess_hash'
30
+ true
31
+ end
32
32
  rescue StandardError, LoadError => e
33
33
  logger.error('Error loading hash track patch', e)
34
34
  false
@@ -45,7 +45,8 @@ module Contrast
45
45
  format_string = preshift.args[0]
46
46
  args = preshift.args[1]
47
47
 
48
- track_sprintf(ret, format_string, args)
48
+ parent_events = []
49
+ track_sprintf(ret, format_string, args, parent_events)
49
50
 
50
51
  properties.build_event(
51
52
  patcher,
@@ -54,32 +55,31 @@ module Contrast
54
55
  ret,
55
56
  preshift.args,
56
57
  1)
58
+
59
+ properties.event.instance_variable_set(:@_parent_events, parent_events)
57
60
  ret
58
61
  end
59
62
 
60
- def track_sprintf result, format_string, args
61
- handle_sprintf_value(format_string, result)
63
+ def track_sprintf result, format_string, args, parent_events
64
+ handle_sprintf_value(format_string, result, parent_events)
62
65
  case args
63
66
  when String
64
- handle_sprintf_value(args, result)
67
+ handle_sprintf_value(args, result, parent_events)
65
68
  when Hash
66
- handle_sprintf_hash(args, result)
69
+ handle_sprintf_hash(args, result, parent_events)
67
70
  when Array
68
- handle_sprintf_array args, result
71
+ handle_sprintf_array(args, result, parent_events)
69
72
  end
70
-
71
- result
72
73
  rescue StandardError => e
73
74
  logger.error(
74
75
  'Unable to track dataflow through sprintf', e)
75
- result
76
76
  end
77
77
 
78
78
  def instrument_kernel_track
79
79
  @_instrument_fiber_variables ||= begin
80
- require 'cs__assess_kernel/cs__assess_kernel'
81
- true
82
- end
80
+ require 'cs__assess_kernel/cs__assess_kernel'
81
+ true
82
+ end
83
83
  rescue StandardError, LoadError => e
84
84
  logger.error('Error loading kernel track patch', e)
85
85
  false
@@ -87,28 +87,26 @@ module Contrast
87
87
 
88
88
  private
89
89
 
90
- def handle_sprintf_value value, result
90
+ def handle_sprintf_value value, result, parent_events
91
91
  properties = Contrast::Agent::Assess::Tracker.properties(result)
92
92
  return unless properties
93
93
 
94
94
  value_properties = Contrast::Agent::Assess::Tracker.properties(value)
95
95
  return unless value_properties
96
96
 
97
- value_properties.events.each do |event|
98
- properties.events << event
99
- end
97
+ parent_events << value_properties.event if value_properties.event
100
98
  properties.splat_from(value, result)
101
99
  end
102
100
 
103
- def handle_sprintf_array args, result
101
+ def handle_sprintf_array args, result, parent_events
104
102
  args.each do |value|
105
- handle_sprintf_value(value, result)
103
+ handle_sprintf_value(value, result, parent_events)
106
104
  end
107
105
  end
108
106
 
109
- def handle_sprintf_hash args, result
107
+ def handle_sprintf_hash args, result, parent_events
110
108
  args.each_value do |value|
111
- handle_sprintf_value(value, result)
109
+ handle_sprintf_value(value, result, parent_events)
112
110
  end
113
111
  end
114
112
  end
@@ -24,6 +24,7 @@ module Contrast
24
24
  # optimization here and return when it is not tracked
25
25
  return unless Contrast::Agent::Assess::Tracker.tracked?(source)
26
26
 
27
+ args = [source]
27
28
  # source might not be all the args passed in, but it is the one we care
28
29
  # about. we could pass in all the args in the last param here if it
29
30
  # becomes an issue in rendering on TS
@@ -33,18 +34,21 @@ module Contrast
33
34
  source,
34
35
  self,
35
36
  ret,
36
- source)
37
+ args)
37
38
  properties = Contrast::Agent::Assess::Tracker.properties(ret)
38
39
  properties.copy_from(source, ret)
40
+
41
+ node = Contrast::Agent::Assess::Policy::Policy.instance.find_propagator_node('Marshal', :load, false)
42
+ properties.build_event(node, ret, self, ret, args)
39
43
  rescue StandardError => e
40
44
  logger.error('Unable to determine if a trigger occurred in Marshal.load', e)
41
45
  end
42
46
 
43
47
  def instrument_marshal_load
44
48
  @_instrument_marshal_load ||= begin
45
- require 'cs__assess_marshal_module/cs__assess_marshal_module'
46
- true
47
- end
49
+ require 'cs__assess_marshal_module/cs__assess_marshal_module'
50
+ true
51
+ end
48
52
  rescue StandardError, LoadError => e
49
53
  logger.error('Error loading marshal load patch', e)
50
54
  false
@@ -71,9 +71,9 @@ module Contrast
71
71
 
72
72
  def instrument_regexp_track
73
73
  @_instrument_regexp_track ||= begin
74
- require 'cs__assess_regexp/cs__assess_regexp'
75
- true
76
- end
74
+ require 'cs__assess_regexp/cs__assess_regexp'
75
+ true
76
+ end
77
77
  rescue StandardError, LoadError => e
78
78
  logger.error('Error loading regexp track patch', e)
79
79
  false
@@ -39,12 +39,16 @@ module Contrast
39
39
  properties = Contrast::Agent::Assess::Tracker.properties(result)
40
40
  return unless properties
41
41
 
42
+ parent_events = []
42
43
  offset = 0
43
44
  inputs.each do |input|
44
45
  properties.copy_from(input, result, offset)
45
46
  offset += input.length
47
+ parent_event = Contrast::Agent::Assess::Tracker.properties(input)&.event
48
+ parent_events << parent_event if parent_event
46
49
  end
47
50
  properties.build_event(INTERPOLATION_NODE, result, inputs, result, inputs)
51
+ properties.event.instance_variable_set(:@_parent_events, parent_events)
48
52
  end
49
53
  rescue StandardError => e
50
54
  logger.error('Unable to track interpolation', e)
@@ -52,9 +56,9 @@ module Contrast
52
56
 
53
57
  def instrument_string
54
58
  @_instrument_string ||= begin
55
- require 'cs__assess_string/cs__assess_string'
56
- true
57
- end
59
+ require 'cs__assess_string/cs__assess_string'
60
+ true
61
+ end
58
62
  rescue StandardError, LoadError => e
59
63
  logger.error('Error loading hash track patch', e)
60
64
  false
@@ -63,14 +67,12 @@ module Contrast
63
67
  def instrument_string_interpolation
64
68
  if @_instrument_string_interpolation.nil?
65
69
  @_instrument_string_interpolation = begin
66
- if AGENT.patch_interpolation? && Funchook.available?
67
- require 'cs__assess_string_interpolation26/cs__assess_string_interpolation26'
68
- end
69
- true
70
- rescue StandardError, LoadError => e
71
- logger.error('Error loading interpolation patch', e)
72
- false
73
- end
70
+ require 'cs__assess_string_interpolation26/cs__assess_string_interpolation26' if AGENT.patch_interpolation? && Funchook.available?
71
+ true
72
+ rescue StandardError, LoadError => e
73
+ logger.error('Error loading interpolation patch', e)
74
+ false
75
+ end
74
76
  end
75
77
  @_instrument_string_interpolation
76
78
  end
@@ -30,9 +30,9 @@ module Contrast
30
30
 
31
31
  def instrument
32
32
  @_instrument ||= begin
33
- require 'cs__protect_kernel/cs__protect_kernel'
34
- true
35
- end
33
+ require 'cs__protect_kernel/cs__protect_kernel'
34
+ true
35
+ end
36
36
  rescue StandardError, LoadError => e
37
37
  logger.error('Error loading kernel protect patch', e)
38
38
  false
@@ -46,7 +46,7 @@ module Contrast
46
46
  #
47
47
  # By default, and hopefully in all cases, we won't need these patches,
48
48
  # so we're allowing nil here rather than raising an exception.
49
- def before_load_patches; end
49
+ def before_load_patches!; end
50
50
 
51
51
  # Some Frameworks require specific patching for their classes to handle
52
52
  # functionality like routing. To accommodate this, this method provides
@@ -39,9 +39,9 @@ module Contrast
39
39
  # configuration.
40
40
  def before_load_patches!
41
41
  @_before_load_patches ||= begin
42
- SUPPORTED_FRAMEWORKS.each(&:before_load_patches)
43
- true
44
- end
42
+ SUPPORTED_FRAMEWORKS.each(&:before_load_patches!)
43
+ true
44
+ end
45
45
  end
46
46
 
47
47
  # Return all the After Load Patches for all the Frameworks we know, even
@@ -24,15 +24,15 @@ module Contrast
24
24
 
25
25
  def instrument
26
26
  @_instrument ||= begin
27
- ::Rack::Session::Cookie.class_eval do
28
- alias_method :cs__patched_initialize, :initialize
29
- def initialize app, options = {}
30
- Contrast::Framework::Rack::Patch::SessionCookie.analyze(options)
31
- cs__patched_initialize(app, options)
32
- end
33
- end
34
- true
35
- end
27
+ ::Rack::Session::Cookie.class_eval do
28
+ alias_method :cs__patched_initialize, :initialize
29
+ def initialize app, options = {}
30
+ Contrast::Framework::Rack::Patch::SessionCookie.analyze(options)
31
+ cs__patched_initialize(app, options)
32
+ end
33
+ end
34
+ true
35
+ end
36
36
  end
37
37
 
38
38
  def analyze options
@@ -19,19 +19,19 @@ module Contrast
19
19
 
20
20
  def instrument
21
21
  @_instrument ||= begin
22
- ::ActionController::Live::Buffer.class_eval do
23
- # normally pre->in->post filters are applied however, in a streamed response
24
- # we can run into a case where it's pre -> in -> post -> more infilters
25
- # in order to submit anything found during the infilters after the response has
26
- # been written we need to explicitly send them
27
- alias_method :cs__close, :close
28
- def close
29
- Contrast::Framework::Rails::Patch::ActionControllerLiveBuffer.send_messages
30
- cs__close
31
- end
32
- end
33
- true
34
- end
22
+ ::ActionController::Live::Buffer.class_eval do
23
+ # normally pre->in->post filters are applied however, in a streamed response
24
+ # we can run into a case where it's pre -> in -> post -> more infilters
25
+ # in order to submit anything found during the infilters after the response has
26
+ # been written we need to explicitly send them
27
+ alias_method :cs__close, :close
28
+ def close
29
+ Contrast::Framework::Rails::Patch::ActionControllerLiveBuffer.send_messages
30
+ cs__close
31
+ end
32
+ end
33
+ true
34
+ end
35
35
  end
36
36
  end
37
37
  end
@@ -13,16 +13,16 @@ module Contrast
13
13
  class RailsApplicationConfiguration
14
14
  def self.instrument
15
15
  @_instrument ||= begin
16
- ::Rails::Application::Configuration.class_eval do
17
- alias_method :cs__patched_session_store, :session_store
18
- def session_store *args
19
- ret = cs__patched_session_store(*args)
20
- Contrast::Framework::Rails::Patch::AssessConfiguration.analyze_session_store(*args)
21
- ret
22
- end
23
- end
24
- true
25
- end
16
+ ::Rails::Application::Configuration.class_eval do
17
+ alias_method :cs__patched_session_store, :session_store
18
+ def session_store *args
19
+ ret = cs__patched_session_store(*args)
20
+ Contrast::Framework::Rails::Patch::AssessConfiguration.analyze_session_store(*args)
21
+ ret
22
+ end
23
+ end
24
+ true
25
+ end
26
26
  end
27
27
  end
28
28
  end
@@ -11,7 +11,7 @@ module Contrast
11
11
  # Extension point allowing for the registration of Patches required to
12
12
  # support the Rails framework.
13
13
  module Support
14
- # (See BaseSupport#before_load_patches)
14
+ # (See BaseSupport#before_load_patches!)
15
15
  def before_load_patches!
16
16
  return unless defined?(::Rails)
17
17
 
@@ -15,17 +15,17 @@ module Contrast
15
15
  class ActionControllerRailtiesHelperInherited
16
16
  def self.instrument
17
17
  @_instrument ||= begin
18
- ::ActionController::Railties::Helpers.class_eval do
19
- alias_method :cs__patched_helper_inherited, :inherited
20
- def inherited klass # rubocop:disable Lint/MissingSuper
21
- klass&.instance_variable_set(:@cs__defining_class, true)
22
- cs__patched_helper_inherited(klass) # This calls the original inherited, which should handle super as needed.
23
- ensure
24
- klass&.instance_variable_set(:@cs__defining_class, false)
25
- end
26
- end
27
- true
28
- end
18
+ ::ActionController::Railties::Helpers.class_eval do
19
+ alias_method :cs__patched_helper_inherited, :inherited
20
+ def inherited klass # rubocop:disable Lint/MissingSuper
21
+ klass&.instance_variable_set(:@cs__defining_class, true)
22
+ cs__patched_helper_inherited(klass) # This calls the original inherited, which should handle super as needed.
23
+ ensure
24
+ klass&.instance_variable_set(:@cs__defining_class, false)
25
+ end
26
+ end
27
+ true
28
+ end
29
29
  end
30
30
  end
31
31
  end
@@ -17,20 +17,20 @@ module Contrast
17
17
  class ActiveRecordAttributeMethodsRead
18
18
  def self.instrument
19
19
  @_instrument ||= begin
20
- ::ActiveRecord::AttributeMethods::Read::ClassMethods.class_eval do
21
- alias_method :cs__patched_define_method_attribute, :define_method_attribute
20
+ ::ActiveRecord::AttributeMethods::Read::ClassMethods.class_eval do
21
+ alias_method :cs__patched_define_method_attribute, :define_method_attribute
22
22
 
23
- def define_method_attribute *args, &block
24
- ret = cs__patched_define_method_attribute(*args, &block)
25
- method_name = args[0]
26
- Contrast::Agent::Assess::Policy::Patcher.patch_assess_method(self, method_name)
27
- ret
28
- end
23
+ def define_method_attribute *args, &block
24
+ ret = cs__patched_define_method_attribute(*args, &block)
25
+ method_name = args[0]
26
+ Contrast::Agent::Assess::Policy::Patcher.patch_assess_method(self, method_name)
27
+ ret
28
+ end
29
29
 
30
- protected :cs__patched_define_method_attribute, :define_method_attribute
31
- end
32
- true
33
- end
30
+ protected :cs__patched_define_method_attribute, :define_method_attribute
31
+ end
32
+ true
33
+ end
34
34
  end
35
35
  end
36
36
  end