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.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_array/cs__assess_array.c +1 -1
  3. data/ext/cs__assess_module/cs__assess_module.c +0 -1
  4. data/ext/cs__assess_yield_track/cs__assess_yield_track.c +34 -0
  5. data/ext/cs__assess_yield_track/cs__assess_yield_track.h +12 -0
  6. data/ext/{cs__scope → cs__assess_yield_track}/extconf.rb +0 -0
  7. data/ext/cs__common/cs__common.c +6 -6
  8. data/ext/cs__common/cs__common.h +3 -1
  9. data/ext/cs__contrast_patch/cs__contrast_patch.c +142 -119
  10. data/ext/cs__contrast_patch/cs__contrast_patch.h +3 -0
  11. data/funchook/autom4te.cache/requests +48 -48
  12. data/funchook/config.log +2 -2
  13. data/lib/contrast/agent.rb +15 -5
  14. data/lib/contrast/agent/assess.rb +0 -1
  15. data/lib/contrast/agent/assess/contrast_event.rb +9 -8
  16. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +68 -18
  17. data/lib/contrast/agent/assess/policy/policy.rb +0 -14
  18. data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
  19. data/lib/contrast/agent/assess/policy/preshift.rb +1 -1
  20. data/lib/contrast/agent/assess/policy/propagation_method.rb +4 -2
  21. data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
  22. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
  23. data/lib/contrast/agent/assess/policy/propagator/splat.rb +2 -2
  24. data/lib/contrast/agent/assess/policy/propagator/split.rb +166 -1
  25. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +1 -0
  26. data/lib/contrast/agent/assess/policy/source_method.rb +199 -140
  27. data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +30 -0
  28. data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +36 -0
  29. data/lib/contrast/agent/assess/policy/trigger_method.rb +238 -153
  30. data/lib/contrast/agent/assess/policy/trigger_node.rb +54 -9
  31. data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +13 -0
  32. data/lib/contrast/agent/assess/properties.rb +29 -0
  33. data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +35 -31
  34. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +1 -1
  35. data/lib/contrast/agent/class_reopener.rb +98 -55
  36. data/lib/contrast/agent/feature_state.rb +1 -1
  37. data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
  38. data/lib/contrast/agent/logger_manager.rb +2 -2
  39. data/lib/contrast/agent/middleware.rb +1 -3
  40. data/lib/contrast/agent/patching/policy/after_load_patch.rb +40 -4
  41. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +33 -8
  42. data/lib/contrast/agent/patching/policy/method_policy.rb +20 -7
  43. data/lib/contrast/agent/patching/policy/patch.rb +54 -23
  44. data/lib/contrast/agent/patching/policy/patch_status.rb +0 -2
  45. data/lib/contrast/agent/patching/policy/patcher.rb +10 -11
  46. data/lib/contrast/agent/patching/policy/policy.rb +4 -0
  47. data/lib/contrast/agent/patching/policy/policy_node.rb +14 -1
  48. data/lib/contrast/agent/patching/policy/trigger_node.rb +2 -1
  49. data/lib/contrast/agent/protect/policy/policy.rb +6 -6
  50. data/lib/contrast/agent/protect/rule/base.rb +1 -1
  51. data/lib/contrast/agent/protect/rule/deserialization.rb +3 -25
  52. data/lib/contrast/agent/protect/rule/sqli.rb +1 -1
  53. data/lib/contrast/agent/railtie.rb +11 -5
  54. data/lib/contrast/agent/request.rb +1 -19
  55. data/lib/contrast/agent/request_context.rb +1 -1
  56. data/lib/contrast/agent/rewriter.rb +4 -3
  57. data/lib/contrast/agent/scope.rb +116 -19
  58. data/lib/contrast/agent/service_heartbeat.rb +5 -2
  59. data/lib/contrast/agent/settings_state.rb +12 -8
  60. data/lib/contrast/agent/version.rb +1 -1
  61. data/lib/contrast/api.rb +1 -0
  62. data/lib/contrast/api/speedracer.rb +2 -2
  63. data/lib/contrast/components/agent.rb +26 -7
  64. data/lib/contrast/components/app_context.rb +8 -45
  65. data/lib/contrast/components/contrast_service.rb +3 -4
  66. data/lib/contrast/components/interface.rb +1 -1
  67. data/lib/contrast/components/scope.rb +56 -26
  68. data/lib/contrast/config/ruby_configuration.rb +8 -3
  69. data/lib/contrast/delegators.rb +9 -0
  70. data/lib/contrast/delegators/application_update.rb +32 -0
  71. data/lib/contrast/extensions/framework/rack/cookie.rb +24 -0
  72. data/lib/contrast/extensions/framework/rack/request.rb +24 -0
  73. data/lib/contrast/extensions/framework/rack/response.rb +23 -0
  74. data/lib/contrast/extensions/framework/rails/action_controller_railties_helper_inherited.rb +20 -0
  75. data/lib/contrast/extensions/framework/rails/active_record.rb +26 -0
  76. data/lib/contrast/extensions/framework/rails/active_record_named.rb +53 -0
  77. data/lib/contrast/extensions/framework/rails/active_record_time_zone_inherited.rb +21 -0
  78. data/lib/contrast/extensions/framework/rails/buffer.rb +28 -0
  79. data/lib/contrast/extensions/framework/rails/configuration.rb +27 -0
  80. data/lib/contrast/extensions/framework/sinatra/base.rb +59 -0
  81. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess.rb +12 -11
  82. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/array.rb +4 -3
  83. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/assess_extension.rb +0 -2
  84. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/basic_object.rb +1 -1
  85. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/erb.rb +0 -0
  86. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/exec_trigger.rb +0 -0
  87. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/fiber.rb +3 -4
  88. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/hash.rb +0 -0
  89. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/kernel.rb +1 -1
  90. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/module.rb +1 -1
  91. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/regexp.rb +0 -0
  92. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/string.rb +0 -0
  93. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/tilt_template_trigger.rb +0 -0
  94. data/lib/contrast/extensions/ruby_core/assess/xpath_library_trigger.rb +40 -0
  95. data/lib/contrast/{core_extensions → extensions/ruby_core}/delegator.rb +0 -0
  96. data/lib/contrast/{core_extensions → extensions/ruby_core}/eval_trigger.rb +1 -1
  97. data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory.rb +0 -0
  98. data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory/datastores.rb +1 -1
  99. data/lib/contrast/extensions/ruby_core/module.rb +17 -0
  100. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect.rb +0 -0
  101. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_command_injection_rule.rb +8 -6
  102. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_deserialization_rule.rb +7 -5
  103. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_no_sqli_rule.rb +5 -3
  104. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_path_traversal_rule.rb +31 -27
  105. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_sqli_rule.rb +5 -3
  106. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_xxe_rule.rb +9 -7
  107. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/kernel.rb +0 -0
  108. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/psych.rb +1 -1
  109. data/lib/contrast/{core_extensions → extensions/ruby_core}/thread.rb +0 -0
  110. data/lib/contrast/framework/base_support.rb +63 -0
  111. data/lib/contrast/framework/manager.rb +109 -0
  112. data/lib/contrast/framework/platform_version.rb +21 -0
  113. data/lib/contrast/framework/rails_support.rb +88 -0
  114. data/lib/contrast/framework/sinatra_application_helper.rb +49 -0
  115. data/lib/contrast/framework/sinatra_support.rb +94 -0
  116. data/lib/contrast/framework/view_technologies_descriptor.rb +20 -0
  117. data/lib/contrast/utils/assess/tracking_util.rb +2 -4
  118. data/lib/contrast/utils/class_util.rb +92 -37
  119. data/lib/contrast/utils/duck_utils.rb +59 -39
  120. data/lib/contrast/utils/environment_util.rb +5 -75
  121. data/lib/contrast/utils/freeze_util.rb +3 -7
  122. data/lib/contrast/utils/invalid_configuration_util.rb +5 -5
  123. data/lib/contrast/utils/job_servers_running.rb +39 -0
  124. data/lib/contrast/utils/ruby_ast_rewriter.rb +2 -2
  125. data/lib/contrast/utils/service_response_util.rb +0 -6
  126. data/lib/contrast/utils/sinatra_helper.rb +6 -0
  127. data/lib/contrast/utils/stack_trace_utils.rb +1 -1
  128. data/resources/assess/policy.json +74 -23
  129. data/resources/inventory/policy.json +1 -1
  130. data/resources/protect/policy.json +11 -9
  131. data/resources/rubocops/object/frozen_cop.rb +1 -1
  132. data/ruby-agent.gemspec +2 -0
  133. data/service_executables/VERSION +1 -1
  134. data/service_executables/linux/contrast-service +0 -0
  135. data/service_executables/mac/contrast-service +0 -0
  136. metadata +94 -57
  137. data/ext/cs__scope/cs__scope.c +0 -96
  138. data/ext/cs__scope/cs__scope.h +0 -33
  139. data/lib/contrast/agent/assess/class_reverter.rb +0 -82
  140. data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +0 -28
  141. data/lib/contrast/core_extensions/module.rb +0 -42
  142. data/lib/contrast/core_extensions/object.rb +0 -27
  143. data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +0 -48
  144. data/lib/contrast/rails_extensions/assess/active_record.rb +0 -32
  145. data/lib/contrast/rails_extensions/assess/active_record_named.rb +0 -61
  146. data/lib/contrast/rails_extensions/assess/configuration.rb +0 -26
  147. data/lib/contrast/rails_extensions/buffer.rb +0 -30
  148. data/lib/contrast/rails_extensions/rack.rb +0 -45
  149. data/lib/contrast/sinatra_extensions/assess/cookie.rb +0 -26
  150. data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +0 -59
  151. data/lib/contrast/utils/operating_environment.rb +0 -38
  152. data/lib/contrast/utils/path_util.rb +0 -151
  153. 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 interchangably
