contrast-agent 3.15.0 → 3.16.0
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.
- checksums.yaml +4 -4
- data/lib/contrast/agent.rb +2 -9
- data/lib/contrast/agent/assess/contrast_event.rb +142 -70
- data/lib/contrast/agent/assess/events/source_event.rb +1 -1
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +10 -3
- data/lib/contrast/agent/assess/policy/policy_node.rb +15 -10
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +7 -1
- data/lib/contrast/agent/assess/policy/propagator/insert.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +0 -3
- data/lib/contrast/agent/assess/policy/propagator/select.rb +1 -3
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +0 -5
- data/lib/contrast/agent/assess/policy/propagator/split.rb +12 -13
- data/lib/contrast/agent/assess/policy/propagator/substitution.rb +21 -14
- data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +4 -5
- data/lib/contrast/agent/assess/policy/trigger_method.rb +39 -14
- data/lib/contrast/agent/assess/policy/trigger_node.rb +31 -37
- data/lib/contrast/agent/assess/property/evented.rb +5 -18
- data/lib/contrast/agent/assess/property/tagged.rb +9 -3
- data/lib/contrast/agent/assess/property/updated.rb +0 -5
- data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +58 -5
- data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +23 -8
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +82 -14
- data/lib/contrast/agent/assess/tag.rb +1 -1
- data/lib/contrast/agent/at_exit_hook.rb +5 -5
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +5 -5
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +20 -20
- data/lib/contrast/agent/patching/policy/module_policy.rb +10 -10
- data/lib/contrast/agent/patching/policy/policy.rb +16 -2
- data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +3 -5
- data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +1 -1
- data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +1 -0
- data/lib/contrast/agent/request.rb +34 -34
- data/lib/contrast/agent/static_analysis.rb +6 -6
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/communication/socket_client.rb +36 -1
- data/lib/contrast/api/decorators/address.rb +13 -13
- data/lib/contrast/api/decorators/message.rb +1 -0
- data/lib/contrast/api/decorators/trace_event.rb +20 -18
- data/lib/contrast/components/app_context.rb +39 -30
- data/lib/contrast/components/contrast_service.rb +9 -9
- data/lib/contrast/components/settings.rb +20 -23
- data/lib/contrast/config/service_configuration.rb +4 -2
- data/lib/contrast/configuration.rb +1 -1
- data/lib/contrast/extension/assess/array.rb +7 -3
- data/lib/contrast/extension/assess/erb.rb +5 -0
- data/lib/contrast/extension/assess/eval_trigger.rb +6 -6
- data/lib/contrast/extension/assess/exec_trigger.rb +1 -1
- data/lib/contrast/extension/assess/fiber.rb +3 -3
- data/lib/contrast/extension/assess/hash.rb +3 -3
- data/lib/contrast/extension/assess/kernel.rb +18 -20
- data/lib/contrast/extension/assess/marshal.rb +8 -4
- data/lib/contrast/extension/assess/regexp.rb +3 -3
- data/lib/contrast/extension/assess/string.rb +13 -11
- data/lib/contrast/extension/protect/kernel.rb +3 -3
- data/lib/contrast/framework/base_support.rb +1 -1
- data/lib/contrast/framework/manager.rb +3 -3
- data/lib/contrast/framework/rack/patch/session_cookie.rb +9 -9
- data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +13 -13
- data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +10 -10
- data/lib/contrast/framework/rails/patch/support.rb +1 -1
- data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +11 -11
- data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +12 -12
- data/lib/contrast/framework/rails/rewrite/active_record_named.rb +3 -3
- data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +12 -12
- data/lib/contrast/framework/sinatra/patch/base.rb +11 -11
- data/lib/contrast/framework/sinatra/support.rb +4 -4
- data/lib/contrast/logger/log.rb +7 -2
- data/lib/contrast/utils/invalid_configuration_util.rb +2 -5
- data/resources/assess/policy.json +31 -12
- data/ruby-agent.gemspec +4 -3
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- 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
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
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
|
@@ -99,9 +99,9 @@ module Contrast
|
|
99
99
|
|
100
100
|
def instrument_fiber_track
|
101
101
|
@_instrument_fiber_variables ||= begin
|
102
|
-
|
103
|
-
|
104
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
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
|
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
|
-
|
81
|
-
|
82
|
-
|
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.
|
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
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
75
|
-
|
76
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
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
|
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
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
21
|
-
|
20
|
+
::ActiveRecord::AttributeMethods::Read::ClassMethods.class_eval do
|
21
|
+
alias_method :cs__patched_define_method_attribute, :define_method_attribute
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|