contrast-agent 6.6.2 → 6.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/contrast/agent/assess/policy/trigger_method.rb +21 -6
  3. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +2 -0
  4. data/lib/contrast/agent/at_exit_hook.rb +1 -7
  5. data/lib/contrast/agent/inventory/database_config.rb +16 -12
  6. data/lib/contrast/agent/inventory/policy/datastores.rb +1 -2
  7. data/lib/contrast/agent/middleware.rb +0 -1
  8. data/lib/contrast/agent/protect/rule/base.rb +16 -20
  9. data/lib/contrast/agent/protect/rule/cmd_injection.rb +5 -4
  10. data/lib/contrast/agent/protect/rule/deserialization.rb +5 -4
  11. data/lib/contrast/agent/protect/rule/path_traversal.rb +9 -7
  12. data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +16 -14
  13. data/lib/contrast/agent/protect/rule/sqli.rb +1 -1
  14. data/lib/contrast/agent/protect/rule/xxe.rb +9 -6
  15. data/lib/contrast/agent/reporting/attack_result/attack_result.rb +8 -0
  16. data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +85 -36
  17. data/lib/contrast/agent/reporting/attack_result/user_input.rb +11 -0
  18. data/lib/contrast/agent/reporting/details/bot_blocker_details.rb +29 -0
  19. data/lib/contrast/agent/reporting/details/cmd_injection_details.rb +30 -0
  20. data/lib/contrast/agent/reporting/details/details.rb +18 -0
  21. data/lib/contrast/agent/reporting/details/http_method_tempering_details.rb +27 -0
  22. data/lib/contrast/agent/reporting/details/ip_denylist_details.rb +27 -0
  23. data/lib/contrast/agent/reporting/details/no_sqli_details.rb +36 -0
  24. data/lib/contrast/agent/reporting/details/path_traversal_details.rb +24 -0
  25. data/lib/contrast/agent/reporting/details/path_traversal_semantic_analysis_details.rb +32 -0
  26. data/lib/contrast/agent/reporting/details/protect_rule_details.rb +17 -0
  27. data/lib/contrast/agent/reporting/details/sqli_details.rb +36 -0
  28. data/lib/contrast/agent/reporting/details/untrusted_deserialization_details.rb +27 -0
  29. data/lib/contrast/agent/reporting/details/virtual_patch_details.rb +24 -0
  30. data/lib/contrast/agent/reporting/details/xss_details.rb +33 -0
  31. data/lib/contrast/agent/reporting/details/xss_match.rb +30 -0
  32. data/lib/contrast/agent/reporting/details/xxe_details.rb +36 -0
  33. data/lib/contrast/agent/reporting/details/xxe_match.rb +25 -0
  34. data/lib/contrast/agent/reporting/details/xxe_wrapper.rb +25 -0
  35. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +1 -1
  36. data/lib/contrast/agent/reporting/masker/masker.rb +78 -65
  37. data/lib/contrast/agent/reporting/masker/masker_utils.rb +1 -30
  38. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +84 -15
  39. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +13 -25
  40. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +17 -22
  41. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +46 -125
  42. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +5 -16
  43. data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +10 -18
  44. data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +6 -14
  45. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +29 -20
  46. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +45 -10
  47. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +2 -2
  48. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -7
  49. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +1 -1
  50. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +2 -2
  51. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +2 -1
  52. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +1 -1
  53. data/lib/contrast/agent/request.rb +2 -0
  54. data/lib/contrast/agent/request_context.rb +13 -4
  55. data/lib/contrast/agent/request_context_extend.rb +59 -40
  56. data/lib/contrast/agent/request_handler.rb +7 -9
  57. data/lib/contrast/agent/service_heartbeat.rb +1 -1
  58. data/lib/contrast/agent/version.rb +1 -1
  59. data/lib/contrast/api/decorators/message.rb +1 -1
  60. data/lib/contrast/components/app_context.rb +62 -8
  61. data/lib/contrast/components/app_context_extend.rb +8 -8
  62. data/lib/contrast/config/assess_configuration.rb +1 -1
  63. data/lib/contrast/config/root_configuration.rb +6 -4
  64. data/lib/contrast/config.rb +0 -1
  65. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +1 -6
  66. data/lib/contrast/utils/assess/event_limit_utils.rb +26 -7
  67. data/lib/contrast/utils/log_utils.rb +16 -10
  68. data/lib/contrast/utils/net_http_base.rb +5 -6
  69. data/lib/contrast/utils/string_utils.rb +2 -6
  70. data/lib/contrast.rb +1 -1
  71. metadata +30 -14
  72. data/lib/contrast/config/application_configuration.rb +0 -57
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f00aee3e36cdb303ca9b209824fbb92386e0ca0043c0f24377f79168dca8d252
4
- data.tar.gz: 7fc3d7571246ff92a10da151ce4b723768e3f7214b5a1e57d5bb1d6a66e86e2b
3
+ metadata.gz: 9a7491020083af4de63e878defb8a57583d22258ec534fba4b6d7ad923861c55
4
+ data.tar.gz: 9c784b84420c8caa8f3123e8dc053b21a7a8964058f8e5b073cbf794275e9793
5
5
  SHA512:
