contrast-agent 6.7.0 → 6.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -2
  3. data/.simplecov +0 -1
  4. data/Rakefile +0 -1
  5. data/ext/cs__assess_array/cs__assess_array.c +41 -10
  6. data/ext/cs__assess_array/cs__assess_array.h +4 -1
  7. data/lib/contrast/agent/assess/policy/trigger_method.rb +2 -2
  8. data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +1 -1
  9. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +1 -1
  10. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +1 -1
  11. data/lib/contrast/agent/excluder.rb +52 -34
  12. data/lib/contrast/agent/exclusion_matcher.rb +21 -9
  13. data/lib/contrast/agent/middleware.rb +4 -4
  14. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +6 -0
  15. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +146 -127
  16. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +20 -0
  17. data/lib/contrast/agent/protect/policy/rule_applicator.rb +1 -1
  18. data/lib/contrast/agent/protect/rule/base.rb +45 -53
  19. data/lib/contrast/agent/protect/rule/base_service.rb +48 -24
  20. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +98 -0
  21. data/lib/contrast/agent/protect/rule/bot_blocker.rb +81 -0
  22. data/lib/contrast/agent/protect/rule/cmd_injection.rb +18 -1
  23. data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +8 -5
  24. data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +22 -22
  25. data/lib/contrast/agent/protect/rule/cmdi/cmdi_chained_command.rb +69 -0
  26. data/lib/contrast/agent/protect/rule/cmdi/cmdi_dangerous_path.rb +68 -0
  27. data/lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb +2 -58
  28. data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -1
  29. data/lib/contrast/agent/protect/rule/deserialization.rb +3 -14
  30. data/lib/contrast/agent/protect/rule/http_method_tampering/http_method_tampering_input_classification.rb +2 -2
  31. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +0 -11
  32. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb +29 -34
  33. data/lib/contrast/agent/protect/rule/no_sqli.rb +25 -18
  34. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_input_classification.rb +61 -0
  35. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +114 -0
  36. data/lib/contrast/agent/protect/rule/path_traversal.rb +38 -12
  37. data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +33 -15
  38. data/lib/contrast/agent/protect/rule/sqli/sqli_base_rule.rb +0 -14
  39. data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +2 -62
  40. data/lib/contrast/agent/protect/rule/sqli.rb +70 -0
  41. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +39 -63
  42. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +6 -33
  43. data/lib/contrast/agent/protect/rule/xss/reflected_xss_input_classification.rb +58 -0
  44. data/lib/contrast/agent/protect/rule/xss.rb +14 -20
  45. data/lib/contrast/agent/protect/rule/xxe.rb +4 -24
  46. data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +18 -39
  47. data/lib/contrast/agent/reporting/attack_result/response_type.rb +9 -9
  48. data/lib/contrast/agent/reporting/details/ip_denylist_details.rb +10 -2
  49. data/lib/contrast/agent/reporting/details/virtual_patch_details.rb +8 -2
  50. data/lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb +27 -0
  51. data/lib/contrast/agent/reporting/input_analysis/details/protect_rule_details.rb +15 -0
  52. data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +1 -2
  53. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +16 -2
  54. data/lib/contrast/agent/reporting/masker/masker.rb +2 -0
  55. data/lib/contrast/agent/reporting/reporter.rb +1 -14
  56. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +15 -12
  57. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +3 -3
  58. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +1 -2
  59. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +0 -2
  60. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +0 -1
  61. data/lib/contrast/agent/reporting/reporting_events/finding.rb +4 -4
  62. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +0 -5
  63. data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +0 -1
  64. data/lib/contrast/agent/reporting/reporting_events/poll.rb +1 -11
  65. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +0 -1
  66. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +0 -1
  67. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +2 -2
  68. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +1 -1
  69. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +0 -3
  70. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +1 -0
  71. data/lib/contrast/agent/reporting/settings/code_exclusion.rb +6 -1
  72. data/lib/contrast/agent/reporting/settings/exclusion_base.rb +18 -0
  73. data/lib/contrast/agent/reporting/settings/exclusions.rb +2 -1
  74. data/lib/contrast/agent/reporting/settings/input_exclusion.rb +9 -3
  75. data/lib/contrast/agent/reporting/settings/protect.rb +15 -15
  76. data/lib/contrast/agent/request.rb +2 -14
  77. data/lib/contrast/agent/request_context.rb +6 -9
  78. data/lib/contrast/agent/request_context_extend.rb +9 -148
  79. data/lib/contrast/agent/thread_watcher.rb +3 -18
  80. data/lib/contrast/agent/version.rb +1 -1
  81. data/lib/contrast/agent.rb +0 -11
  82. data/lib/contrast/agent_lib/api/command_injection.rb +46 -0
  83. data/lib/contrast/agent_lib/api/init.rb +101 -0
  84. data/lib/contrast/agent_lib/api/input_tracing.rb +267 -0
  85. data/lib/contrast/agent_lib/api/method_tempering.rb +29 -0
  86. data/lib/contrast/agent_lib/api/panic.rb +87 -0
  87. data/lib/contrast/agent_lib/api/path_semantic_file_security_bypass.rb +40 -0
  88. data/lib/contrast/agent_lib/interface.rb +260 -0
  89. data/lib/contrast/agent_lib/interface_base.rb +118 -0
  90. data/lib/contrast/agent_lib/return_types/eval_result.rb +44 -0
  91. data/lib/contrast/agent_lib/test.rb +29 -0
  92. data/lib/contrast/api/communication/connection_status.rb +5 -5
  93. data/lib/contrast/components/agent.rb +0 -14
  94. data/lib/contrast/components/app_context.rb +0 -2
  95. data/lib/contrast/components/app_context_extend.rb +0 -25
  96. data/lib/contrast/components/config.rb +1 -18
  97. data/lib/contrast/components/protect.rb +4 -1
  98. data/lib/contrast/components/ruby_component.rb +1 -1
  99. data/lib/contrast/components/settings.rb +37 -89
  100. data/lib/contrast/config/protect_rule_configuration.rb +7 -7
  101. data/lib/contrast/config/protect_rules_configuration.rb +20 -58
  102. data/lib/contrast/configuration.rb +1 -10
  103. data/lib/contrast/extension/assess/array.rb +9 -0
  104. data/lib/contrast/extension/delegator.rb +2 -0
  105. data/lib/contrast/framework/manager.rb +3 -1
  106. data/lib/contrast/framework/rails/railtie.rb +0 -1
  107. data/lib/contrast/framework/rails/support.rb +0 -1
  108. data/lib/contrast/tasks/config.rb +1 -8
  109. data/lib/contrast/utils/duck_utils.rb +1 -0
  110. data/lib/contrast/utils/input_classification_base.rb +156 -0
  111. data/lib/contrast/utils/os.rb +0 -20
  112. data/lib/contrast/utils/response_utils.rb +0 -16
  113. data/lib/contrast/utils/stack_trace_utils.rb +3 -15
  114. data/lib/contrast/utils/string_utils.rb +10 -7
  115. data/lib/contrast.rb +2 -3
  116. data/resources/protect/policy.json +1 -2
  117. data/ruby-agent.gemspec +2 -5
  118. metadata +42 -112
  119. data/exe/contrast_service +0 -23
  120. data/lib/contrast/agent/protect/rule/cmdi/cmdi_worth_watching.rb +0 -64
  121. data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +0 -118
  122. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_matcher.rb +0 -45
  123. data/lib/contrast/agent/reaction_processor.rb +0 -47
  124. data/lib/contrast/agent/service_heartbeat.rb +0 -35
  125. data/lib/contrast/api/communication/messaging_queue.rb +0 -128
  126. data/lib/contrast/api/communication/response_processor.rb +0 -90
  127. data/lib/contrast/api/communication/service_lifecycle.rb +0 -77
  128. data/lib/contrast/api/communication/socket.rb +0 -44
  129. data/lib/contrast/api/communication/socket_client.rb +0 -130
  130. data/lib/contrast/api/communication/speedracer.rb +0 -138
  131. data/lib/contrast/api/communication/tcp_socket.rb +0 -32
  132. data/lib/contrast/api/communication/unix_socket.rb +0 -28
  133. data/lib/contrast/api/communication.rb +0 -20
  134. data/lib/contrast/api/decorators/address.rb +0 -59
  135. data/lib/contrast/api/decorators/agent_startup.rb +0 -56
  136. data/lib/contrast/api/decorators/application_settings.rb +0 -43
  137. data/lib/contrast/api/decorators/application_startup.rb +0 -56
  138. data/lib/contrast/api/decorators/bot_blocker.rb +0 -37
  139. data/lib/contrast/api/decorators/http_request.rb +0 -137
  140. data/lib/contrast/api/decorators/input_analysis.rb +0 -18
  141. data/lib/contrast/api/decorators/instrumentation_mode.rb +0 -35
  142. data/lib/contrast/api/decorators/ip_denylist.rb +0 -37
  143. data/lib/contrast/api/decorators/message.rb +0 -67
  144. data/lib/contrast/api/decorators/rasp_rule_sample.rb +0 -52
  145. data/lib/contrast/api/decorators/response_type.rb +0 -17
  146. data/lib/contrast/api/decorators/server_features.rb +0 -25
  147. data/lib/contrast/api/decorators/user_input.rb +0 -51
  148. data/lib/contrast/api/decorators/virtual_patch.rb +0 -34
  149. data/lib/contrast/api/decorators.rb +0 -22
  150. data/lib/contrast/api/dtm.pb.rb +0 -363
  151. data/lib/contrast/api/settings.pb.rb +0 -500
  152. data/lib/contrast/api.rb +0 -16
  153. data/lib/contrast/components/contrast_service.rb +0 -88
  154. data/lib/contrast/components/service.rb +0 -55
  155. data/lib/contrast/tasks/service.rb +0 -84
  156. data/lib/contrast/utils/input_classification.rb +0 -73
  157. data/lib/protobuf/code_generator.rb +0 -129
  158. data/lib/protobuf/decoder.rb +0 -28
  159. data/lib/protobuf/deprecation.rb +0 -117
  160. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +0 -79
  161. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +0 -360
  162. data/lib/protobuf/descriptors.rb +0 -3
  163. data/lib/protobuf/encoder.rb +0 -11
  164. data/lib/protobuf/enum.rb +0 -365
  165. data/lib/protobuf/exceptions.rb +0 -9
  166. data/lib/protobuf/field/base_field.rb +0 -380
  167. data/lib/protobuf/field/base_field_object_definitions.rb +0 -504
  168. data/lib/protobuf/field/bool_field.rb +0 -64
  169. data/lib/protobuf/field/bytes_field.rb +0 -67
  170. data/lib/protobuf/field/double_field.rb +0 -25
  171. data/lib/protobuf/field/enum_field.rb +0 -56
  172. data/lib/protobuf/field/field_array.rb +0 -102
  173. data/lib/protobuf/field/field_hash.rb +0 -122
  174. data/lib/protobuf/field/fixed32_field.rb +0 -25
  175. data/lib/protobuf/field/fixed64_field.rb +0 -28
  176. data/lib/protobuf/field/float_field.rb +0 -43
  177. data/lib/protobuf/field/int32_field.rb +0 -21
  178. data/lib/protobuf/field/int64_field.rb +0 -34
  179. data/lib/protobuf/field/integer_field.rb +0 -23
  180. data/lib/protobuf/field/message_field.rb +0 -51
  181. data/lib/protobuf/field/sfixed32_field.rb +0 -27
  182. data/lib/protobuf/field/sfixed64_field.rb +0 -28
  183. data/lib/protobuf/field/signed_integer_field.rb +0 -29
  184. data/lib/protobuf/field/sint32_field.rb +0 -21
  185. data/lib/protobuf/field/sint64_field.rb +0 -21
  186. data/lib/protobuf/field/string_field.rb +0 -51
  187. data/lib/protobuf/field/uint32_field.rb +0 -21
  188. data/lib/protobuf/field/uint64_field.rb +0 -21
  189. data/lib/protobuf/field/varint_field.rb +0 -77
  190. data/lib/protobuf/field.rb +0 -74
  191. data/lib/protobuf/generators/base.rb +0 -85
  192. data/lib/protobuf/generators/enum_generator.rb +0 -39
  193. data/lib/protobuf/generators/extension_generator.rb +0 -27
  194. data/lib/protobuf/generators/field_generator.rb +0 -193
  195. data/lib/protobuf/generators/file_generator.rb +0 -262
  196. data/lib/protobuf/generators/group_generator.rb +0 -122
  197. data/lib/protobuf/generators/message_generator.rb +0 -104
  198. data/lib/protobuf/generators/option_generator.rb +0 -17
  199. data/lib/protobuf/generators/printable.rb +0 -160
  200. data/lib/protobuf/generators/service_generator.rb +0 -50
  201. data/lib/protobuf/lifecycle.rb +0 -33
  202. data/lib/protobuf/logging.rb +0 -39
  203. data/lib/protobuf/message/fields.rb +0 -233
  204. data/lib/protobuf/message/serialization.rb +0 -85
  205. data/lib/protobuf/message.rb +0 -241
  206. data/lib/protobuf/optionable.rb +0 -72
  207. data/lib/protobuf/tasks/compile.rake +0 -80
  208. data/lib/protobuf/tasks.rb +0 -1
  209. data/lib/protobuf/varint.rb +0 -20
  210. data/lib/protobuf/varint_pure.rb +0 -31
  211. data/lib/protobuf/version.rb +0 -3
  212. data/lib/protobuf/wire_type.rb +0 -10
  213. data/lib/protobuf.rb +0 -91
  214. data/proto/dynamic_discovery.proto +0 -46
  215. data/proto/google/protobuf/compiler/plugin.proto +0 -183
  216. data/proto/google/protobuf/descriptor.proto +0 -911
  217. data/proto/rpc.proto +0 -71
  218. data/service_executables/.gitkeep +0 -0
  219. data/service_executables/VERSION +0 -1
  220. data/service_executables/linux/contrast-service +0 -0
  221. data/service_executables/mac/contrast-service +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c688788c7666c5ea72351e52ad02fe838923dc0dde589199917d2bfa96080630