6
+ # Utility methods for identifying instances that can be used interchangeably
7
7
  class DuckUtils
8
- def self.quacks_like_tracked_hash? obj
9
- return false unless obj
10
- return false if quacks_like_cs_patched?(obj)
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
- obj.is_a?(Hash)
13
- end
19
+ object.cs__delegator_respond_to?(method)
20
+ end
14
21
 
15
- def self.quacks_like_tracked_enumerable? obj
16
- return false unless obj
17
- return false if obj.is_a?(IO)
18
- # TODO: RUBY-606: temporary work around to avoid the agent treating OpenSSL::Buffering as a source,
19
- # see https://contrast.atlassian.net/browse/RUBY-588
20
- return false if defined?(OpenSSL::Buffering) && obj.is_a?(OpenSSL::Buffering)
21
- return false if quacks_like_cs_patched?(obj)
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
- obj.is_a?(Enumerable)
24
- end
31
+ quacks_to?(object, :closed?)
32
+ end
25
33
 
26
- # This method will return true if the object being checked has been patched
27
- # to have the cs__properties field. We check the cs__tracked? method since it
28
- # is side effect free (ie doesn't cause the properties object to be created).
29
- def self.quacks_like_cs_patched? obj
30
- obj && quacks_to?(obj, :cs__tracked?)
31
- end
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
- # All Objects respond to dup. Not all Objects respond nicely. Nil, True,
34
- # False and Number types respond with TypeError. This check should handle
35
- # those cases.
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
- # Most things that are closable IO's will in fact be of the IO type. That
42
- # being said, some will also be extensions of DelegateClass with IO type,
43
- # like Tempfile. We need to handle both cases.
44
- def self.quacks_like_closable_io object
45
- return false unless Contrast::Utils::IOUtil.io?(object)
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
- quacks_to?(object, :closed?)
48
- end
62
+ # otherwise, don't risk it
63
+ false
64
+ end
49
65
 
