contrast-agent 6.6.4 → 6.6.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/contrast/agent/assess/policy/trigger_method.rb +21 -6
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +2 -0
- data/lib/contrast/agent/at_exit_hook.rb +1 -7
- data/lib/contrast/agent/inventory/database_config.rb +12 -13
- data/lib/contrast/agent/middleware.rb +0 -1
- data/lib/contrast/agent/protect/rule/base.rb +16 -20
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +5 -4
- data/lib/contrast/agent/protect/rule/deserialization.rb +5 -4
- data/lib/contrast/agent/protect/rule/path_traversal.rb +9 -7
- data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +16 -14
- data/lib/contrast/agent/protect/rule/sqli.rb +1 -1
- data/lib/contrast/agent/protect/rule/xxe.rb +9 -6
- data/lib/contrast/agent/reporting/attack_result/attack_result.rb +8 -0
- data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +85 -36
- data/lib/contrast/agent/reporting/attack_result/user_input.rb +11 -0
- data/lib/contrast/agent/reporting/details/bot_blocker_details.rb +29 -0
- data/lib/contrast/agent/reporting/details/cmd_injection_details.rb +30 -0
- data/lib/contrast/agent/reporting/details/details.rb +18 -0
- data/lib/contrast/agent/reporting/details/http_method_tempering_details.rb +27 -0
- data/lib/contrast/agent/reporting/details/ip_denylist_details.rb +27 -0
- data/lib/contrast/agent/reporting/details/no_sqli_details.rb +36 -0
- data/lib/contrast/agent/reporting/details/path_traversal_details.rb +24 -0
- data/lib/contrast/agent/reporting/details/path_traversal_semantic_analysis_details.rb +32 -0
- data/lib/contrast/agent/reporting/details/protect_rule_details.rb +17 -0
- data/lib/contrast/agent/reporting/details/sqli_details.rb +36 -0
- data/lib/contrast/agent/reporting/details/untrusted_deserialization_details.rb +27 -0
- data/lib/contrast/agent/reporting/details/virtual_patch_details.rb +24 -0
- data/lib/contrast/agent/reporting/details/xss_details.rb +33 -0
- data/lib/contrast/agent/reporting/details/xss_match.rb +30 -0
- data/lib/contrast/agent/reporting/details/xxe_details.rb +36 -0
- data/lib/contrast/agent/reporting/details/xxe_match.rb +25 -0
- data/lib/contrast/agent/reporting/details/xxe_wrapper.rb +25 -0
- data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +1 -1
- data/lib/contrast/agent/reporting/masker/masker.rb +78 -65
- data/lib/contrast/agent/reporting/masker/masker_utils.rb +1 -30
- data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +84 -15
- data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +13 -25
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +17 -22
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +46 -125
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +5 -16
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +10 -18
- data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +6 -14
- data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +29 -20
- data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +45 -10
- data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -7
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +2 -1
- data/lib/contrast/agent/request.rb +2 -0
- data/lib/contrast/agent/request_context.rb +13 -4
- data/lib/contrast/agent/request_context_extend.rb +59 -40
- data/lib/contrast/agent/request_handler.rb +7 -9
- data/lib/contrast/agent/service_heartbeat.rb +1 -1
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/components/app_context.rb +6 -6
- data/lib/contrast/config/assess_configuration.rb +1 -1
- data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +1 -6
- data/lib/contrast/utils/assess/event_limit_utils.rb +26 -7
- data/lib/contrast/utils/log_utils.rb +15 -9
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a7491020083af4de63e878defb8a57583d22258ec534fba4b6d7ad923861c55
|
4
|
+
data.tar.gz: 9c784b84420c8caa8f3123e8dc053b21a7a8964058f8e5b073cbf794275e9793
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
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.
|
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::
|
34
|
-
# @param hash_or_str [Hash, String
|
33
|
+
# @param activity_or_update [Contrast::Agent::Reporting::ApplicationUpdate]
|
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 |
|
40
|
-
next unless
|
39
|
+
arr.each do |component|
|
40
|
+
next unless component
|
41
41
|
|
42
|
-
if activity_or_update.
|
43
|
-
activity_or_update.
|
42
|
+
if activity_or_update.cs__is_a?(Contrast::Agent::Reporting::ApplicationUpdate)
|
43
|
+
activity_or_update.components << component
|
44
44
|
else
|
45
|
-
|
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,7 +77,7 @@ module Contrast
|
|
78
77
|
# reporting.
|
79
78
|
#
|
80
79
|
# @param hash_or_str [Hash, String]
|
81
|
-
# @return [Array<Contrast::
|
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
|
|
@@ -98,9 +97,9 @@ module Contrast
|
|
98
97
|
# understandable by TeamServer.
|
99
98
|
#
|
100
99
|
# @param hash [Hash] the information used to open a database connection
|
101
|
-
# @return [Array<Contrast::
|
100
|
+
# @return [Array<Contrast::Agent::Reporting::ArchitectureComponent>]
|
102
101
|
def build_from_db_hash hash
|
103
|
-
ac = Contrast::
|
102
|
+
ac = Contrast::Agent::Reporting::ArchitectureComponent.build_database
|
104
103
|
ac.vendor = hash[:adapter] || hash[ADAPTER] || Contrast::Utils::ObjectShare::EMPTY_STRING
|
105
104
|
ac.remote_host = host_from_hash(hash)
|
106
105
|
ac.remote_port = port_from_hash(hash)
|
@@ -131,7 +130,7 @@ module Contrast
|
|
131
130
|
# mysql+mysqlconnector://scott:tiger@localhost/foo # pragma: allowlist secret
|
132
131
|
#
|
133
132
|
# @param str [String] the DB connection string
|
134
|
-
# @return [Array<Contrast::
|
133
|
+
# @return [Array<Contrast::Agent::Reporting::ArchitectureComponent>, nil]
|
135
134
|
def build_from_db_string str
|
136
135
|
adapter, hosts, database = split_connection_str(str)
|
137
136
|
return unless adapter && hosts && database
|
@@ -140,7 +139,7 @@ module Contrast
|
|
140
139
|
hosts.split(Contrast::Utils::ObjectShare::COMMA).map do |s|
|
141
140
|
host, port = s.split(Contrast::Utils::ObjectShare::COLON)
|
142
141
|
|
143
|
-
ac = Contrast::
|
142
|
+
ac = Contrast::Agent::Reporting::ArchitectureComponent.build_database
|
144
143
|
ac.vendor = Contrast::Utils::StringUtils.force_utf8(adapter)
|
145
144
|
ac.remote_host = Contrast::Utils::StringUtils.force_utf8(host)
|
146
145
|
ac.remote_port = port.to_i
|
@@ -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::
|
172
|
+
# @param result [Contrast::Agent::Reporting::AttackResult]
|
173
173
|
def append_to_activity context, result
|
174
|
-
context.activity.
|
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
|
183
|
-
|
184
|
-
outcome =
|
185
|
-
|
186
|
-
|
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::
|
237
|
+
result.response = Contrast::Agent::Reporting::ResponseType::MONITORED
|
242
238
|
when Contrast::Api::Settings::ProtectionRule::Mode::BLOCK
|
243
|
-
result.response = Contrast::
|
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::
|
258
|
+
Contrast::Agent::Reporting::ResponseType::BLOCKED
|
263
259
|
else
|
264
|
-
Contrast::
|
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::
|
275
|
+
# @return [Contrast::Agent::Reporting::AttackResult]
|
280
276
|
def build_attack_result _context
|
281
|
-
result = Contrast::
|
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::
|
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::
|
365
|
+
Contrast::Agent::Reporting::ResponseType::SUSPICIOUS
|
370
366
|
else
|
371
|
-
Contrast::
|
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.
|
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.
|
105
|
-
sample.
|
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::
|
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.
|
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.
|
142
|
+
sample.details.deserializer = deserializer
|
142
143
|
|
143
144
|
command = !!kwargs[:COMMAND_SCOPE]
|
144
|
-
sample.
|
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
|
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.
|
70
|
+
sample.details = Contrast::Agent::Reporting::Details::PathTraversalDetails.new
|
69
71
|
path ||= input_analysis_result.value
|
70
|
-
sample.
|
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.
|
81
|
+
sample.details = Contrast::Agent::Reporting::Details::PathTraversalSemanticAnalysisDetails.new
|
80
82
|
path = Contrast::Utils::StringUtils.protobuf_safe_string(path)
|
81
|
-
sample.
|
83
|
+
sample.details.path = path
|
82
84
|
|
83
85
|
if custom_code_access_sysfile_enabled? && custom_code_accessing_system_file?(path)
|
84
|
-
sample.
|
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.
|
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::
|
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.
|
26
|
-
sqli_sample.
|
27
|
-
sqli_sample.
|
28
|
-
sqli_sample.
|
29
|
-
sqli_sample.
|
30
|
-
sqli_sample.
|
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::
|
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.
|
49
|
-
no_sqli_sample.
|
50
|
-
no_sqli_sample.
|
51
|
-
no_sqli_sample.
|
52
|
-
no_sqli_sample.
|
53
|
-
no_sqli_sample.
|
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::
|
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.
|
125
|
+
sample.details = kwargs[:details]
|
123
126
|
sample
|
124
127
|
end
|
125
128
|
|
126
129
|
def build_user_input ia_result
|
127
|
-
input = Contrast::
|
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::
|
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::
|
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
|