6
- metadata.gz: 9fc9e69602a2706cb41bf8d13e07693afb61ad85ad03ff43182f3c79c5f9dff1c0b8ed3e0cb690d15cf8e43830920516604e9b497945963897f0ee1b82e11f9b
7
- data.tar.gz: dfd4e5146f9ac498b83d76b13a9d6ed17a5de0e659ed301acbf6a873e18d5ff75ea8aa8fa7c3789433e100903a9f6bfb4b87c9d283107c5bd04015f862e88644
6
+ metadata.gz: 8896ddef1bb19c81b279f54c3ec1f5458474d7f6a9b5b7910670c2e87e00a1bdfab2a6ab422bb585eb125ba707839b9967490b2001951b360b211d3e41f2b15e
7
+ data.tar.gz: 2a6e933028aaf9b899cc107e565a112344408563035c20fec1cd3625d02bbd1de5ca6d02566a9379a07b532bda16d64b0868f2a30b0183aaafcfc0d2d3dc1a6d
@@ -9,6 +9,7 @@ require 'contrast/utils/sha256_builder'
9
9
  require 'contrast/utils/assess/trigger_method_utils'
10
10
  require 'contrast/agent/assess/events/event_data'
11
11
  require 'contrast/agent/reporting/reporting_events/preflight'
12
+ require 'contrast/agent/reporting/reporting_events/application_activity'
12
13
  require 'contrast/agent/reporting/reporting_events/preflight_message'
13
14
  require 'contrast/agent/reporting/reporting_events/route_discovery'
14
15
  require 'contrast/agent/reporting/reporting_utilities/reporting_storage'
@@ -118,7 +119,8 @@ module Contrast
118
119
  append_to_finding(finding, event_data, request)
119
120
  logger.trace('Finding created', node_id: trigger_node.id, source_id: source.__id__,
120
121
  rule: trigger_node.rule_id)
121
- report_finding(finding, request)
122
+ # check here if we need to add that finding
123
+ report_finding(finding, request) unless not_reported?(finding)
122
124
  end
123
125
  end
124
126
 
@@ -133,22 +135,21 @@ module Contrast
133
135
  def report_finding finding, request = nil
134
136
  context = Contrast::Agent::REQUEST_TRACKER.current
135
137
  if context
136
- context.activity.findings << finding
138
+ # REMOVE_DTM_ACTIVITY
139
+ context.dtm_activity.findings << finding
137
140
  return
138
141
  end
139
142
 
140
143
  return unless ::Contrast::ASSESS.non_request_tracking? || NON_REQUEST_RULES.include?(finding.rule_id)
141
144
 
145
+ # REMOVE_DTM_ACTIVITY Findings still using dtm - REMOVE
142
146
  activity = Contrast::Api::Dtm::Activity.new
143
- activity.findings << finding
144
147
  if request
145
- activity.http_request = request.dtm
148
+ activity.request = request.dtm
146
149
  else
147
150
  logger.debug('Attempted to report finding without request', finding: finding)
148
151
  end
149
152
 
150
- # If we're out of request context, then we need to report this finding ourselves,
151
- # so we'll send it in the one-off activity we created.
152
153
  Contrast::Agent.messaging_queue&.send_event_eventually(activity)
153
154
  end
154
155
 
@@ -269,6 +270,20 @@ module Contrast
269
270
 
270
271
  MINIMUM_FINDING_VERSION
271
272
  end
