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.
- 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 +16 -12
- data/lib/contrast/agent/inventory/policy/datastores.rb +1 -2
- 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_events/preflight_message.rb +2 -2
- data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -7
- data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +2 -2
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +2 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +1 -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/api/decorators/message.rb +1 -1
- data/lib/contrast/components/app_context.rb +62 -8
- data/lib/contrast/components/app_context_extend.rb +8 -8
- data/lib/contrast/config/assess_configuration.rb +1 -1
- data/lib/contrast/config/root_configuration.rb +6 -4
- data/lib/contrast/config.rb +0 -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 +16 -10
- data/lib/contrast/utils/net_http_base.rb +5 -6
- data/lib/contrast/utils/string_utils.rb +2 -6
- data/lib/contrast.rb +1 -1
- metadata +30 -14
- data/lib/contrast/config/application_configuration.rb +0 -57
@@ -30,21 +30,18 @@ module Contrast
|
|
30
30
|
|
31
31
|
# Mask sensitive data according to the contrast sensitive data rules.
|
32
32
|
#
|
33
|
-
# @param [Contrast::
|
33
|
+
# @param [Contrast::Agent::Reporting::ApplicationActivity]
|
34
34
|
def mask activity
|
35
|
-
return unless Contrast::Agent::Reporter.enabled?
|
36
35
|
return unless activity
|
37
36
|
|
38
|
-
logger.debug('
|
39
|
-
activity: activity.__id__,
|
40
|
-
request: activity.http_request&.uuid)
|
37
|
+
logger.debug('Masker: masking sensitive data', activity: activity.__id__, request: activity.request&.__id__)
|
41
38
|
mask_body(activity)
|
42
39
|
mask_query_string(activity)
|
43
40
|
mask_request_params(activity)
|
44
41
|
mask_request_cookies(activity)
|
45
42
|
mask_request_headers(activity)
|
46
43
|
rescue StandardError => _e
|
47
|
-
logger.debug('Could not mask activity!', activity: activity.__id__, request: activity.
|
44
|
+
logger.debug('Could not mask activity!', activity: activity.__id__, request: activity.request&.__id__)
|
48
45
|
end
|
49
46
|
|
50
47
|
private
|
@@ -64,68 +61,67 @@ module Contrast
|
|
64
61
|
|
65
62
|
# Mask request body:
|
66
63
|
#
|
67
|
-
# @param activity [Contrast::
|
64
|
+
# @param activity [Contrast::Agent::Reporting::ApplicationActivity]
|
68
65
|
# @return masked_body [String, nil]
|
69
66
|
def mask_body activity
|
70
67
|
return unless mask_body?
|
71
68
|
|
72
|
-
body = activity.
|
69
|
+
body = activity.request.body
|
73
70
|
return if body.nil? || body.empty?
|
74
71
|
|
75
|
-
activity.
|
76
|
-
activity.
|
72
|
+
activity.request.body = BODY_MASK
|
73
|
+
activity.request.body_binary = BODY_BINARY_MASK
|
77
74
|
end
|
78
75
|
|
79
76
|
# Mask request params.
|
80
77
|
#
|
81
|
-
# @param activity [Contrast::
|
78
|
+
# @param activity [Contrast::Agent::Reporting::ApplicationActivity]
|
82
79
|
# @return masked_body [String, nil]
|
83
80
|
def mask_request_params activity
|
84
|
-
params = activity.
|
81
|
+
params = activity.request.parameters
|
85
82
|
return unless params
|
86
83
|
|
87
|
-
mask_with_dictionary(activity.
|
84
|
+
mask_with_dictionary(activity.attack_results, params)
|
88
85
|
end
|
89
86
|
|
90
87
|
def mask_request_headers activity
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
88
|
+
headers = activity.request.headers
|
89
|
+
return if headers&.empty?
|
90
|
+
|
91
|
+
# Used normalized request_headers
|
92
|
+
mask = mask_with_dictionary(activity.attack_results, headers)
|
93
|
+
activity.request.headers = mask if mask
|
98
94
|
end
|
99
95
|
|
100
96
|
# Mask Cookies.
|
101
97
|
#
|
102
|
-
# @param activity [Contrast::
|
98
|
+
# @param activity [Contrast::Agent::Reporting::ApplicationActivity] Activity to mask
|
103
99
|
# @return masked_values [Hash, nil]
|
104
100
|
def mask_request_cookies activity
|
105
|
-
cookies = activity.
|
106
|
-
return
|
101
|
+
cookies = activity.request.cookies
|
102
|
+
return if cookies&.empty?
|
107
103
|
|
108
|
-
mask_with_dictionary(activity.
|
104
|
+
mask_with_dictionary(activity.attack_results, cookies)
|
109
105
|
end
|
110
106
|
|
111
107
|
# Mask request query string:
|
112
108
|
# exp: password => sensitive to password => contrast-redacted-password
|
113
109
|
#
|
114
|
-
# @param activity [Contrast::
|
110
|
+
# @param activity [Contrast::Agent::Reporting::ApplicationActivity]
|
115
111
|
# @return masked_query [String]
|
116
112
|
def mask_query_string activity
|
117
|
-
qs = activity.
|
113
|
+
qs = activity.request.query_string
|
118
114
|
return if qs.nil? || qs.empty?
|
119
115
|
|
120
|
-
|
121
|
-
|
116
|
+
mask = mask_raw_query(qs, activity.attack_results)
|
117
|
+
activity.request.query_string = mask if mask
|
122
118
|
end
|
123
119
|
|
124
120
|
# Mask if the value in the passed hash are matched against dictionary
|
125
121
|
# keyword. If the mask_attack_vector flag is set, this will also mask
|
126
122
|
# any attack.
|
127
123
|
#
|
128
|
-
# @param results [Array<Contrast::
|
124
|
+
# @param results [Array<Contrast::Agent::Reporting::ApplicationDefendAttackActivity>]
|
129
125
|
# results to match against.
|
130
126
|
# @param hash [Hash] Normalized hash representing the key/val pair from
|
131
127
|
# the activity's http request parameters.
|
@@ -134,81 +130,98 @@ module Contrast
|
|
134
130
|
return if hash.nil? || hash.empty?
|
135
131
|
|
136
132
|
hash.each do |key, val|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
# key => Contrast::Api::Dtm::Pair (key, val<Values>).
|
142
|
-
# try one level down
|
143
|
-
if val.cs__respond_to?(:values)
|
144
|
-
mask_values(key, val, results)
|
133
|
+
next unless dictionary_match(key)
|
134
|
+
|
135
|
+
if val.cs__is_a?(Array)
|
136
|
+
mask_values(key, val, hash, results)
|
145
137
|
else
|
146
138
|
# Just assign keys.
|
147
139
|
mask_hash(key, val, hash, results)
|
148
140
|
end
|
149
141
|
end
|
150
|
-
hash
|
151
142
|
end
|
152
143
|
|
153
|
-
# Mask the values of
|
154
|
-
#
|
144
|
+
# Mask the values of key value pair with array of string as input.
|
145
|
+
# If the mask_attack_vector? flag is set then the attack vector won't be
|
146
|
+
# masked.
|
155
147
|
#
|
156
|
-
# @param key [String]
|
157
|
-
#
|
158
|
-
# @param results [Array<Contrast::
|
148
|
+
# @param key [String]
|
149
|
+
# @param hash [Hash] Normalized hash representing the key/val pair.
|
150
|
+
# @param results [Array<Contrast::Agent::Reporting::ApplicationDefendAttackActivity>]
|
159
151
|
# results to match against.
|
160
|
-
# @param val [
|
161
|
-
def mask_values key, val, results
|
162
|
-
val.
|
152
|
+
# @param val [String, Array<String>]
|
153
|
+
def mask_values key, val, hash, results
|
154
|
+
val.each.with_index do |v, idx|
|
163
155
|
# Mask the attack vector only if the flag is set.
|
164
|
-
|
156
|
+
hash[key][idx] = MASK + key.downcase if attack_vector?(results, v) && mask_attack_vector?
|
165
157
|
# It is not attack vector and we mask it as normal.
|
166
|
-
|
158
|
+
hash[key][idx] = MASK + key.downcase unless attack_vector?(results, v)
|
167
159
|
end
|
168
|
-
|
160
|
+
hash
|
169
161
|
end
|
170
162
|
|
171
|
-
# Handles the masking of
|
172
|
-
# this case is used when called from #mask_field_hash
|
173
|
-
# and #mask_raw_query helper methods. Since they dont
|
174
|
-
# return values containing sub-values (key, val<Values>).
|
163
|
+
# Handles the masking of hash
|
175
164
|
#
|
176
165
|
# @param key [String] current iterable key from Protobuf::Field::FieldHash
|
177
166
|
# @param val [String] normalized value to be matched against the results
|
178
167
|
# and masked.
|
179
168
|
# @param hash [Hash] Normalized hash representing the key/val pair.
|
180
|
-
# @param results [Array<Contrast::
|
169
|
+
# @param results [Array<Contrast::Agent::Reporting::ApplicationDefendAttackActivity>]
|
181
170
|
# results to match against.
|
171
|
+
# @return [Hash]
|
182
172
|
def mask_hash key, val, hash, results
|
173
|
+
# Mask the attack vector only if the flag is set.
|
183
174
|
hash[key] = MASK + key.downcase if attack_vector?(results, val) && mask_attack_vector?
|
175
|
+
# It is not attack vector we mask it.
|
184
176
|
hash[key] = MASK + key.downcase unless attack_vector?(results, val)
|
177
|
+
hash
|
185
178
|
end
|
186
179
|
|
187
180
|
# Match to see if values matches input from AttackResults array.
|
188
181
|
# If match is found and the attack result's response is any of
|
189
182
|
# [BAP(Block At Perimeter), BLOCKED, PROBED] the return is true.
|
190
183
|
#
|
191
|
-
# @param results [Array<Contrast::
|
184
|
+
# @param results [Array<Contrast::Agent::Reporting::ApplicationDefendAttackActivity>]
|
192
185
|
# results to match against.
|
193
186
|
# @param value [String] Input to match.
|
194
|
-
# @return
|
187
|
+
# @return [Boolean]
|
195
188
|
def attack_vector? results, value
|
196
189
|
return false unless value && results
|
197
190
|
|
198
|
-
results.each do |
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
191
|
+
results.each do |attacker|
|
192
|
+
attacker.each do |activity|
|
193
|
+
blocked = iterate_attack_samples(activity.blocked, value)
|
194
|
+
return blocked if blocked
|
195
|
+
|
196
|
+
exploited = iterate_attack_samples(activity.exploited, value)
|
197
|
+
return exploited if exploited
|
205
198
|
|
206
|
-
|
199
|
+
ineffective = iterate_attack_samples(activity.ineffective, value)
|
200
|
+
return ineffective if ineffective
|
201
|
+
|
202
|
+
suspicious = iterate_attack_samples(activity.suspicious, value)
|
203
|
+
return suspicious if suspicious
|
207
204
|
end
|
208
205
|
end
|
209
206
|
false
|
210
207
|
end
|
211
208
|
|
209
|
+
# Go through activity samples and search for a matching input.
|
210
|
+
#
|
211
|
+
# @param activity [Contrast::Agent::Reporting::ApplicationDefendAttackActivity]
|
212
|
+
# @param value [String] Input to match.
|
213
|
+
# @return [Boolean]
|
214
|
+
def iterate_attack_samples activity, value
|
215
|
+
return false unless activity
|
216
|
+
|
217
|
+
activity.samples.any? do |sample|
|
218
|
+
match = sample.user_input.value == value.to_s
|
219
|
+
|
220
|
+
return true if match
|
221
|
+
end
|
222
|
+
false
|
223
|
+
end
|
224
|
+
|
212
225
|
# Consult with our current settings state.
|
213
226
|
#
|
214
227
|
# @return true | false
|
@@ -227,7 +240,7 @@ module Contrast
|
|
227
240
|
#
|
228
241
|
# @param value [String] Value to check.
|
229
242
|
# @return match [String, nil] from the Dictionary, or nil.
|
230
|
-
def
|
243
|
+
def dictionary_match value
|
231
244
|
return unless @_dictionary
|
232
245
|
|
233
246
|
@_dictionary.each do |rule|
|
@@ -9,35 +9,6 @@ module Contrast
|
|
9
9
|
# helper methods used for masking
|
10
10
|
module MaskerUtils
|
11
11
|
include Contrast::Utils::ObjectShare
|
12
|
-
# Helper to deal with Protobuf FieldHash.
|
13
|
-
#
|
14
|
-
# @param field_hash [Protobuf::Field::FieldHash] hash to be masked
|
15
|
-
# @param results [Array<Contrast::Api::Dtm::AttackResults>]
|
16
|
-
# results to match against.
|
17
|
-
# @return [Hash]
|
18
|
-
def mask_field_hash field_hash, results
|
19
|
-
return {} unless field_hash&.any?
|
20
|
-
|
21
|
-
hash = {}
|
22
|
-
# Because this is the start of a built string, we have to be sure that it is not frozen.
|
23
|
-
masked = +''
|
24
|
-
field_hash.each do |entry|
|
25
|
-
# Protobuf::Field::FieldHash produces array, with the key as first param and value as second.
|
26
|
-
new_value = entry[1].delete(SEMICOLON).split(SPACE)
|
27
|
-
new_value.each do |value|
|
28
|
-
arr = value.split(EQUALS)
|
29
|
-
# Add to new hash.
|
30
|
-
hash[arr[0]] = arr[1]
|
31
|
-
end
|
32
|
-
# Mask the newly created hash.
|
33
|
-
mask_with_dictionary(results, hash)
|
34
|
-
|
35
|
-
# Restore to original form.
|
36
|
-
hash.each { |k, v| masked += "#{ k }=#{ v }; " }
|
37
|
-
masked.rstrip!
|
38
|
-
field_hash[entry[0]] = masked
|
39
|
-
end
|
40
|
-
end
|
41
12
|
|
42
13
|
# Mask raw query as it comes from the env.
|
43
14
|
# exp:
|
@@ -45,7 +16,7 @@ module Contrast
|
|
45
16
|
# 'ssn=contrast-redacted-ssn&id=contrast-redacted-id'
|
46
17
|
#
|
47
18
|
# @param query [String]
|
48
|
-
# @param results [Array<Contrast::
|
19
|
+
# @param results [Array<Contrast::Agent::Reporting::ApplicationDefendAttackActivitys>]
|
49
20
|
# results to match against.
|
50
21
|
def mask_raw_query query, results
|
51
22
|
masked = EMPTY_STRING
|
@@ -5,6 +5,7 @@ require 'contrast/components/logger'
|
|
5
5
|
require 'contrast/agent/reporting/reporting_events/application_reporting_event'
|
6
6
|
require 'contrast/agent/reporting/reporting_events/application_defend_activity'
|
7
7
|
require 'contrast/agent/reporting/reporting_events/application_inventory_activity'
|
8
|
+
require 'contrast/agent/reporting/attack_result/response_type'
|
8
9
|
|
9
10
|
module Contrast
|
10
11
|
module Agent
|
@@ -12,38 +13,106 @@ module Contrast
|
|
12
13
|
# This is the new ApplicationActivity class which will include all the needed information for the new reporting
|
13
14
|
# system to report
|
14
15
|
class ApplicationActivity < Contrast::Agent::Reporting::ApplicationReportingEvent
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
include Contrast::Agent::Reporting::ResponseType
|
17
|
+
|
18
|
+
# @return [Integer]
|
19
|
+
attr_accessor :query_count
|
20
|
+
# @return [Array]
|
21
|
+
attr_accessor :routes
|
22
|
+
# @return [Array]
|
23
|
+
attr_accessor :dynamic_sources
|
24
|
+
# @return [Contrast::Agent::Response]
|
25
|
+
attr_accessor :response
|
24
26
|
|
25
27
|
def initialize
|
28
|
+
@routes = []
|
29
|
+
@dynamic_sources = {}
|
30
|
+
@query_count = 0
|
26
31
|
@event_method = :PUT
|
27
32
|
@event_type = :application_activity
|
28
33
|
@event_endpoint = Contrast::Agent::Reporting::Endpoints.application_activity
|
29
34
|
super
|
30
35
|
end
|
31
36
|
|
37
|
+
# @return [Contrast::Agent::Reporting::FindingRequest] Current context's request
|
38
|
+
def request
|
39
|
+
@_request ||= FindingRequest.convert(Contrast::Agent::REQUEST_TRACKER.current&.request)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Contrast::Agent::Reporting::ApplicationDefendActivity] main
|
43
|
+
# activity for all protect rules.
|
44
|
+
def defend
|
45
|
+
@_defend ||= Contrast::Agent::Reporting::ApplicationDefendActivity.new
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [Contrast::Agent::Reporting::ApplicationInventoryActivity] main
|
49
|
+
# activity for all inventory activity reporting.
|
50
|
+
def inventory
|
51
|
+
@_inventory ||= Contrast::Agent::Reporting::ApplicationInventoryActivity.new
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return file_name [String] used for audit
|
32
55
|
def file_name
|
33
56
|
'activity-application'
|
34
57
|
end
|
35
58
|
|
36
59
|
def to_controlled_hash
|
37
60
|
hsh = { lastUpdate: since_last_update }
|
38
|
-
hsh[:defend] = @
|
39
|
-
hsh[:inventory] = @
|
61
|
+
hsh[:defend] = @_defend&.to_controlled_hash if @_defend
|
62
|
+
hsh[:inventory] = @_inventory&.to_controlled_hash if @_inventory
|
40
63
|
hsh
|
41
64
|
end
|
42
65
|
|
43
|
-
#
|
44
|
-
|
45
|
-
|
46
|
-
|
66
|
+
# Look for attack results and access to samples by
|
67
|
+
# searching with rule_id and response_type
|
68
|
+
#
|
69
|
+
# @param rule_id [String] name of the protect rule
|
70
|
+
# @param response_type[Symbol<Contrast::Agent::Reporting::ResponseType]
|
71
|
+
# filter by response type
|
72
|
+
# @return [Array<Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity>, nil]
|
73
|
+
# return any matches.
|
74
|
+
def attack_results_for rule_id, response_type = nil
|
75
|
+
results = []
|
76
|
+
defend.attackers.each do |attacker|
|
77
|
+
results << case response_type
|
78
|
+
when BLOCKED, BLOCK_AT_PERIMETER
|
79
|
+
attacker.protection_rules[rule_id].blocked
|
80
|
+
when EXPLOITED
|
81
|
+
attacker.protection_rules[rule_id].exploited
|
82
|
+
when PROBED
|
83
|
+
attacker.protection_rules[rule_id].ineffective
|
84
|
+
when SUSPICIOUS
|
85
|
+
attacker.protection_rules[rule_id].suspicious
|
86
|
+
else
|
87
|
+
attacker.protection_rules[rule_id]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
results
|
91
|
+
end
|
92
|
+
|
93
|
+
# By reference. List of all results only by values, no rule_ids.
|
94
|
+
#
|
95
|
+
# @return [Array<[Contrast::Agent::Reporting::ApplicationDefendAttackerActivity]>]
|
96
|
+
def attack_results
|
97
|
+
results = []
|
98
|
+
defend.attackers.each { |a| results << a.protection_rules.values }
|
99
|
+
results
|
100
|
+
end
|
101
|
+
|
102
|
+
# This is primary used for attaching new data and merging existing
|
103
|
+
# samples per rule entry in attackers, and to make sure the attack
|
104
|
+
# time_map is updated correctly.
|
105
|
+
#
|
106
|
+
# @param attack_result [Contrast::Agent::Reporting::AttackResult]
|
107
|
+
def attach_defend attack_result
|
108
|
+
defend.attach_data(attack_result)
|
109
|
+
end
|
110
|
+
|
111
|
+
# This is primary used for attaching new inventory reporting
|
112
|
+
#
|
113
|
+
# @param architecture [Contrast::Agent::Reporting::AttackResult]
|
114
|
+
def attach_inventory architecture
|
115
|
+
inventory.attach_data(architecture)
|
47
116
|
end
|
48
117
|
end
|
49
118
|
end
|
@@ -13,20 +13,9 @@ module Contrast
|
|
13
13
|
# @return [Array<Contrast::Agent::Reporting::ApplicationDefendAttackerActivity>]
|
14
14
|
attr_reader :attackers
|
15
15
|
|
16
|
-
class << self
|
17
|
-
# @param activity_dtm [Contrast::Api::Dtm::ApplicationActivity]
|
18
|
-
# @return [Contrast::Agent::Reporting::ApplicationDefendActivity]
|
19
|
-
def convert activity_dtm
|
20
|
-
activity = new
|
21
|
-
activity.attach_data(activity_dtm.results)
|
22
|
-
activity
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
16
|
def initialize
|
27
17
|
@attackers = []
|
28
18
|
@event_type = :application_defend_activity
|
29
|
-
super
|
30
19
|
end
|
31
20
|
|
32
21
|
def to_controlled_hash
|
@@ -35,20 +24,19 @@ module Contrast
|
|
35
24
|
}
|
36
25
|
end
|
37
26
|
|
38
|
-
# @param
|
39
|
-
def attach_data
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
27
|
+
# @param attack_result [Contrast::Agent::Reporting::AttackResult]
|
28
|
+
def attach_data attack_result
|
29
|
+
attacker_activity = Contrast::Agent::Reporting::ApplicationDefendAttackerActivity.new
|
30
|
+
attacker_activity.attach_data(attack_result)
|
31
|
+
existing_attacker_activity = attackers.find do |existing|
|
32
|
+
existing.source_forwarded_for == attacker_activity.source_forwarded_for &&
|
33
|
+
existing.source_ip == attacker_activity.source_ip
|
34
|
+
end
|
35
|
+
rule = attack_result.rule_id
|
36
|
+
if existing_attacker_activity
|
37
|
+
attach_existing(existing_attacker_activity, attacker_activity, rule)
|
38
|
+
else
|
39
|
+
attackers << attacker_activity
|
52
40
|
end
|
53
41
|
end
|
54
42
|
|
@@ -19,44 +19,39 @@ module Contrast
|
|
19
19
|
attr_accessor :ineffective
|
20
20
|
# @return [Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity]
|
21
21
|
attr_accessor :suspicious
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
activity = new
|
27
|
-
activity.attach_data(attack_result)
|
28
|
-
activity
|
29
|
-
end
|
30
|
-
end
|
22
|
+
# Helper method to determine before hand the response type and iv needed for access
|
23
|
+
#
|
24
|
+
# @return [Contrast::Agent::Reporting::ResponseType]
|
25
|
+
attr_reader :response_type
|
31
26
|
|
32
27
|
def initialize
|
33
28
|
@start_time = start_time
|
34
|
-
super
|
35
29
|
end
|
36
30
|
|
37
31
|
def to_controlled_hash
|
38
32
|
{
|
39
33
|
startTime: @start_time,
|
40
|
-
blocked: blocked&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
|
41
|
-
exploited: exploited&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
|
42
|
-
ineffective: ineffective&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
|
43
|
-
suspicious: suspicious&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH
|
34
|
+
blocked: @blocked&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
|
35
|
+
exploited: @exploited&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
|
36
|
+
ineffective: @ineffective&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
|
37
|
+
suspicious: @suspicious&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH
|
44
38
|
}
|
45
39
|
end
|
46
40
|
|
47
|
-
# @param attack_result [Contrast::
|
41
|
+
# @param attack_result [Contrast::Agent::Reporting::AttackResult]
|
48
42
|
# @return [Contrast::Agent::Reporting::Defend::AttackSampleActivity]
|
49
43
|
def attach_data attack_result
|
50
|
-
attack_sample_activity =
|
51
|
-
|
52
|
-
|
53
|
-
|
44
|
+
attack_sample_activity = Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity.new
|
45
|
+
attack_sample_activity.attach_data(attack_result)
|
46
|
+
@response_type = attack_result.response
|
47
|
+
case response_type
|
48
|
+
when ::Contrast::Agent::Reporting::ResponseType::BLOCKED
|
54
49
|
@blocked = attack_sample_activity
|
55
|
-
when ::Contrast::
|
50
|
+
when ::Contrast::Agent::Reporting::ResponseType::MONITORED
|
56
51
|
@exploited = attack_sample_activity
|
57
|
-
when ::Contrast::
|
52
|
+
when ::Contrast::Agent::Reporting::ResponseType::PROBED
|
58
53
|
@ineffective = attack_sample_activity
|
59
|
-
when ::Contrast::
|
54
|
+
when ::Contrast::Agent::Reporting::ResponseType::SUSPICIOUS
|
60
55
|
@suspicious = attack_sample_activity
|
61
56
|
end
|
62
57
|
end
|