4
- data.tar.gz: f63416e47b9b815f0ec7a79858fb11f866bf5c49c952cf278dfb851679f44957
3
+ metadata.gz: 2c32847e196cdcf1540bd39373f9327a46e50cb1c4be6516f2ad5664696c0221
4
+ data.tar.gz: 03b9bc37cf6b8fe3fd0662f120f6f24cc9faf868cf91c7fb698ccbcb52f15aac
5
5
  SHA512:
6
- metadata.gz: 0b5ee56bb30a55609a6252a105c8ab60e0bf66bdcac23e4efa937cfbc99f7669ab5ed7ffdc41dfd1b9659a09a93d2f7714af0eb398b46069542f0dff753c1ccd
7
- data.tar.gz: 84b72b0f516808677745cc1ea7ecdedf762309ceb79eaac2908f1f16ac6abc811f2997bc50673e78101d7845ddd67a73c996c7ed3ebdbca6d33cf88883926499
6
+ metadata.gz: 204a13ebf2cc20d9302d55a1d2201cc0f8f2ba35b5bf1b3392f75c0636f8ab5224de54106af8349c16da111d86f2381e894d8925eccf2df1e46e4d04b99eb7be
7
+ data.tar.gz: ac50424a98754b82bab6576b7205cdb3f6243f5dc6aa9c55f817f15cfba61e1f0858c27a66efd18457442f0b4f2e8ea42cdfcbecdd67c6941edcd86c77b11164
data/.gitignore CHANGED
@@ -21,7 +21,6 @@
21
21
  bin
