contrast-agent 3.8.5 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/cs__assess_array/cs__assess_array.c +1 -1
- data/ext/cs__assess_module/cs__assess_module.c +0 -1
- data/ext/cs__assess_yield_track/cs__assess_yield_track.c +34 -0
- data/ext/cs__assess_yield_track/cs__assess_yield_track.h +12 -0
- data/ext/{cs__scope → cs__assess_yield_track}/extconf.rb +0 -0
- data/ext/cs__common/cs__common.c +6 -6
- data/ext/cs__common/cs__common.h +3 -1
- data/ext/cs__contrast_patch/cs__contrast_patch.c +142 -119
- data/ext/cs__contrast_patch/cs__contrast_patch.h +3 -0
- data/funchook/autom4te.cache/requests +48 -48
- data/funchook/config.log +2 -2
- data/lib/contrast/agent.rb +15 -5
- data/lib/contrast/agent/assess.rb +0 -1
- data/lib/contrast/agent/assess/contrast_event.rb +9 -8
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +68 -18
- data/lib/contrast/agent/assess/policy/policy.rb +0 -14
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
- data/lib/contrast/agent/assess/policy/preshift.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagation_method.rb +4 -2
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +2 -2
- data/lib/contrast/agent/assess/policy/propagator/split.rb +166 -1
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +1 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +199 -140
- data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +30 -0
- data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +36 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +238 -153
- data/lib/contrast/agent/assess/policy/trigger_node.rb +54 -9
- data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +13 -0
- data/lib/contrast/agent/assess/properties.rb +29 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +35 -31
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +1 -1
- data/lib/contrast/agent/class_reopener.rb +98 -55
- data/lib/contrast/agent/feature_state.rb +1 -1
- data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
- data/lib/contrast/agent/logger_manager.rb +2 -2
- data/lib/contrast/agent/middleware.rb +1 -3
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +40 -4
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +33 -8
- data/lib/contrast/agent/patching/policy/method_policy.rb +20 -7
- data/lib/contrast/agent/patching/policy/patch.rb +54 -23
- data/lib/contrast/agent/patching/policy/patch_status.rb +0 -2
- data/lib/contrast/agent/patching/policy/patcher.rb +10 -11
- data/lib/contrast/agent/patching/policy/policy.rb +4 -0
- data/lib/contrast/agent/patching/policy/policy_node.rb +14 -1
- data/lib/contrast/agent/patching/policy/trigger_node.rb +2 -1
- data/lib/contrast/agent/protect/policy/policy.rb +6 -6
- data/lib/contrast/agent/protect/rule/base.rb +1 -1
- data/lib/contrast/agent/protect/rule/deserialization.rb +3 -25
- data/lib/contrast/agent/protect/rule/sqli.rb +1 -1
- data/lib/contrast/agent/railtie.rb +11 -5
- data/lib/contrast/agent/request.rb +1 -19
- data/lib/contrast/agent/request_context.rb +1 -1
- data/lib/contrast/agent/rewriter.rb +4 -3
- data/lib/contrast/agent/scope.rb +116 -19
- data/lib/contrast/agent/service_heartbeat.rb +5 -2
- data/lib/contrast/agent/settings_state.rb +12 -8
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api.rb +1 -0
- data/lib/contrast/api/speedracer.rb +2 -2
- data/lib/contrast/components/agent.rb +26 -7
- data/lib/contrast/components/app_context.rb +8 -45
- data/lib/contrast/components/contrast_service.rb +3 -4
- data/lib/contrast/components/interface.rb +1 -1
- data/lib/contrast/components/scope.rb +56 -26
- data/lib/contrast/config/ruby_configuration.rb +8 -3
- data/lib/contrast/delegators.rb +9 -0
- data/lib/contrast/delegators/application_update.rb +32 -0
- data/lib/contrast/extensions/framework/rack/cookie.rb +24 -0
- data/lib/contrast/extensions/framework/rack/request.rb +24 -0
- data/lib/contrast/extensions/framework/rack/response.rb +23 -0
- data/lib/contrast/extensions/framework/rails/action_controller_railties_helper_inherited.rb +20 -0
- data/lib/contrast/extensions/framework/rails/active_record.rb +26 -0
- data/lib/contrast/extensions/framework/rails/active_record_named.rb +53 -0
- data/lib/contrast/extensions/framework/rails/active_record_time_zone_inherited.rb +21 -0
- data/lib/contrast/extensions/framework/rails/buffer.rb +28 -0
- data/lib/contrast/extensions/framework/rails/configuration.rb +27 -0
- data/lib/contrast/extensions/framework/sinatra/base.rb +59 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess.rb +12 -11
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/array.rb +4 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/assess_extension.rb +0 -2
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/basic_object.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/erb.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/exec_trigger.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/fiber.rb +3 -4
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/hash.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/kernel.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/module.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/regexp.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/string.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/tilt_template_trigger.rb +0 -0
- data/lib/contrast/extensions/ruby_core/assess/xpath_library_trigger.rb +40 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/delegator.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/eval_trigger.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory/datastores.rb +1 -1
- data/lib/contrast/extensions/ruby_core/module.rb +17 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_command_injection_rule.rb +8 -6
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_deserialization_rule.rb +7 -5
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_no_sqli_rule.rb +5 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_path_traversal_rule.rb +31 -27
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_sqli_rule.rb +5 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_xxe_rule.rb +9 -7
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/kernel.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/psych.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/thread.rb +0 -0
- data/lib/contrast/framework/base_support.rb +63 -0
- data/lib/contrast/framework/manager.rb +109 -0
- data/lib/contrast/framework/platform_version.rb +21 -0
- data/lib/contrast/framework/rails_support.rb +88 -0
- data/lib/contrast/framework/sinatra_application_helper.rb +49 -0
- data/lib/contrast/framework/sinatra_support.rb +94 -0
- data/lib/contrast/framework/view_technologies_descriptor.rb +20 -0
- data/lib/contrast/utils/assess/tracking_util.rb +2 -4
- data/lib/contrast/utils/class_util.rb +92 -37
- data/lib/contrast/utils/duck_utils.rb +59 -39
- data/lib/contrast/utils/environment_util.rb +5 -75
- data/lib/contrast/utils/freeze_util.rb +3 -7
- data/lib/contrast/utils/invalid_configuration_util.rb +5 -5
- data/lib/contrast/utils/job_servers_running.rb +39 -0
- data/lib/contrast/utils/ruby_ast_rewriter.rb +2 -2
- data/lib/contrast/utils/service_response_util.rb +0 -6
- data/lib/contrast/utils/sinatra_helper.rb +6 -0
- data/lib/contrast/utils/stack_trace_utils.rb +1 -1
- data/resources/assess/policy.json +74 -23
- data/resources/inventory/policy.json +1 -1
- data/resources/protect/policy.json +11 -9
- data/resources/rubocops/object/frozen_cop.rb +1 -1
- data/ruby-agent.gemspec +2 -0
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +94 -57
- data/ext/cs__scope/cs__scope.c +0 -96
- data/ext/cs__scope/cs__scope.h +0 -33
- data/lib/contrast/agent/assess/class_reverter.rb +0 -82
- data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +0 -28
- data/lib/contrast/core_extensions/module.rb +0 -42
- data/lib/contrast/core_extensions/object.rb +0 -27
- data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +0 -48
- data/lib/contrast/rails_extensions/assess/active_record.rb +0 -32
- data/lib/contrast/rails_extensions/assess/active_record_named.rb +0 -61
- data/lib/contrast/rails_extensions/assess/configuration.rb +0 -26
- data/lib/contrast/rails_extensions/buffer.rb +0 -30
- data/lib/contrast/rails_extensions/rack.rb +0 -45
- data/lib/contrast/sinatra_extensions/assess/cookie.rb +0 -26
- data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +0 -59
- data/lib/contrast/utils/operating_environment.rb +0 -38
- data/lib/contrast/utils/path_util.rb +0 -151
- data/lib/contrast/utils/scope_util.rb +0 -99
@@ -3,55 +3,75 @@
|
|
3
3
|
|
4
4
|
module Contrast
|
5
5
|
module Utils
|
6
|
-
# Utility methods for identifying instances that can be used
|
6
|
+
# Utility methods for identifying instances that can be used interchangeably
|
7
7
|
class DuckUtils
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
class << self
|
9
|
+
# Determine if the given object, or the object to which it delegates,
|
10
|
+
# responds to the given method.
|
11
|
+
#
|
12
|
+
# @param object [Object]
|
13
|
+
# @param method [Symbol]
|
14
|
+
# @return [Boolean]
|
15
|
+
def quacks_to? object, method
|
16
|
+
return true if object.cs__respond_to?(method)
|
17
|
+
return false unless object.is_a?(Delegator)
|
11
18
|
|
12
|
-
|
13
|
-
|
19
|
+
object.cs__delegator_respond_to?(method)
|
20
|
+
end
|
14
21
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
#
|
19
|
-
#
|
20
|
-
return
|
21
|
-
|
22
|
+
# Most things that are closable IO's will in fact be of the IO type. That
|
23
|
+
# being said, some will also be extensions of DelegateClass with IO type,
|
24
|
+
# like Tempfile. We need to handle both cases.
|
25
|
+
#
|
26
|
+
# @param object [Object]
|
27
|
+
# @return [Boolean]
|
28
|
+
def closable_io? object
|
29
|
+
return false unless Contrast::Utils::IOUtil.io?(object)
|
22
30
|
|
23
|
-
|
24
|
-
|
31
|
+
quacks_to?(object, :closed?)
|
32
|
+
end
|
25
33
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
34
|
+
# Determine if the given Object is a Hash, or similar enough to a hash
|
35
|
+
# for us to iterate on it using the #each_pair method
|
36
|
+
#
|
37
|
+
# @param object [Object]
|
38
|
+
# @return [Boolean]
|
39
|
+
def iterable_hash? object
|
40
|
+
# do iterate on things believed to safely implement #each_pair
|
41
|
+
return true if object.cs__is_a?(Hash)
|
32
42
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
# https://stackoverflow.com/questions/20954789/how-do-i-check-if-a-variable-really-responds-to-dup
|
37
|
-
def self.quacks_like_duplicable? obj
|
38
|
-
obj.cs__class.methods.include? :new
|
39
|
-
end
|
43
|
+
# otherwise, don't risk it
|
44
|
+
false
|
45
|
+
end
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
return
|
47
|
+
# Determine if the given Object is a concrete implementation of
|
48
|
+
# Enumerable known to be safe to call #each on.
|
49
|
+
#
|
50
|
+
# @param object [Object]
|
51
|
+
# @return [Boolean]
|
52
|
+
def iterable_enumerable? object
|
53
|
+
# do iterate on things believed to safely implement #each. We're
|
54
|
+
# purposefully skipping Hash and Hash-like things here as
|
55
|
+
# #iterable_hash? should handle those.
|
56
|
+
return true if object.cs__is_a?(Array)
|
57
|
+
return true if object.cs__is_a?(Enumerator)
|
58
|
+
return true if object.cs__is_a?(Hash)
|
59
|
+
return true if object.cs__is_a?(Range)
|
60
|
+
return true if object.cs__is_a?(Set)
|
46
61
|
|
47
|
-
|
48
|
-
|
62
|
+
# otherwise, don't risk it
|
63
|
+
false
|
64
|
+
end
|
49
65
|
|
50
|
-
|
51
|
-
|
52
|
-
|
66
|
+
# This method will return true if the object being checked has been patched
|
67
|
+
# to have the cs__properties field. We check the cs__tracked? method since it
|
68
|
+
# is side effect free (ie doesn't cause the properties object to be created).
|
69
|
+
def trackable? object
|
70
|
+
return true if object.cs__respond_to?(:cs__tracked?)
|
71
|
+
return false unless object.is_a?(Delegator)
|
53
72
|
|
54
|
-
|
73
|
+
object.cs__delegator_respond_to?(:cs__tracked?)
|
74
|
+
end
|
55
75
|
end
|
56
76
|
end
|
57
77
|
end
|
@@ -2,7 +2,8 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
cs__scoped_require 'socket'
|
5
|
-
|
5
|
+
|
6
|
+
cs__scoped_require 'contrast/extensions/ruby_core/module'
|
6
7
|
cs__scoped_require 'contrast/components/interface'
|
7
8
|
cs__scoped_require 'contrast/utils/object_share'
|
8
9
|
cs__scoped_require 'contrast/utils/string_utils'
|
@@ -12,16 +13,10 @@ module Contrast
|
|
12
13
|
# Gather information about the application and server environment
|
13
14
|
# that the agent is running in.
|
14
15
|
class EnvironmentUtil
|
15
|
-
include Contrast::Components::Interface
|
16
|
-
|
17
|
-
access_component :analysis
|
18
|
-
|
19
|
-
DEFAULT_APP_NAME = 'rack'
|
20
|
-
DEFAULT_SERVER_NAME = 'localhost'
|
21
|
-
|
22
16
|
CS_VERSION = 'VERSION'
|
23
17
|
|
24
18
|
# Possible names of constants that would hold version info
|
19
|
+
# TODO - RUBY-770
|
25
20
|
VERSION_CONSTANT_CANDIDATES = %w[
|
26
21
|
VERSION
|
27
22
|
::VERSION
|
@@ -30,16 +25,6 @@ module Contrast
|
|
30
25
|
::Application::VERSION
|
31
26
|
].cs__freeze
|
32
27
|
|
33
|
-
# Common places where view-layer files can be found in a Rails application
|
34
|
-
RAILS_VIEWS = [
|
35
|
-
['app/assets', '*.coffee', %w[CoffeeScript]],
|
36
|
-
['app/assets', '*.scss', %w[SASS]],
|
37
|
-
['app/views', '*.html', %w[HTML5]],
|
38
|
-
['app/views', '*.html.erb', %w[HTML5 ERB]],
|
39
|
-
['app/views', '*.html.haml', %w[HTML5 HAML]],
|
40
|
-
['public', '*.html', %w[HTML5]]
|
41
|
-
].cs__freeze
|
42
|
-
|
43
28
|
class << self
|
44
29
|
######### These are helpers ####################
|
45
30
|
|
@@ -50,6 +35,7 @@ module Contrast
|
|
50
35
|
######### Actually env/framework dependent ####################
|
51
36
|
|
52
37
|
# See CONTRAST-16380 for more details
|
38
|
+
# TODO RUBY-770
|
53
39
|
def determine_application_version
|
54
40
|
@_determine_application_version ||= begin
|
55
41
|
candidates = VERSION_CONSTANT_CANDIDATES.map do |name|
|
@@ -80,20 +66,9 @@ module Contrast
|
|
80
66
|
end
|
81
67
|
end
|
82
68
|
|
83
|
-
def platform
|
84
|
-
version = Rails.version rescue Sinatra::VERSION rescue Rack.version rescue '' # rubocop:disable Style/RescueModifier
|
85
|
-
major, minor, patch = *version.split(Contrast::Utils::ObjectShare::PERIOD)
|
86
|
-
major ||= ''
|
87
|
-
minor ||= ''
|
88
|
-
patch ||= ''
|
89
|
-
|
90
|
-
[major, minor, patch]
|
91
|
-
rescue StandardError
|
92
|
-
Contrast::Utils::ObjectShare::EMPTY_TRIPLE
|
93
|
-
end
|
94
|
-
|
95
69
|
# Read libraries from the gemfile and append to the given ApplicationUpdate message
|
96
70
|
# or other class that has a libraries map association
|
71
|
+
# TODO - RUBY-770
|
97
72
|
def add_library_to_app_update app_update_pb, library_tags = ''
|
98
73
|
libraries = Contrast::Utils::GemfileReader.instance.library_pb_list
|
99
74
|
libraries.each do |n|
|
@@ -101,51 +76,6 @@ module Contrast
|
|
101
76
|
app_update_pb.libraries[n.hash_code] = n
|
102
77
|
end
|
103
78
|
end
|
104
|
-
|
105
|
-
# Iterate through known locations, looking for files
|
106
|
-
# that represent view or template files. If found, for each file in the directory
|
107
|
-
# append the technology and the view object to the application update instance
|
108
|
-
def scan_views app_update_msg
|
109
|
-
return unless INVENTORY.enabled?
|
110
|
-
|
111
|
-
scan_rails_views(app_update_msg)
|
112
|
-
scan_sinatra_views(app_update_msg)
|
113
|
-
end
|
114
|
-
|
115
|
-
# Find all the predefined routes for this application and append them to the
|
116
|
-
# provided inventory message
|
117
|
-
# msg should be a Contrast::Api::Dtm::ApplicationUpdate or some other msg
|
118
|
-
# that has a routes array consisting of Contrast::Api::Dtm::RouteCoverage
|
119
|
-
def scan_routes msg
|
120
|
-
return unless INVENTORY.enabled?
|
121
|
-
|
122
|
-
Contrast::Utils::PathUtil.find_routes.each do |route|
|
123
|
-
msg.routes << route
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
private
|
128
|
-
|
129
|
-
def scan_view_directories app_update_msg, view_location_data
|
130
|
-
view_location_data.each do |path, extension, tech_names|
|
131
|
-
next if Dir["#{ path }/**/*#{ extension }"].empty?
|
132
|
-
|
133
|
-
tech_names.each do |tech|
|
134
|
-
app_update_msg.technologies[tech] = true
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def scan_rails_views app_update_msg
|
140
|
-
scan_view_directories(app_update_msg, RAILS_VIEWS)
|
141
|
-
end
|
142
|
-
|
143
|
-
def scan_sinatra_views app_update_msg
|
144
|
-
sinatra_app = Contrast::Utils::SinatraHelper.app_class
|
145
|
-
return unless sinatra_app
|
146
|
-
|
147
|
-
scan_view_directories(app_update_msg, Contrast::Utils::SinatraHelper.scannable_view_dirs)
|
148
|
-
end
|
149
79
|
end
|
150
80
|
end
|
151
81
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
cs__scoped_require 'contrast/core_extensions/object'
|
5
4
|
cs__scoped_require 'contrast/utils/duck_utils'
|
6
5
|
|
7
6
|
module Contrast
|
@@ -11,21 +10,18 @@ module Contrast
|
|
11
10
|
class FreezeUtil
|
12
11
|
class << self
|
13
12
|
# Make every attempt to duplicate the frozen object so that it can
|
14
|
-
# be tracked.
|
15
|
-
# but throw a TypeError. This catches that case and returns the
|
16
|
-
# original. We luck out as these three cases do not get propagated to
|
13
|
+
# be tracked.
|
17
14
|
#
|
18
15
|
# @param original [Object] something frozen, usually a String
|
19
16
|
# @return [Object] the original or an unfrozen copy
|
20
17
|
def unfreeze_dup original
|
21
18
|
return original unless original.cs__frozen?
|
22
|
-
return original unless Contrast::Utils::DuckUtils.quacks_like_duplicable?(original)
|
23
19
|
|
24
20
|
copy = original.dup
|
25
|
-
if Contrast::Utils::DuckUtils.
|
21
|
+
if Contrast::Utils::DuckUtils.iterable_hash?(copy)
|
26
22
|
copy.each_key do |key|
|
27
23
|
value = original[key]
|
28
|
-
copy[key] =
|
24
|
+
copy[key] = value.dup
|
29
25
|
end
|
30
26
|
end
|
31
27
|
copy
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
-
# frozen_string_literal:
|
2
|
+
# frozen_string_literal: true
|
3
3
|
|
4
4
|
cs__scoped_require 'contrast/components/interface'
|
5
5
|
|
@@ -11,9 +11,9 @@ module Contrast
|
|
11
11
|
include Contrast::Components::Interface
|
12
12
|
access_component :agent, :analysis, :contrast_service, :logging
|
13
13
|
|
14
|
-
CS__PATH = 'path'
|
15
|
-
CS__SESSION_ID = 'sessionId'
|
16
|
-
CS__SNIPPET = 'snippet'
|
14
|
+
CS__PATH = 'path'
|
15
|
+
CS__SESSION_ID = 'sessionId'
|
16
|
+
CS__SNIPPET = 'snippet'
|
17
17
|
|
18
18
|
# Build and report a finding for the given rule
|
19
19
|
#
|
@@ -71,7 +71,7 @@ module Contrast
|
|
71
71
|
idx = call_location&.lineno
|
72
72
|
if file_path && idx && File.exist?(file_path)
|
73
73
|
idx = idx > 5 ? idx - 5 : 0
|
74
|
-
snippet = ''
|
74
|
+
snippet = +''
|
75
75
|
File.foreach(file_path).with_index do |line, line_num|
|
76
76
|
next unless line_num >= idx
|
77
77
|
break if line_num > idx + 10
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Contrast
|
5
|
+
module Utils
|
6
|
+
# A module that detects whether any job servers attached to
|
7
|
+
# the application are running
|
8
|
+
module JobServersRunning
|
9
|
+
include Contrast::Components::Interface
|
10
|
+
access_component :logging
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def job_servers_running?
|
14
|
+
sidekiq_running? || rake_running?
|
15
|
+
end
|
16
|
+
|
17
|
+
def sidekiq_running?
|
18
|
+
return unless defined?(Sidekiq) && Sidekiq.cs__respond_to?(:server?) && Sidekiq.server?
|
19
|
+
|
20
|
+
logger.debug(nil, 'Detected the spawn of a Sidekiq process')
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def rake_running?
|
25
|
+
return unless defined?(Rake) &&
|
26
|
+
Rake.cs__respond_to?(:application) &&
|
27
|
+
Rake.application.cs__respond_to?(:top_level_tasks)
|
28
|
+
|
29
|
+
disabled_rake_tasks = Contrast::Agent::FeatureState.instance.disabled_agent_rake_tasks
|
30
|
+
has_disabled_task = Rake.application.top_level_tasks.any? { |top_level_task| disabled_rake_tasks.include?(top_level_task) }
|
31
|
+
return false unless has_disabled_task
|
32
|
+
|
33
|
+
logger.debug(nil, 'Detected startup within Rake task')
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
-
# frozen_string_literal:
|
2
|
+
# frozen_string_literal: true
|
3
3
|
|
4
4
|
cs__scoped_require 'parser/current'
|
5
5
|
|
@@ -32,7 +32,7 @@ module Contrast
|
|
32
32
|
def on_dstr node
|
33
33
|
return if node.children.all? { |child_node| child_node.type == :str }
|
34
34
|
|
35
|
-
new_content = '('
|
35
|
+
new_content = +'('
|
36
36
|
node.children.each_with_index do |child_node, index|
|
37
37
|
# A begin node looks like #{some_code} in ruby, we do a substring
|
38
38
|
# from [2...-1] to get rid of the #{ & trailing }.
|
@@ -100,12 +100,6 @@ module Contrast
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
if (dynamic_sources_map_pb = server_features&.assess&.dynamic_sources_map)
|
104
|
-
dynamic_sources_map = dynamic_sources_map_pb.keys.inject({}) do |hsh, key|
|
105
|
-
hsh[key] = dynamic_sources_map_pb[key]
|
106
|
-
end
|
107
|
-
Contrast::Agent::Assess::Policy::Policy.instance.update_dynamic_sources dynamic_sources_map
|
108
|
-
end
|
109
103
|
# This is for assess
|
110
104
|
# PERF, we could avoid here with dirty-tracking.
|
111
105
|
Contrast::Utils::Assess::SamplingUtil.instance.update
|
@@ -8,7 +8,7 @@ module Contrast
|
|
8
8
|
module Utils
|
9
9
|
# Utilities for converting ruby stack trace into DTMs
|
10
10
|
class StackTraceUtils
|
11
|
-
CONTRAST_MARKER = 'contrast/
|
11
|
+
CONTRAST_MARKER = 'contrast/extensions/ruby_core'
|
12
12
|
MONKEYPATCH_MARKER = 'cs__'
|
13
13
|
|
14
14
|
# TODO: RUBY-532
|
@@ -23,15 +23,17 @@
|
|
23
23
|
"method_visibility": "public",
|
24
24
|
"method_name":"body",
|
25
25
|
"target":"R",
|
26
|
-
"type":"BODY"
|
26
|
+
"type":"BODY",
|
27
|
+
"tags":["CROSS_SITE"]
|
27
28
|
}, {
|
28
29
|
"class_name":"Rack::Request::Env",
|
29
30
|
"instance_method": true,
|
30
31
|
"method_visibility": "public",
|
31
32
|
"method_name":"get_header",
|
33
|
+
"source": "P0",
|
32
34
|
"target":"R",
|
33
35
|
"type":"HEADER",
|
34
|
-
"tags":["NO_NEWLINES"]
|
36
|
+
"tags":["NO_NEWLINES", "CROSS_SITE"]
|
35
37
|
}, {
|
36
38
|
"class_name":"ActionDispatch::Request",
|
37
39
|
"instance_method": true,
|
@@ -39,28 +41,30 @@
|
|
39
41
|
"method_name": "raw_post",
|
40
42
|
"target": "R",
|
41
43
|
"type": "BODY",
|
42
|
-
"tags":["NO_NEWLINES"]
|
44
|
+
"tags":["NO_NEWLINES", "CROSS_SITE"]
|
43
45
|
}, {
|
44
46
|
"class_name":"Rack::Request::Helpers",
|
45
47
|
"instance_method": true,
|
46
48
|
"method_visibility": "public",
|
47
49
|
"method_name":"POST",
|
48
50
|
"target":"R",
|
49
|
-
"type":"PARAMETER"
|
51
|
+
"type":"PARAMETER",
|
52
|
+
"tags":["CROSS_SITE"]
|
50
53
|
}, {
|
51
54
|
"class_name":"Rack::Request::Helpers",
|
52
55
|
"instance_method": true,
|
53
56
|
"method_visibility": "public",
|
54
57
|
"method_name":"GET",
|
55
58
|
"target":"R",
|
56
|
-
"type":"PARAMETER"
|
59
|
+
"type":"PARAMETER",
|
60
|
+
"tags":["CROSS_SITE"]
|
57
61
|
}, {
|
58
62
|
"class_name":"Rack::Request::Helpers",
|
59
63
|
"instance_method": true,
|
60
64
|
"method_visibility": "public",
|
61
65
|
"method_name":"cookies",
|
62
66
|
"target":"R",
|
63
|
-
"type":"
|
67
|
+
"type":"COOKIE",
|
64
68
|
"tags":["NO_NEWLINES"]
|
65
69
|
}, {
|
66
70
|
"class_name":"Rack::Request::Helpers",
|
@@ -68,71 +72,72 @@
|
|
68
72
|
"method_visibility": "public",
|
69
73
|
"method_name":"url",
|
70
74
|
"target":"R",
|
71
|
-
"type":"PARAMETER"
|
75
|
+
"type":"PARAMETER",
|
76
|
+
"tags":["CROSS_SITE"]
|
72
77
|
}, {
|
73
78
|
"class_name":"Rack::Request::Helpers",
|
74
79
|
"instance_method": true,
|
75
80
|
"method_visibility": "public",
|
76
81
|
"method_name":"query_string",
|
77
82
|
"target":"R",
|
78
|
-
"type":"
|
83
|
+
"type":"BODY",
|
84
|
+
"tags":["CROSS_SITE"]
|
79
85
|
}, {
|
80
86
|
"class_name":"Rack::Request",
|
81
87
|
"instance_method": true,
|
82
88
|
"method_visibility": "public",
|
83
89
|
"method_name":"body",
|
84
90
|
"target":"R",
|
85
|
-
"type":"BODY"
|
91
|
+
"type":"BODY",
|
92
|
+
"tags":["CROSS_SITE"]
|
86
93
|
}, {
|
87
94
|
"class_name":"Rack::Request",
|
88
95
|
"instance_method": true,
|
89
96
|
"method_visibility": "public",
|
90
97
|
"method_name":"query_string",
|
91
98
|
"target":"R",
|
92
|
-
"type":"BODY"
|
99
|
+
"type":"BODY",
|
100
|
+
"tags":["CROSS_SITE"]
|
93
101
|
}, {
|
94
102
|
"class_name":"Rack::Request",
|
95
103
|
"instance_method": true,
|
96
104
|
"method_visibility": "public",
|
97
105
|
"method_name":"GET",
|
98
106
|
"target":"R",
|
99
|
-
"type":"PARAMETER"
|
107
|
+
"type":"PARAMETER",
|
108
|
+
"tags":["CROSS_SITE"]
|
100
109
|
}, {
|
101
110
|
"class_name":"Rack::Request",
|
102
111
|
"instance_method": true,
|
103
112
|
"method_visibility": "public",
|
104
113
|
"method_name":"POST",
|
105
114
|
"target":"R",
|
106
|
-
"type":"PARAMETER"
|
115
|
+
"type":"PARAMETER",
|
116
|
+
"tags":["CROSS_SITE"]
|
107
117
|
}, {
|
108
118
|
"class_name":"Rack::Request",
|
109
119
|
"instance_method": true,
|
110
120
|
"method_visibility": "public",
|
111
121
|
"method_name":"cookies",
|
112
122
|
"target":"R",
|
113
|
-
"type":"
|
123
|
+
"type":"COOKIE",
|
114
124
|
"tags":["NO_NEWLINES"]
|
115
|
-
}, {
|
116
|
-
"class_name":"Rack::Request",
|
117
|
-
"instance_method": true,
|
118
|
-
"method_visibility": "public",
|
119
|
-
"method_name":"url",
|
120
|
-
"target":"R",
|
121
|
-
"type":"BODY"
|
122
125
|
}, {
|
123
126
|
"class_name":"ActionController::Metal",
|
124
127
|
"instance_method": true,
|
125
128
|
"method_visibility": "public",
|
126
129
|
"method_name":"params",
|
127
130
|
"target":"R",
|
128
|
-
"type":"PARAMETER"
|
131
|
+
"type":"PARAMETER",
|
132
|
+
"tags":["CROSS_SITE"]
|
129
133
|
}, {
|
130
134
|
"class_name":"ActionController::StrongParameters",
|
131
135
|
"instance_method": true,
|
132
136
|
"method_visibility": "public",
|
133
137
|
"method_name":"params",
|
134
138
|
"target":"R",
|
135
|
-
"type":"PARAMETER"
|
139
|
+
"type":"PARAMETER",
|
140
|
+
"tags":["CROSS_SITE"]
|
136
141
|
}
|
137
142
|
],
|
138
143
|
"propagators":[
|
@@ -1213,6 +1218,7 @@
|
|
1213
1218
|
]
|
1214
1219
|
}, {
|
1215
1220
|
"name":"reflected-xss",
|
1221
|
+
"required_tags": ["CROSS_SITE"],
|
1216
1222
|
"disallowed_tags":["BASE64_ENCODED", "CSS_ENCODED", "CSV_ENCODED", "HTML_ENCODED", "JAVASCRIPT_ENCODED", "JAVA_ENCODED", "LDAP_ENCODED", "OS_ENCODED", "SQL_ENCODED", "URL_ENCODED", "VBSCRIPT_ENCODED", "XML_ENCODED", "XPATH_ENCODED"],
|
1217
1223
|
"triggers":[
|
1218
1224
|
{
|
@@ -1565,7 +1571,6 @@
|
|
1565
1571
|
},
|
1566
1572
|
{
|
1567
1573
|
"name": "xxe",
|
1568
|
-
"dataflow": "true",
|
1569
1574
|
"triggers": [
|
1570
1575
|
{
|
1571
1576
|
"class_name": "Ox",
|
@@ -1668,6 +1673,52 @@
|
|
1668
1673
|
"source": "P0"
|
1669
1674
|
}
|
1670
1675
|
]
|
1676
|
+
}, {
|
1677
|
+
"name": "xpath-injection",
|
1678
|
+
"disallowed_tags":["XPATH_ENCODED"],
|
1679
|
+
"triggers": [
|
1680
|
+
{
|
1681
|
+
"class_name": "XPath::Expression",
|
1682
|
+
"instance_method": true,
|
1683
|
+
"method_visibility": "private",
|
1684
|
+
"method_name": "initialize",
|
1685
|
+
"source": "P1",
|
1686
|
+
"trigger_class": "XPathLibraryTrigger",
|
1687
|
+
"trigger_method": "xpath_trigger_check"
|
1688
|
+
}, {
|
1689
|
+
"class_name": "Oga::XML::CharacterNode",
|
1690
|
+
"instance_method": true,
|
1691
|
+
"method_visibility": "public",
|
1692
|
+
"method_name": "initialize",
|
1693
|
+
"source": "P0",
|
1694
|
+
"trigger_class": "XPathLibraryTrigger",
|
1695
|
+
"trigger_method": "xpath_trigger_check"
|
1696
|
+
}, {
|
1697
|
+
"class_name": "XPather",
|
1698
|
+
"instance_method": true,
|
1699
|
+
"method_visibility": "public",
|
1700
|
+
"method_name": "get",
|
1701
|
+
"source": "P0"
|
1702
|
+
}, {
|
1703
|
+
"class_name": "XPather",
|
1704
|
+
"instance_method": true,
|
1705
|
+
"method_visibility": "public",
|
1706
|
+
"method_name": "search",
|
1707
|
+
"source": "P0"
|
1708
|
+
}, {
|
1709
|
+
"class_name": "Ox::HasAttrs",
|
1710
|
+
"instance_method": true,
|
1711
|
+
"method_visibility": "public",
|
1712
|
+
"method_name": "[]=",
|
1713
|
+
"source": "P1"
|
1714
|
+
}, {
|
1715
|
+
"class_name": "Nokogiri::XML::Node",
|
1716
|
+
"instance_method": true,
|
1717
|
+
"method_visibility": "public",
|
1718
|
+
"method_name": "[]=",
|
1719
|
+
"source": "P1"
|
1720
|
+
}
|
1721
|
+
]
|
1671
1722
|
}
|
1672
1723
|
]
|
1673
1724
|
}
|