273
+
274
+ # Check if the following finding was already added to context.activity
275
+ # We could use this after we get rid of the MessagingQueue.
276
+ #
277
+ # @param finding [Contrast::Api::Dtm::Finding] Finding we're about to report
278
+ # @return Boolean
279
+ def not_reported? finding
280
+ return false unless (current = Contrast::Agent::REQUEST_TRACKER.current)
281
+
282
+ currently_added_findings = current.dtm_activity.findings
283
+ return false if currently_added_findings.empty?
284
+
285
+ currently_added_findings.any? { |f| f.rule_id == finding.rule_id && f.hash_code == finding.hash_code }
286
+ end
272
287
  end
273
288
  end
274
289
  end
@@ -113,6 +113,8 @@ module Contrast
113
113
  class_name = clazz.cs__name
114
114
 
115
115
  finding = assign_finding(class_name, constant_string)
116
+ # TODO: RUBY-1705
117
+ # The only place we still use dtm activity
116
118
  activity = Contrast::Api::Dtm::Activity.new
117
119
  activity.findings << finding
118
120
  Contrast::Agent.messaging_queue.send_event_eventually(activity, force: true)
@@ -37,13 +37,7 @@ module Contrast
37
37
  ].compact.each do |event|
38
38
  Contrast::Agent.reporter&.send_event_immediately(event)
39
39
  end
40
-
41
- if Contrast::Agent::Reporter.enabled?
42
- event = Contrast::Agent::Reporting::DtmMessage.dtm_to_event(context.activity)
43
- Contrast::Agent.reporter&.send_event_immediately(event)
44
- else
45
- Contrast::Agent.messaging_queue&.send_event_immediately(context.activity)
46
- end
40
+ Contrast::Agent.reporter&.send_event_immediately(context.activity)
47
41
  end
48
42
  end
49
43
  end
@@ -30,20 +30,19 @@ module Contrast
30
30
  # Both report the same
31
31
  # Contrast::Api::Dtm::ArchitectureComponent, but have different names for their fields.
32
32
  #
33
- # @param activity_or_update [Contrast::Api::Dtm::Activity, Contrast::Agent::Reporting::ApplicationUpdate]
33
+ # @param activity_or_update [Contrast::Agent::Reporting::ApplicationUpdate]
34
34
  # @param hash_or_str [Hash, String] the database connection information
35
35
  def append_db_config activity_or_update, hash_or_str = active_record_config
36
36
  arr = build_from_db_config(hash_or_str)
37
37
  return unless arr&.any?
38
38
 
39
- arr.each do |a|
40
- next unless a
39
+ arr.each do |component|
40
+ next unless component
41
41
 
42
- if activity_or_update.is_a?(Contrast::Api::Dtm::Activity)
43
- activity_or_update.architectures << a
42
+ if activity_or_update.cs__is_a?(Contrast::Agent::Reporting::ApplicationUpdate)
43
+ activity_or_update.components << component
44
44
  else
45
- converted_comp = Contrast::Agent::Reporting::ArchitectureComponent.convert(a)
46
- activity_or_update.components << converted_comp
45
+ activity_or_update.attach_inventory(component)
47
46
  end
48
47
  end
49
48
  rescue StandardError => e
@@ -78,10 +77,15 @@ module Contrast
78
77
  # reporting.
79
78
  #
80
79
  # @param hash_or_str [Hash, String]
81
- # @return [Array<Contrast::Api::Dtm::ArchitectureComponent>, nil]
80
+ # @return [Array<Contrast::Agent::Reporting::ArchitectureComponent>, nil]
82
81
  def build_from_db_config hash_or_str
83
82
  return unless hash_or_str
84
83
 
84
+ # we need to handle types of HashConfig, which != Hash
85
+ # for example ActiveRecord::DatabaseConfigurations::HashConfig is type of active_record config
86
+ # but the method is not handling it properly
87
+ # so we need to handle it here and extract the hash
88
+ hash_or_str = hash_or_str.configuration_hash if hash_or_str.cs__respond_to?(:configuration_hash)
85
89
  if hash_or_str.is_a?(Hash)
86
90
  build_from_db_hash(hash_or_str)
87
91
  else
@@ -93,9 +97,9 @@ module Contrast
93
97
  # understandable by TeamServer.
94
98
  #
95
99
  # @param hash [Hash] the information used to open a database connection
96
- # @return [Array<Contrast::Api::Dtm::ArchitectureComponent>]
100
+ # @return [Array<Contrast::Agent::Reporting::ArchitectureComponent>]
97
101
  def build_from_db_hash hash