22
22
  ruby-spec
23
23
  mspec
24
- service_executables
25
24
 
26
25
  # rspec generated files
27
26
  /spec/dummy_files/*
@@ -57,7 +56,6 @@ contrast-agent-*.gem
57
56
 
58
57
  .ruby-version
59
58
  .ruby-gemset
60
- service_executables/*-*
61
59
 
62
60
  # IDE stuff
63
61
  tags
data/.simplecov CHANGED
@@ -4,6 +4,5 @@
4
4
  SimpleCov.minimum_coverage(line: 94)
5
5
  SimpleCov.start do
6
6
  add_filter '/spec/'
7
- add_filter '/lib/protobuf/'
8
7
  enable_coverage :branch
9
8
  end
data/Rakefile CHANGED
@@ -6,7 +6,6 @@ $stdout.sync = true
6
6
  require 'bundler/gem_tasks'
7
7
  require 'rspec/core/rake_task'
8
8
  require 'rake/extensiontask'
9
- load 'protobuf/tasks/compile.rake'
10
9
  require 'fileutils'
11
10
 
12
11
  CLOBBER << 'shared_libraries/*'
@@ -31,15 +31,46 @@ static VALUE contrast_assess_array_join(const int argc, const VALUE *argv,
31
31
  return result;
32
32
  }
33
33
 
34
+ static VALUE contrast_assess_prepend_array_join(const int argc, const VALUE *argv,
35
+ const VALUE ary) {
36
+ VALUE sep, result;
37
+ /* We need to figure out the separator the join method actually used. */
38
+ /* First, check if one was provided. */
39
+ rb_scan_args(argc, argv, "01", &sep);
40
+ /* Second, check to see if `$;` is set*/
41
+ if (NIL_P(sep)) {
42
+ sep = rb_output_fs;
43
+ }
44
+
45
+ /* call the Array.join but patched one */
46
+ result = rb_ary_join(ary, sep);
47
+ /* call the Contrast::Extensions::Assess::ArrayPropagator#cs__track_join */
48
+ result = rb_funcall(array_propagator, rb_sym_assess_track_array_join, 3,
49
+ ary, sep, result);
50
+
51
+ /*call original occurs in ruby*/
52
+ return Qtrue;
53
+ }
54
+
34
55
  void Init_cs__assess_array(void) {
35
- array_propagator =
36
- rb_define_class_under(core_assess, "ArrayPropagator", rb_cObject);
37
- rb_sym_assess_track_array_join = rb_intern("cs__track_join");
38
- /*
39
- * Here we need to check before using the alias or prepend spec
40
- * This patch is happening here, we register the cs__track_join
41
- * method of the Array propagator, and call it here from Ruby.
42
- */
43
- rb_sym_assess_array_join =
44
- contrast_register_patch("Array", "join", contrast_assess_array_join);
56
+
57
+ VALUE rb_mod_ary = rb_const_get(rb_cObject, rb_intern("Array"));
58
+ VALUE rb_sym_ary_join = ID2SYM(rb_intern("join"));
59
+ // check if prepended
60
+ VALUE is_prepended = contrast_check_prepended(rb_mod_ary, rb_sym_ary_join, Qtrue);
61
+ // register the cs__track_join method of the Array propagator, and call it here from Ruby.
62
+ array_propagator = rb_define_class_under(core_assess, "ArrayPropagator", rb_cObject);
63
+ rb_sym_assess_track_array_join = rb_intern("cs__track_join");
64
+
65
+ // register the cs__join method of the ContrastArray for prepending, and call it here from Ruby.
66
+ VALUE contrast_array = rb_define_module_under(core_assess, "ContrastArray");
67
+ rb_define_module_function(contrast_array, "cs__join", contrast_assess_prepend_array_join, -1);
68
+
69
+ if(is_prepended == Qtrue) {
70
+ // do nothing prepend is done in Ruby
71
+ } else {
72
+ // register alias patch
73
+ rb_sym_assess_array_join =
74
+ contrast_register_patch("Array", "join", contrast_assess_array_join);
75
+ }
45
76
  }