50
- def self.quacks_to? object, method
51
- return true if object.cs__respond_to?(method)
52
- return false unless object.is_a?(Delegator)
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
- object.cs__delegator_respond_to?(method)
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
- cs__scoped_require 'contrast/core_extensions/module'
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. Some things, like Nil, True, and False, respond to dup
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.quacks_like_tracked_hash?(copy)
21
+ if Contrast::Utils::DuckUtils.iterable_hash?(copy)
26
22
  copy.each_key do |key|
27
23
  value = original[key]
28
- copy[key] = Contrast::Utils::DuckUtils.quacks_like_duplicable?(original) ? value.dup : value
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: false
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'.cs__freeze
15
- CS__SESSION_ID = 'sessionId'.cs__freeze
16
- CS__SNIPPET = 'snippet'.cs__freeze
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: false
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
@@ -33,6 +33,12 @@ module Contrast
33
33
  end
34
34
  end
35
35
 
36
+ def self.settings_instance
37
+ @_settings_instance ||= begin
38
+ app_class&.settings
39
+ end
40
+ end
41
+
36
42
  def self.view_directory
37
43
  @_view_directory ||= begin
38
44
  app_class&.settings&.views
@@ -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/core_extensions'
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":"PARAMETER",
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":"PARAMETER"
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":"PARAMETER",
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
  }