98
- ac = Contrast::Api::Dtm::ArchitectureComponent.build_database
102
+ ac = Contrast::Agent::Reporting::ArchitectureComponent.build_database
99
103
  ac.vendor = hash[:adapter] || hash[ADAPTER] || Contrast::Utils::ObjectShare::EMPTY_STRING
100
104
  ac.remote_host = host_from_hash(hash)
101
105
  ac.remote_port = port_from_hash(hash)
@@ -126,7 +130,7 @@ module Contrast
126
130
  # mysql+mysqlconnector://scott:tiger@localhost/foo # pragma: allowlist secret
127
131
  #
128
132
  # @param str [String] the DB connection string
129
- # @return [Array<Contrast::Api::Dtm::ArchitectureComponent>, nil]
133
+ # @return [Array<Contrast::Agent::Reporting::ArchitectureComponent>, nil]
130
134
  def build_from_db_string str
131
135
  adapter, hosts, database = split_connection_str(str)
132
136
  return unless adapter && hosts && database
@@ -135,7 +139,7 @@ module Contrast
135
139
  hosts.split(Contrast::Utils::ObjectShare::COMMA).map do |s|
136
140
  host, port = s.split(Contrast::Utils::ObjectShare::COLON)
137
141
 
138
- ac = Contrast::Api::Dtm::ArchitectureComponent.build_database
142
+ ac = Contrast::Agent::Reporting::ArchitectureComponent.build_database
139
143
  ac.vendor = Contrast::Utils::StringUtils.force_utf8(adapter)
140
144
  ac.remote_host = Contrast::Utils::StringUtils.force_utf8(host)
141
145
  ac.remote_port = port.to_i
@@ -13,9 +13,8 @@ module Contrast
13
13
  # in which database operations occur. It is responsible for deciding if
14
14
  # the given invocation is worth reporting or not.
15
15
  module DataStores
16
+ extend Contrast::Components::Logger::InstanceMethods
16
17
  class << self
17
- extend Contrast::Components::Logger::InstanceMethods
18
-
19
18
  # The key used in policy.json to indicate the database type to
20
19
  # report.
21
20
  DATA_STORE_MARKER = 'data_store'
@@ -180,7 +180,6 @@ module Contrast
180
180
  else
181
181
  request_handler.ruleset.postfilter
182
182
  request_handler.report_activity
183
- request_handler.send_activity_messages # TODO: RUBY-1438 -- remove
184
183
  end
185
184
  end
186
185
  # unsuccessful attack
@@ -169,9 +169,9 @@ module Contrast
169
169
  #
170
170
  # @param context [Contrast::Agent::RequestContext] the context of the
171
171
  # request in which this input is evaluated.
172
- # @param result [Contrast::Api::Dtm::AttackResult]
172
+ # @param result [Contrast::Agent::Reporting::AttackResult]
173
173
  def append_to_activity context, result
174
- context.activity.results << result if result
174
+ context.activity.attach_defend(result) if result
175
175
  end
176
176
 
177
177
  # With this we log to CEF
@@ -179,15 +179,11 @@ module Contrast
179
179
  # @param result [Contrast::Api::Dtm::AttackResult]
180
180
  # @param attack [Symbol] the type of message we want to send
181
181
  # @param value [String] the input value we want to log
182
- def cef_logging result, attack = :ineffective_attack, value = nil
183
- sample_to_json = Contrast::Api::Dtm::RaspRuleSample.to_controlled_hash(result.samples[0])
184
- outcome = if result.response.cs__is_a?(Hash)
185
- Contrast::Agent::Reporting::ResponseType.cs__const_get(result.response[:name])
186
- else
187
- Contrast::Api::Dtm::AttackResult::ResponseType.get_name_by_tag(result.response)
188
- end
189
- input_type = extract_input_type(sample_to_json[:user_input].input_type)
190
- input_value = value || sample_to_json[:user_input].value
182
+ def cef_logging result, attack = :ineffective_attack, value: nil
183
+ sample = result.samples[0]
184
+ outcome = result.response.to_s
185
+ input_type = sample.user_input.input_type.to_s
186
+ input_value = sample.user_input.value || value
191
187
  cef_logger.send(attack, result.rule_id, outcome, input_type, input_value)
192
188
  end
193
189
 
@@ -238,9 +234,9 @@ module Contrast
238
234
  def update_successful_attack_response context, ia_result, result, attack_string = nil
239
235
  case mode