@@ -3,8 +3,11 @@
3
3
  static VALUE array_propagator;
4
4
  static VALUE rb_sym_assess_array_join;
5
5
  static VALUE rb_sym_assess_track_array_join;
6
-
6
+ static VALUE rb_mod_ary, rb_sym_ary_join, is_prepended, contrast_array;
7
7
  static VALUE contrast_assess_array_join(const int argc, const VALUE *argv,
8
8
  const VALUE ary);
9
9
 
10
+ static VALUE contrast_assess_prepend_array_join(const int argc, const VALUE *argv,
11
+ const VALUE ary);
12
+
10
13
  void Init_cs__assess_array(void);
@@ -23,7 +23,7 @@ module Contrast
23
23
  # A trigger method is one which can perform a dangerous action, as described by the
24
24
  # Contrast::Agent::Assess::Policy::TriggerNode class. Each such method will call to this module just after
25
25
  # invocation in order to determine if the call was done safely. In those cases where it was not, a Finding
26
- # report is issued to the Service.
26
+ # report is issued to TeamServer.
27
27
  module TriggerMethod
28
28
  extend Contrast::Components::Logger::InstanceMethods
29
29
  extend Contrast::Utils::Assess::TriggerMethodUtils
@@ -105,7 +105,7 @@ module Contrast
105
105
  nil