240
236
  when Contrast::Api::Settings::ProtectionRule::Mode::MONITOR
241
- result.response = Contrast::Api::Dtm::AttackResult::ResponseType::MONITORED
237
+ result.response = Contrast::Agent::Reporting::ResponseType::MONITORED
242
238
  when Contrast::Api::Settings::ProtectionRule::Mode::BLOCK
243
- result.response = Contrast::Api::Dtm::AttackResult::ResponseType::BLOCKED
239
+ result.response = Contrast::Agent::Reporting::ResponseType::BLOCKED
244
240
  end
245
241
 
246
242
  ia_result.attack_count = ia_result.attack_count + 1 if ia_result
@@ -259,9 +255,9 @@ module Contrast
259
255
  def update_perimeter_attack_response context, ia_result, result
260
256
  if mode == Contrast::Api::Settings::ProtectionRule::Mode::BLOCK_AT_PERIMETER
261
257
  result.response = if blocked_rule?(ia_result)
262
- Contrast::Api::Dtm::AttackResult::ResponseType::BLOCKED
258
+ Contrast::Agent::Reporting::ResponseType::BLOCKED
263
259
  else
264
- Contrast::Api::Dtm::AttackResult::ResponseType::BLOCKED_AT_PERIMETER
260
+ Contrast::Agent::Reporting::ResponseType::BLOCKED_AT_PERIMETER
265
261
  end
266
262
  log_rule_matched(context, ia_result, result.response)
267
263
  elsif ia_result.nil? || ia_result.attack_count.zero?
@@ -276,9 +272,9 @@ module Contrast
276
272
  #
277
273
  # @param _context [Contrast::Agent::RequestContext] the context of
278
274
  # the current request
279
- # @return [Contrast::Api::Dtm::AttackResult]
275
+ # @return [Contrast::Agent::Reporting::AttackResult]
280
276
  def build_attack_result _context
281
- result = Contrast::Api::Dtm::AttackResult.new
277
+ result = Contrast::Agent::Reporting::AttackResult.new
282
278
  result.rule_id = rule_name
283
279
  result
284
280
  end
@@ -311,7 +307,7 @@ module Contrast
311
307
  end
312
308
 
313
309
  def build_base_sample context, ia_result
314
- Contrast::Api::Dtm::RaspRuleSample.build(context, ia_result)
310
+ Contrast::Agent::Reporting::RaspRuleSample.build(context, ia_result)
315
311
  end
316
312
 
317
313
  def log_rule_matched _context, ia_result, response, _matched_string = nil
@@ -366,9 +362,9 @@ module Contrast
366
362
  # determined to be an attack
367
363
  def assign_reporter_response_type ia_result
368
364
  if suspicious_rule?(ia_result) && Contrast::CONTRAST_SERVICE.use_agent_communication?
369
- Contrast::Api::Dtm::AttackResult::ResponseType::SUSPICIOUS
365
+ Contrast::Agent::Reporting::ResponseType::SUSPICIOUS
370
366
  else
371
- Contrast::Api::Dtm::AttackResult::ResponseType::PROBED
367
+ Contrast::Agent::Reporting::ResponseType::PROBED
372
368
  end
373
369
  end
374
370
  end
@@ -6,6 +6,7 @@ require 'contrast/utils/stack_trace_utils'
6
6
  require 'contrast/utils/object_share'
7
7
  require 'contrast/components/logger'
8
8
  require 'contrast/agent/reporting/input_analysis/input_type'
9
+ require 'contrast/agent/reporting/details/cmd_injection_details'
9
10
 
10
11
  module Contrast
11
12
  module Agent
@@ -97,17 +98,17 @@ module Contrast
97
98
  # evaluation
98
99
  def build_sample context, input_analysis_result, candidate_string, **_kwargs
99
100
  sample = build_base_sample(context, input_analysis_result)
100
- sample.cmdi = Contrast::Api::Dtm::CmdInjectionDetails.new
101
+ sample.details = Contrast::Agent::Reporting::Details::CmdInjectionDetails.new
101
102
 
102
103
  command = candidate_string || input_analysis_result.value
103
104
  command = Contrast::Utils::StringUtils.protobuf_safe_string(command)
104
- sample.cmdi.command = command
105
- sample.cmdi.end_idx = command.length
105
+ sample.details.cmd = command
106
+ sample.details.end_idx = command.length
106
107
 
107
108
  # This is a special case where the user input is UNKNOWN_USER_INPUT but
108
109
  # we want to send the attack value
109
110
  if input_analysis_result.nil?
110
- ui = Contrast::Api::Dtm::UserInput.new
111
+ ui = Contrast::Agent::Reporting::UserInput.new
111
112
  ui.input_type = :UNKNOWN
112
113
  ui.value = command
113
114
  sample.user_input = ui
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/agent/protect/rule/base'
5
+ require 'contrast/agent/reporting/details/untrusted_deserialization_details'
5
6
  require 'contrast/components/logger'
6
7
 
7
8
  module Contrast
@@ -116,7 +117,7 @@ module Contrast
116
117
  ia_result = build_evaluation(gadget_command)
117
118
  result = build_attack_with_match(context, ia_result, nil, gadget_command, **kwargs)
118
119
  append_to_activity(context, result)
119
- cef_logging(result, :successful_attack, gadget_command)
120
+ cef_logging(result, :successful_attack, value: gadget_command)
120
121
  raise(Contrast::SecurityException.new(self, BLOCK_MESSAGE)) if blocked?
121
122
  end
122
123
 
@@ -135,13 +136,13 @@ module Contrast
135
136
  # to render this attack event in TeamServer.
136
137
  def build_sample context, input_analysis_result, _candidate_string, **kwargs
137
138
  sample = build_base_sample(context, input_analysis_result)
138
- sample.untrusted_deserialization = Contrast::Api::Dtm::UntrustedDeserializationDetails.new
139
+ sample.details = Contrast::Agent::Reporting::Details::UntrustedDeserializationDetails.new
139
140
 
140
141
  deserializer = Contrast::Utils::StringUtils.protobuf_safe_string(kwargs[:GADGET_TYPE])
141
- sample.untrusted_deserialization.deserializer = deserializer
142
+ sample.details.deserializer = deserializer
142
143
 
143
144
  command = !!kwargs[:COMMAND_SCOPE]
144
- sample.untrusted_deserialization.command = command
145
+ sample.details.cmd = command
145
146
 
146
147
  sample
147
148
  end
@@ -3,6 +3,8 @@
3
3
 
4
4
  require 'contrast/agent/protect/rule/base_service'
5
5
  require 'contrast/utils/stack_trace_utils'
6
+ require 'contrast/agent/reporting/details/path_traversal_details'
7
+ require 'contrast/agent/reporting/details/path_traversal_semantic_analysis_details'
6
8
 
7
9
  module Contrast
8
10
  module Agent
@@ -48,7 +50,7 @@ module Contrast
48
50
  append_to_activity(context, result)
49
51
  return unless blocked?
50
52
 
51
- cef_logging(result, :successful_attack, path)
53
+ cef_logging(result, :successful_attack)
52
54
  raise(Contrast::SecurityException.new(self,
53
55
  "Path Traversal rule triggered. Call to File.#{ method } blocked."))
54
56
  end
@@ -65,9 +67,9 @@ module Contrast
65
67
  # evaluation
66
68
  def build_sample context, input_analysis_result, path, **_kwargs
67
69
  sample = build_base_sample(context, input_analysis_result)
68
- sample.path_traversal = Contrast::Api::Dtm::PathTraversalDetails.new
70
+ sample.details = Contrast::Agent::Reporting::Details::PathTraversalDetails.new
69
71
  path ||= input_analysis_result.value
70
- sample.path_traversal.path = Contrast::Utils::StringUtils.protobuf_safe_string(path)
72
+ sample.details.path = Contrast::Utils::StringUtils.protobuf_safe_string(path)
71
73
  sample
72
74
  end
73
75
 
@@ -76,17 +78,17 @@ module Contrast
76
78
  # Build a subclass of the RaspRuleSample if the sample matches
77
79
  def build_rep_sample context, path
78
80
  sample = build_base_sample(context, nil)
79
- sample.path_traversal_semantic = Contrast::Api::Dtm::PathTraversalSemanticAnalysisDetails.new
81
+ sample.details = Contrast::Agent::Reporting::Details::PathTraversalSemanticAnalysisDetails.new
80
82
  path = Contrast::Utils::StringUtils.protobuf_safe_string(path)
81
- sample.path_traversal_semantic.path = path
83
+ sample.details.path = path
82
84
 
83
85
  if custom_code_access_sysfile_enabled? && custom_code_accessing_system_file?(path)