106
106
  end
107
107
 
108
- # Given a finding, append it to an activity message and send it to the Service for processing. If an
108
+ # Given a finding, append it to an activity message and send it to the TeamServer for processing. If an
109
109
  # activity message does not exist, b/c we're invoked outside of a request context, build an activity and
110
110
  # immediately report it with the finding.
111
111
  #
@@ -7,7 +7,7 @@ module Contrast
7
7
  module Policy
8
8
  module TriggerValidation
9
9
  # Validator used to assert a REDOS finding is actually vulnerable
10
- # before serializing that finding as a DTM to report to the service.
10
+ # before serializing that finding as a DTM to report to the TeamServer.
11
11
  module REDOSValidator
12
12
  RULE_NAME = 'redos'
13
13
 
@@ -7,7 +7,7 @@ module Contrast
7
7
  module Policy
8
8
  module TriggerValidation
9
9
  # Validator used to assert a SSRF finding is actually vulnerable
10
- # before serializing that finding as a DTM to report to the service.
10
+ # before serializing that finding as a DTM to report to the TeamServer.
11
11
  module SSRFValidator
12
12
  RULE_NAME = 'ssrf'
13
13
  URL_PATTERN = %r{(?<protocol>http|https|ftp|sftp|telnet|gopher|rtsp|rtsps|ssh|svn)://(?<host>[^/?]+)(?<path>/?[^?]*)(?<query_string>\?.*)?}i.cs__freeze # rubocop:disable Layout/LineLength
@@ -8,7 +8,7 @@ module Contrast
8
8
  module TriggerValidation
9
9
  # Validator used to assert a Reflected XSS finding is actually
10
10
  # vulnerable before serializing that finding as a DTM to report to
11
- # the service.
11
+ # the TeamServer.
12
12
  module XSSValidator
13
13
  RULE_NAME = 'reflected-xss'
14
14
  SAFE_CONTENT_TYPES = %w[/csv /javascript /json /pdf /x-javascript /x-json].cs__freeze
@@ -1,13 +1,17 @@
1
1
  # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'contrast/agent/reporting/settings/url_exclusion'
5
+
4
6
  module Contrast
5
7
  module Agent
6
8
  # Given an array of exclusion matcher instances provides methods to
7
9
  # determine if the exclusions apply to particular urls.
8
10
  class Excluder # rubocop:disable Metrics/ClassLength
11
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
9
12
  attr_reader :exclusions
10
13
 
14
+ # @param exclusions [Array<Contrast::Agent::ExclusionMatcher>]
11
15
  def initialize exclusions = []
12
16
  @exclusions = exclusions
13
17
  end
@@ -16,12 +20,12 @@ module Contrast
16
20
  # then we can avoid any tracking for the request.
17
21
  #
18
22
  # @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
19
- # return [Boolean]
23
+ # @return [Boolean]
20
24
  def assess_excluded_by_url? request
21
25
  request_path = request.path
22
26
 
23
- assess_url_exclusions_for_all_rules.any? do |exclusion|
24
- path_match?(exclusion, request_path)
27
+ assess_url_exclusions_for_all_rules.any? do |exclusion_matcher|
28
+ path_match?(exclusion_matcher, request_path)
25
29
  end
26
30
  end
27
31
 
@@ -34,9 +38,9 @@ module Contrast
34
38
  def assess_excluded_by_url_and_rule? request, rule_id
35
39
  request_path = request.path
36
40
 
37
- assess_url_exclusions.any? do |exclusion|
38
- path_match?(exclusion, request_path) &&
39
- (exclusion.assessment_rules.empty? || exclusion.assessment_rules.include?(rule_id))
41
+ assess_url_exclusions.any? do |exclusion_matcher|
42
+ path_match?(exclusion_matcher, request_path) &&
43
+ (exclusion_matcher.assess_rules.empty? || exclusion_matcher.assess_rules.include?(rule_id))
40
44
  end
41
45
  end
42
46
 
@@ -44,13 +48,14 @@ module Contrast
44
48
  # rules, then we can avoid tracking this entry.
45
49
  #
46
50
  # @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
47
- # @param rule_id [String]
51
+ # @param source_type [String]
52
+ # @param source_name [String]
48
53
  # return [Boolean]
49
54
  def assess_excluded_by_input? request, source_type, source_name
50
55
  request_path = request.path
51
56
 
52
- assess_input_exclusions_for_all_rules.any? do |exclusion|
53
- input_match?(exclusion, source_type, source_name) && path_match?(exclusion, request_path)
57
+ assess_input_exclusions_for_all_rules.any? do |exclusion_matcher|
58
+ input_match?(exclusion_matcher, source_type, source_name) && path_match?(exclusion_matcher, request_path)
54
59
  end
55
60
  end
56
61
 
@@ -66,11 +71,11 @@ module Contrast
66
71
 
67
72
  # We need to check for url exclusions here for the input rules as the url exclusions
68
73
  # that have already been checked didn't include the INPUT exclusions. So we look for
69
- # any INPUT exclusions that apply to the current url and the suppleid rule.
74
+ # any INPUT exclusions that apply to the current url and the supplied rule.
70
75
  path = request.path
71
- rule_input_exclusions = assess_input_exclusions.select do |exclusion|
72
- (exclusion.protection_rules.empty? || exclusion.protection_rules.include?(rule)) && path_match?(exclusion,
73
- path)
76
+ rule_input_exclusions = assess_input_exclusions.select do |exclusion_matcher|
77
+ (exclusion_matcher.protection_rules.empty? || exclusion_matcher.protection_rules.include?(rule)) &&
78
+ path_match?(exclusion_matcher, path)
74
79
  end
75
80
  return false if rule_input_exclusions.empty?
76
81
 
@@ -94,72 +99,85 @@ module Contrast
94
99
  def protect_excluded_by_url? request
95
100
  request_path = request.path
96
101
 
97
- protect_url_exclusions_for_all_rules.any? do |exclusion|
98
- path_match?(exclusion, request_path)
102
+ protect_url_exclusions_for_all_rules.any? do |exclusion_matcher|
103
+ path_match?(exclusion_matcher, request_path)
99
104
  end
100
105
  end
101
106
 
102
107
  private
103
108
 
109
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
104
110
  def assess_url_exclusions_for_all_rules
105
- @_assess_url_exclusions_for_all_rules ||= assess_url_exclusions.select do |exclusion|
106
- exclusion.assessment_rules.empty?
111
+ @_assess_url_exclusions_for_all_rules ||= assess_url_exclusions.select do |exclusion_matcher|
112
+ exclusion_matcher.assess_rules.empty?
107
113
  end
108
114
  end
109
115
 
116
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
110
117
  def assess_url_exclusions
111
- @_assess_url_exclusions ||= assess_exclusions.select do |exclusion|
112
- exclusion.type == Contrast::Api::Settings::Exclusion::ExclusionType::URL
118
+ @_assess_url_exclusions ||= assess_exclusions.select do |exclusion_matcher|
119
+ exclusion_matcher.type == :URL
113
120
  end
114
121
  end
115
122
 
123
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
116
124
  def assess_input_exclusions_for_all_rules
117
- @_assess_input_exclusions_for_all_rules ||= assess_input_exclusions.select do |exclusion|
118
- exclusion.assessment_rules.empty?
125
+ @_assess_input_exclusions_for_all_rules ||= assess_input_exclusions.select do |exclusion_matcher|
126
+ exclusion_matcher.assess_rules.empty?
119
127
  end
120
128
  end
121
129
 
130
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
122
131
  def assess_input_exclusions
123
- @_assess_input_exclusions ||= assess_exclusions.select do |exclusion|
124
- exclusion.type == Contrast::Api::Settings::Exclusion::ExclusionType::INPUT
132
+ @_assess_input_exclusions ||= assess_exclusions.select do |exclusion_matcher|
133
+ exclusion_matcher.type == :INPUT
125
134
  end
126
135
  end
127
136
 
137
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
128
138
  def assess_exclusions
129
139
  @_assess_exclusions ||= @exclusions.select(&:assess)
130
140
  end
131
141
 
142
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
132
143
  def protect_url_exclusions_for_all_rules
133
- @_protect_url_exclusions_for_all_rules ||= protect_url_exclusions.select do |exclusion|
134
- exclusion.protection_rules.empty?
144
+ @_protect_url_exclusions_for_all_rules ||= protect_url_exclusions.select do |exclusion_matcher|
145
+ exclusion_matcher.protect_rules.empty?
135
146
  end
136
147
  end
137
148
 
149
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
138
150
  def protect_url_exclusions
139
- @_protect_url_exclusions ||= protect_exclusions.select do |exclusion|
140
- exclusion.type == Contrast::Api::Settings::Exclusion::ExclusionType::URL
151
+ @_protect_url_exclusions ||= protect_exclusions.select do |exclusion_matcher|
152
+ exclusion_matcher.type == :URL
141
153
  end
142
154
  end
143
155
 
156
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
144
157
  def protect_exclusions
145
158
  @_protect_exclusions ||= @exclusions.select(&:protect)
146
159
  end
147
160
 
148
- def path_match? exclusion, path
149
- exclusion.wildcard_url || exclusion.urls.any? { |url| url.match?(path) }
161
+ # @return [Boolean]
162
+ def path_match? exclusion_matcher, path
163
+ exclusion_matcher.wildcard_url || exclusion_matcher.urls.any? { |url| url.match?(path) }
150
164
  end
151
165
 
166
+ # @param exclusion [Contrast::Agent::ExclusionMatcher]
167
+ # @param source_type [String]
168
+ # @param source_name [String]
169
+ # @return [Boolean]
152
170
  def input_match? exclusion, source_type, source_name
153
171
  case exclusion.input_type
154
- when Contrast::Api::Settings::Exclusion::InputType::PARAMETER
172
+ when 'PARAMETER'
155
173
  input_match_parameter?(exclusion, source_type, source_name)
156
- when Contrast::Api::Settings::Exclusion::InputType::COOKIE
174
+ when 'COOKIE'
157
175
  input_match_cookie?(exclusion, source_type, source_name)
158
- when Contrast::Api::Settings::Exclusion::InputType::HEADER
176
+ when 'HEADER'
159
177
  input_match_header?(exclusion, source_type, source_name)
160
- when Contrast::Api::Settings::Exclusion::InputType::BODY
178
+ when 'BODY'
161
179
  Contrast::Agent::Assess::Policy::SourceMethod::BODY_TYPE == source_type
162
- when Contrast::Api::Settings::Exclusion::InputType::QUERYSTRING
180
+ when 'QUERYSTRING'
163
181
  Contrast::Agent::Assess::Policy::SourceMethod::QUERYSTRING_TYPE == source_type
164
182
  else
165
183
  false
@@ -2,6 +2,10 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/components/logger'
5
+ require 'contrast/agent/reporting/settings/exclusion_base'
6
+ require 'contrast/agent/reporting/settings/code_exclusion'
7
+ require 'contrast/agent/reporting/settings/input_exclusion'
8
+ require 'contrast/agent/reporting/settings/url_exclusion'
5
9
 
6
10
  module Contrast
7
11
  module Agent
@@ -13,22 +17,30 @@ module Contrast
13
17
 
14
18
  extend Forwardable
15
19
 
16
- attr_reader :protect, :assess, :urls, :wildcard_url, :wildcard_input
20
+ attr_reader :protect, :assess, :type, :urls, :wildcard_url, :wildcard_input
17
21
 
18
- def_delegators :@exclusion, :type, :assessment_rules, :protection_rules, :input_type, :input_name
22
+ def_delegators :@exclusion, :protect_rules, :assess_rules, :input_type, :input_name
19
23
 
20
24
  # Create a matcher around an exclusion sent from TeamServer.
21
25
  #
22
- # @param excl [Contrast::Api::Settings::Exclusion]
26
+ # @param excl [Contrast::Agent::Reporting::Settings::ExclusionBase]
23
27
  # @return [Contrast::Agent::ExclusionMatcher]
24
28
  def initialize excl
25
29
  @exclusion = excl
26
30
  @protect = @exclusion.protect
27
31
  @assess = @exclusion.assess
28
32
 
29
- handle_wildcard_input
30
- handle_wildcard_url
31
- handle_wildcard_code
33
+ case excl
34
+ when Contrast::Agent::Reporting::Settings::CodeExclusion
35
+ handle_wildcard_code
36
+ @type = :CODE
37
+ when Contrast::Agent::Reporting::Settings::InputExclusion
38
+ handle_wildcard_input
39
+ @type = :INPUT
40
+ when Contrast::Agent::Reporting::Settings::UrlExclusion
41
+ handle_wildcard_url
42
+ @type = :URL
43
+ end
32
44
  end
33
45
 
34
46
  # According to the docs for exclusions, user input applies to all inputs if
@@ -97,7 +109,7 @@ module Contrast
97
109
  end
98
110
 
99
111
  def code?
100
- @exclusion.type == Contrast::Api::Settings::Exclusion::ExclusionType::CODE
112
+ @type == :CODE
101
113
  end
102
114
 
103
115
  def match_all?
@@ -105,12 +117,12 @@ module Contrast
105
117
  end
106
118
 
107
119
  # Determine if the given rule is excluded by this exclusion.
108
- # In this case, the `protection_rules` being empty means apply to all rules,
120
+ # In this case, the `protect_rules` being empty means apply to all rules,
109
121
  # not no rules
110
122
  #
111
123
  # @param rule - the id of the rule which we're checking for exclusion
112
124
  def protection_rule? rule
113
- protect? && (@exclusion.protection_rules.empty? || @exclusion.protection_rules.include?(rule))
125
+ protect? && (@exclusion.protect_rules.empty? || @exclusion.protect_rules.include?(rule))
114
126
  end
115
127
 
116
128
  # Determine if the given rule is excluded by this exclusion.
@@ -73,12 +73,12 @@ module Contrast
73
73
  private
74
74
 
75
75
  # Startup the Agent as part of the initialization process:
76
- # - start the service sending thread, responsible for sending and processing messages
77
- # - start the heartbeat thread, which triggers service startup
76
+ # - start the TeamServer sending thread, responsible for sending and processing messages
77
+ # - start the heartbeat thread, which handles periodic messages to TeamServer
78
78
  # - start instrumenting libraries and do a 'catchup' patch for everything we didn't see get loaded
79
79
  # - enable TracePoint, which handles all class loads and required instrumentation going forward
80
80
  def agent_startup_routine
81
- logger.debug_with_time('middleware: starting service') do
81
+ logger.debug_with_time('middleware: starting reporting threads') do
82
82
  Contrast::Agent.thread_watcher.ensure_running?
83
83
  end
84
84
 
@@ -147,7 +147,7 @@ module Contrast
147
147
  # which is being triggered when there is a failure within the pre-call with the agent
148
148
  def pre_call_with_agent context, request_handler
149
149
  with_contrast_scope do
150
- context.service_extract_request
150
+ context.protect_input_analysis
151
151
  request_handler.ruleset.prefilter
152
152
  end
153
153
  rescue StandardError => e
@@ -56,6 +56,7 @@ module Contrast
56
56
  unless Contrast::Agent::Assess.cs__object_method_prepended?(Marshal, :load, false)
57
57
  apply_marshal_load_alias_patch
58
58
  end
59
+ apply_array_join_prepend_patch if Contrast::Agent::Assess.cs__object_method_prepended?(Array, :join, true)
59
60
  true
60
61
  end
61
62
  end
@@ -121,6 +122,11 @@ module Contrast
121
122
  Marshal.alias_method(:cs__marshal_load, :load)
122
123
  Marshal.alias_method(:load, :cs__marshal_load)
123
124
  end
125
+
126
+ # Prepend Contrast::Extension::Assess::ContrastArray to pick up the ContrastArray#join method
127
+ def apply_array_join_prepend_patch
128
+ Array.prepend(Contrast::Extension::Assess::ContrastArray)
129
+ end
124
130
  end
125
131
  end
126
132
  end