84
- sample.path_traversal_semantic.findings << :CUSTOM_CODE_ACCESSING_SYSTEM_FILES
86
+ sample.details.findings << :CUSTOM_CODE_ACCESSING_SYSTEM_FILES
85
87
  return sample
86
88
  end
87
89
 
88
90
  if common_file_exploits_enabled? && contains_known_attack_signatures?(path)
89
- sample.path_traversal_semantic.findings << :COMMON_FILE_EXPLOITS
91
+ sample.details.findings << :COMMON_FILE_EXPLOITS
90
92
  return sample
91
93
  end
92
94
 
@@ -3,6 +3,8 @@
3
3
 
4
4
  require 'contrast/agent/protect/rule/base'
5
5
  require 'contrast/agent/protect/rule/base_service'
6
+ require 'contrast/agent/reporting/details/sqli_details'
7
+ require 'contrast/agent/reporting/details/no_sqli_details'
6
8
 
7
9
  module Contrast
8
10
  module Agent
@@ -18,16 +20,16 @@ module Contrast
18
20
  # @candidate_string [String] the value of the input which may be an attack
19
21
  # @kwargs [Hash] key - value pairs of context individual rules need to build out details
20
22
  # to send to the Service to tell the story of the attack
21
- # @return [Contrast::Api::Dtm::RaspRuleSample] the sample from this attack
23
+ # @return [Contrast::Agent::Reporting::RaspRuleSample] the sample from this attack
22
24
  module SqliSample
23
25
  def build_sample context, input_analysis_result, candidate_string, **kwargs
24
26
  sqli_sample = build_base_sample(context, input_analysis_result)
25
- sqli_sample.sqli = Contrast::Api::Dtm::SqlInjectionDetails.new
26
- sqli_sample.sqli.query = Contrast::Utils::StringUtils.protobuf_safe_string(candidate_string)
27
- sqli_sample.sqli.start_idx = kwargs[:start_idx]
28
- sqli_sample.sqli.end_idx = kwargs[:end_idx]
29
- sqli_sample.sqli.boundary_overrun_idx = kwargs[:boundary_overrun_idx].to_i
30
- sqli_sample.sqli.input_boundary_idx = kwargs[:input_boundary_idx].to_i
27
+ sqli_sample.details = Contrast::Agent::Reporting::Details::SqliDetails.new
28
+ sqli_sample.details.query = Contrast::Utils::StringUtils.protobuf_safe_string(candidate_string)
29
+ sqli_sample.details.start_idx = kwargs[:start_idx]
30
+ sqli_sample.details.end_idx = kwargs[:end_idx]
31
+ sqli_sample.details.boundary_overrun_idx = kwargs[:boundary_overrun_idx].to_i
32
+ sqli_sample.details.input_boundary_idx = kwargs[:input_boundary_idx].to_i
31
33
  sqli_sample
32
34
  end
33
35
  end
@@ -41,16 +43,16 @@ module Contrast
41
43
  # @candidate_string [String] the value of the input which may be an attack
42
44
  # @kwargs [Hash] key - value pairs of context individual rules need to build out details
43
45
  # to send to the Service to tell the story of the attack
44
- # @return [Contrast::Api::Dtm::RaspRuleSample] the sample from this attack
46
+ # @return [Contrast::Agent::Reporting::RaspRuleSample] the sample from this attack
45
47
  module NoSqliSample
46
48
  def build_sample context, input_analysis_result, candidate_string, **kwargs
47
49
  no_sqli_sample = build_base_sample(context, input_analysis_result)
48
- no_sqli_sample.no_sqli = Contrast::Api::Dtm::NoSqlInjectionDetails.new
49
- no_sqli_sample.no_sqli.query = Contrast::Utils::StringUtils.protobuf_safe_string(candidate_string)
50
- no_sqli_sample.no_sqli.start_idx = kwargs[:start_idx].to_i
51
- no_sqli_sample.no_sqli.end_idx = kwargs[:end_idx].to_i
52
- no_sqli_sample.no_sqli.boundary_overrun_idx = kwargs[:boundary_overrun_idx].to_i
53
- no_sqli_sample.no_sqli.input_boundary_idx = kwargs[:input_boundary_idx].to_i
50
+ no_sqli_sample.details = Contrast::Agent::Reporting::Details::NoSqliDetails.new
51
+ no_sqli_sample.details.query = Contrast::Utils::StringUtils.protobuf_safe_string(candidate_string)
52
+ no_sqli_sample.details.start_idx = kwargs[:start_idx].to_i
53
+ no_sqli_sample.details.end_idx = kwargs[:end_idx].to_i
54
+ no_sqli_sample.details.boundary_overrun_idx = kwargs[:boundary_overrun_idx].to_i
55
+ no_sqli_sample.details.input_boundary_idx = kwargs[:input_boundary_idx].to_i
54
56
  no_sqli_sample
55
57
  end
56
58
  end
@@ -61,7 +61,7 @@ module Contrast
61
61
 
62
62
  append_to_activity(context, result)
63
63
 
64
- cef_logging(result, :successful_attack, query_string)
64
+ cef_logging(result, :successful_attack, value: query_string)
65
65
  raise(Contrast::SecurityException.new(self, BLOCK_MESSAGE)) if blocked?
66
66
  end
67
67
  end
@@ -2,6 +2,9 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/agent/protect/rule/base'
5
+ require 'contrast/agent/reporting/details/xxe_details'
6
+ require 'contrast/agent/reporting/details/xxe_match'
7
+ require 'contrast/agent/reporting/details/xxe_wrapper'
5
8
  require 'contrast/utils/timer'
6
9
  require 'contrast/components/logger'
7
10
 
@@ -62,7 +65,7 @@ module Contrast
62
65
  append_to_activity(context, result)
63
66
  return unless blocked?
64
67
 
65
- cef_logging(result, :successful_attack, xml)
68
+ cef_logging(result, :successful_attack, value: xml)
66
69
  raise(Contrast::SecurityException.new(self, BLOCK_MESSAGE))
67
70
  end
68
71
 
@@ -105,7 +108,7 @@ module Contrast
105
108
  entity_wrapper = Contrast::Agent::Protect::Rule::Xxe::EntityWrapper.new(ss.matched)
106
109
  next unless entity_wrapper.external_entity?
107
110
 
108
- xxe_details ||= Contrast::Api::Dtm::XxeDetails.new
111
+ xxe_details ||= Contrast::Agent::Reporting::Details::XxeDetails.new
109
112
  xxe_details.declared_entities << build_match(ss)
110
113
  xxe_details.entities_resolved << build_wrapper(entity_wrapper)
111
114
  end
@@ -119,12 +122,12 @@ module Contrast
119
122
  def build_sample context, ia_result, _url, **kwargs
120
123
  sample = build_base_sample(context, ia_result)
121
124
  sample.user_input = build_user_input(ia_result)
122
- sample.xxe = kwargs[:details]
125
+ sample.details = kwargs[:details]
123
126
  sample
124
127
  end
125
128
 
126
129
  def build_user_input ia_result
127
- input = Contrast::Api::Dtm::UserInput.new
130
+ input = Contrast::Agent::Reporting::UserInput.new
128
131
  input.key = INPUT_NAME
129
132
  input.input_type = :UNKNOWN
130
133
  input.document_type = :XML
@@ -146,14 +149,14 @@ module Contrast
146
149
  end
147
150
 
148
151
  def build_match string_scanner
149
- match = Contrast::Api::Dtm::XxeMatch.new
152
+ match = Contrast::Agent::Reporting::Details::XxeMatch.new
150
153
  match.end_idx = string_scanner.pos.to_i
151
154
  match.start_idx = match.end_idx - string_scanner.matched_size
152
155
  match
153
156
  end
154
157
 
155
158
  def build_wrapper entity_wrapper
156
- wrapper = Contrast::Api::Dtm::XxeWrapper.new
159
+ wrapper = Contrast::Agent::Reporting::Details::XxeWrapper.new
157
160
  wrapper.system_id = Contrast::Utils::StringUtils.protobuf_safe_string(entity_wrapper.system_id)
158
161
  wrapper.public_id = Contrast::Utils::StringUtils.protobuf_safe_string(entity_wrapper.public_id)
159
162
  wrapper
@@ -57,6 +57,14 @@ module Contrast
57
57
  def tags= tags
58
58
  @_tags = tags if tags.is_a?(String)
59
59
  end
60
+
61
+ def details
62
+ @_details ||= {}
63
+ end
64
+
65
+ def details= protect_details
66
+ @_details = protect_details if protect_details.is_a?(Contrast::Agent::Reporting::Details::ProtectRuleDetails)
67
+ end
60
68
  end
61
69
  end
62
70
  end