contrast-agent 4.6.0 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitmodules +1 -1
- data/Rakefile +1 -2
- data/ext/build_funchook.rb +3 -3
- data/ext/extconf_common.rb +1 -5
- data/lib/contrast/agent/assess.rb +1 -1
- data/lib/contrast/agent/assess/contrast_object.rb +2 -2
- data/lib/contrast/agent/assess/events/event_factory.rb +2 -1
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +6 -3
- data/lib/contrast/agent/assess/policy/patcher.rb +10 -17
- data/lib/contrast/agent/assess/policy/policy_node.rb +25 -33
- data/lib/contrast/agent/assess/policy/preshift.rb +3 -1
- data/lib/contrast/agent/assess/policy/propagation_method.rb +6 -15
- data/lib/contrast/agent/assess/policy/propagation_node.rb +19 -8
- data/lib/contrast/agent/assess/policy/propagator/center.rb +2 -1
- data/lib/contrast/agent/assess/policy/propagator/insert.rb +3 -1
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +2 -1
- data/lib/contrast/agent/assess/policy/propagator/select.rb +2 -12
- data/lib/contrast/agent/assess/policy/propagator/split.rb +3 -7
- data/lib/contrast/agent/assess/policy/propagator/substitution.rb +1 -7
- data/lib/contrast/agent/assess/policy/propagator/trim.rb +3 -15
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +6 -3
- data/lib/contrast/agent/assess/policy/source_method.rb +6 -6
- data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +1 -3
- data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +5 -1
- data/lib/contrast/agent/assess/policy/trigger_method.rb +6 -15
- data/lib/contrast/agent/assess/policy/trigger_node.rb +2 -1
- data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +4 -3
- data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +1 -2
- data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +1 -8
- data/lib/contrast/agent/assess/property/evented.rb +8 -5
- data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +11 -5
- data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +4 -1
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +3 -5
- data/lib/contrast/agent/class_reopener.rb +3 -1
- data/lib/contrast/agent/disable_reaction.rb +1 -3
- data/lib/contrast/agent/exclusion_matcher.rb +5 -11
- data/lib/contrast/agent/inventory/dependencies.rb +2 -0
- data/lib/contrast/agent/middleware.rb +3 -5
- data/lib/contrast/agent/module_data.rb +3 -3
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +6 -5
- data/lib/contrast/agent/patching/policy/method_policy.rb +6 -2
- data/lib/contrast/agent/patching/policy/module_policy.rb +14 -7
- data/lib/contrast/agent/patching/policy/patch.rb +11 -16
- data/lib/contrast/agent/patching/policy/patch_status.rb +6 -7
- data/lib/contrast/agent/patching/policy/patcher.rb +15 -12
- data/lib/contrast/agent/patching/policy/policy_node.rb +14 -4
- data/lib/contrast/agent/patching/policy/trigger_node.rb +21 -8
- data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +1 -1
- data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +1 -1
- data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +1 -1
- data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +2 -3
- data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +1 -1
- data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +5 -9
- data/lib/contrast/agent/protect/policy/rule_applicator.rb +5 -5
- data/lib/contrast/agent/protect/rule/base.rb +13 -16
- data/lib/contrast/agent/protect/rule/base_service.rb +9 -5
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +14 -18
- data/lib/contrast/agent/protect/rule/deserialization.rb +6 -13
- data/lib/contrast/agent/protect/rule/http_method_tampering.rb +3 -14
- data/lib/contrast/agent/protect/rule/no_sqli.rb +6 -2
- data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +1 -3
- data/lib/contrast/agent/protect/rule/path_traversal.rb +5 -5
- data/lib/contrast/agent/protect/rule/sqli.rb +1 -1
- data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +1 -1
- data/lib/contrast/agent/protect/rule/xss.rb +1 -1
- data/lib/contrast/agent/protect/rule/xxe.rb +5 -12
- data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +1 -2
- data/lib/contrast/agent/reaction_processor.rb +11 -10
- data/lib/contrast/agent/request.rb +23 -23
- data/lib/contrast/agent/request_context.rb +9 -14
- data/lib/contrast/agent/rewriter.rb +5 -3
- data/lib/contrast/agent/service_heartbeat.rb +2 -3
- data/lib/contrast/agent/tracepoint_hook.rb +1 -1
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/communication/response_processor.rb +2 -4
- data/lib/contrast/api/communication/service_lifecycle.rb +4 -2
- data/lib/contrast/api/communication/socket_client.rb +8 -21
- data/lib/contrast/api/communication/speedracer.rb +3 -7
- data/lib/contrast/api/decorators/application_startup.rb +6 -2
- data/lib/contrast/api/decorators/library.rb +8 -6
- data/lib/contrast/api/decorators/message.rb +3 -3
- data/lib/contrast/api/decorators/trace_event.rb +3 -1
- data/lib/contrast/api/decorators/trace_event_object.rb +1 -3
- data/lib/contrast/api/decorators/trace_taint_range_tags.rb +1 -6
- data/lib/contrast/components/agent.rb +9 -4
- data/lib/contrast/components/app_context.rb +6 -6
- data/lib/contrast/components/config.rb +2 -1
- data/lib/contrast/components/contrast_service.rb +7 -8
- data/lib/contrast/components/interface.rb +3 -2
- data/lib/contrast/components/sampling.rb +8 -2
- data/lib/contrast/components/settings.rb +4 -2
- data/lib/contrast/config/assess_rules_configuration.rb +1 -3
- data/lib/contrast/config/base_configuration.rb +4 -5
- data/lib/contrast/config/exception_configuration.rb +1 -5
- data/lib/contrast/config/heap_dump_configuration.rb +12 -6
- data/lib/contrast/config/logger_configuration.rb +1 -5
- data/lib/contrast/configuration.rb +3 -14
- data/lib/contrast/extension/assess/array.rb +1 -6
- data/lib/contrast/extension/assess/erb.rb +1 -7
- data/lib/contrast/extension/assess/eval_trigger.rb +2 -6
- data/lib/contrast/extension/assess/exec_trigger.rb +3 -9
- data/lib/contrast/extension/assess/fiber.rb +2 -12
- data/lib/contrast/extension/assess/kernel.rb +2 -9
- data/lib/contrast/extension/assess/marshal.rb +2 -6
- data/lib/contrast/extension/assess/regexp.rb +1 -6
- data/lib/contrast/extension/assess/string.rb +3 -1
- data/lib/contrast/extension/kernel.rb +4 -2
- data/lib/contrast/framework/manager.rb +1 -2
- data/lib/contrast/framework/rack/patch/session_cookie.rb +5 -18
- data/lib/contrast/framework/rack/patch/support.rb +6 -4
- data/lib/contrast/framework/rails/patch/assess_configuration.rb +7 -2
- data/lib/contrast/framework/rails/patch/support.rb +4 -2
- data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +4 -1
- data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +2 -0
- data/lib/contrast/framework/rails/rewrite/active_record_named.rb +2 -0
- data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +2 -0
- data/lib/contrast/framework/rails/support.rb +2 -2
- data/lib/contrast/framework/sinatra/support.rb +3 -1
- data/lib/contrast/funchook/funchook.rb +1 -5
- data/lib/contrast/logger/application.rb +12 -9
- data/lib/contrast/logger/format.rb +2 -5
- data/lib/contrast/logger/log.rb +4 -3
- data/lib/contrast/logger/request.rb +1 -2
- data/lib/contrast/security_exception.rb +1 -1
- data/lib/contrast/tasks/service.rb +5 -1
- data/lib/contrast/utils/assess/tracking_util.rb +1 -2
- data/lib/contrast/utils/class_util.rb +0 -8
- data/lib/contrast/utils/hash_digest.rb +2 -5
- data/lib/contrast/utils/io_util.rb +1 -1
- data/lib/contrast/utils/job_servers_running.rb +9 -4
- data/lib/contrast/utils/os.rb +2 -1
- data/lib/contrast/utils/ruby_ast_rewriter.rb +2 -1
- data/ruby-agent.gemspec +13 -14
- data/sonar-project.properties +9 -0
- metadata +37 -36
|
@@ -42,7 +42,8 @@ module Contrast
|
|
|
42
42
|
rescue Contrast::SecurityException => e
|
|
43
43
|
raise e
|
|
44
44
|
rescue StandardError => e
|
|
45
|
-
logger.error('Error applying protect rule', e, module: object.cs__class.cs__name, method: method,
|
|
45
|
+
logger.error('Error applying protect rule', e, module: object.cs__class.cs__name, method: method,
|
|
46
|
+
rule: rule_name)
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
protected
|
|
@@ -68,11 +69,10 @@ module Contrast
|
|
|
68
69
|
raise NoMethodError, 'This is abstract, override it.'
|
|
69
70
|
end
|
|
70
71
|
|
|
71
|
-
# The name of the rule, as expected by the Contrast Service and
|
|
72
|
-
# Contrast UI.
|
|
72
|
+
# The name of the rule, as expected by the Contrast Service and Contrast UI.
|
|
73
73
|
#
|
|
74
74
|
# @return [String]
|
|
75
|
-
def
|
|
75
|
+
def rule_name
|
|
76
76
|
raise NoMethodError, 'This is abstract, override it.'
|
|
77
77
|
end
|
|
78
78
|
|
|
@@ -82,7 +82,7 @@ module Contrast
|
|
|
82
82
|
#
|
|
83
83
|
# @return [Contrast::Agent::Protect::Rule::Base]
|
|
84
84
|
def rule
|
|
85
|
-
PROTECT.rule
|
|
85
|
+
PROTECT.rule rule_name
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
# Should we skip analysis for this rule for this method invocation?
|
|
@@ -37,13 +37,13 @@ module Contrast
|
|
|
37
37
|
attr_reader :mode
|
|
38
38
|
|
|
39
39
|
def initialize
|
|
40
|
-
PROTECT.rules[
|
|
40
|
+
PROTECT.rules[rule_name] = self
|
|
41
41
|
@mode = mode_from_settings
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
# Should return the name as it is known to Teamserver; defaults to class
|
|
45
|
-
def
|
|
46
|
-
cs__class.
|
|
45
|
+
def rule_name
|
|
46
|
+
cs__class.cs__name
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def enabled?
|
|
@@ -52,7 +52,7 @@ module Contrast
|
|
|
52
52
|
return false unless PROTECT.enabled?
|
|
53
53
|
|
|
54
54
|
# 2. it is not enabled because it is in the list of disabled protect rules
|
|
55
|
-
return false if PROTECT.rule_config&.disabled_rules&.include?(
|
|
55
|
+
return false if PROTECT.rule_config&.disabled_rules&.include?(rule_name)
|
|
56
56
|
|
|
57
57
|
# 3. it is enabled so long as its mode is not NO_ACTION
|
|
58
58
|
@mode != Contrast::Api::Settings::ProtectionRule::Mode::NO_ACTION
|
|
@@ -60,7 +60,7 @@ module Contrast
|
|
|
60
60
|
|
|
61
61
|
def excluded? exclusions
|
|
62
62
|
Array(exclusions).any? do |ex|
|
|
63
|
-
ex.protection_rule?(
|
|
63
|
+
ex.protection_rule?(rule_name)
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
@@ -176,8 +176,8 @@ module Contrast
|
|
|
176
176
|
protected
|
|
177
177
|
|
|
178
178
|
def mode_from_settings
|
|
179
|
-
PROTECT.rule_mode(
|
|
180
|
-
logger.trace('Retrieving rule mode', rule:
|
|
179
|
+
PROTECT.rule_mode(rule_name).tap do |mode|
|
|
180
|
+
logger.trace('Retrieving rule mode', rule: rule_name, mode: mode)
|
|
181
181
|
end
|
|
182
182
|
end
|
|
183
183
|
|
|
@@ -194,7 +194,7 @@ module Contrast
|
|
|
194
194
|
exclusions = SETTINGS.code_exclusions
|
|
195
195
|
return false unless exclusions
|
|
196
196
|
|
|
197
|
-
for_rule = exclusions.select { |ex| ex.protection_rule?(
|
|
197
|
+
for_rule = exclusions.select { |ex| ex.protection_rule?(rule_name) }
|
|
198
198
|
return false if for_rule.empty?
|
|
199
199
|
|
|
200
200
|
stack = caller_locations
|
|
@@ -213,7 +213,7 @@ module Contrast
|
|
|
213
213
|
# @param _kwargs [Hash] key-value pairs used by the rule to build a
|
|
214
214
|
# report.
|
|
215
215
|
def find_attacker _context, _potential_attack_string, **_kwargs
|
|
216
|
-
raise NoMethodError, "Rule #{
|
|
216
|
+
raise NoMethodError, "Rule #{ rule_name } did not implement find_attack"
|
|
217
217
|
end
|
|
218
218
|
|
|
219
219
|
def update_successful_attack_response context, ia_result, result, attack_string = nil
|
|
@@ -249,7 +249,7 @@ module Contrast
|
|
|
249
249
|
# @return [Contrast::Api::Dtm::AttackResult]
|
|
250
250
|
def build_attack_result _context
|
|
251
251
|
result = Contrast::Api::Dtm::AttackResult.new
|
|
252
|
-
result.rule_id =
|
|
252
|
+
result.rule_id = rule_name
|
|
253
253
|
result
|
|
254
254
|
end
|
|
255
255
|
|
|
@@ -286,7 +286,7 @@ module Contrast
|
|
|
286
286
|
|
|
287
287
|
def log_rule_matched _context, ia_result, response, _matched_string = nil
|
|
288
288
|
logger.debug('A successful attack was detected',
|
|
289
|
-
rule:
|
|
289
|
+
rule: rule_name,
|
|
290
290
|
type: ia_result&.input_type,
|
|
291
291
|
name: ia_result&.key,
|
|
292
292
|
input: ia_result&.value,
|
|
@@ -296,11 +296,8 @@ module Contrast
|
|
|
296
296
|
private
|
|
297
297
|
|
|
298
298
|
def log_rule_probed _context, ia_result
|
|
299
|
-
logger.debug('An unsuccessful attack was detected',
|
|
300
|
-
|
|
301
|
-
type: ia_result&.input_type,
|
|
302
|
-
name: ia_result&.key,
|
|
303
|
-
input: ia_result&.value)
|
|
299
|
+
logger.debug('An unsuccessful attack was detected', rule: rule_name, type: ia_result&.input_type,
|
|
300
|
+
name: ia_result&.key, input: ia_result&.value)
|
|
304
301
|
end
|
|
305
302
|
end
|
|
306
303
|
end
|
|
@@ -10,7 +10,7 @@ module Contrast
|
|
|
10
10
|
# Encapsulate common code for protect rules that do their
|
|
11
11
|
# input analysis on Speedracer rather in ruby code
|
|
12
12
|
class BaseService < Contrast::Agent::Protect::Rule::Base
|
|
13
|
-
def
|
|
13
|
+
def rule_name
|
|
14
14
|
'base-service'
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -32,7 +32,11 @@ module Contrast
|
|
|
32
32
|
# streamed responses will break
|
|
33
33
|
def postfilter context
|
|
34
34
|
return unless enabled? && POSTFILTER_MODES.include?(mode)
|
|
35
|
-
|
|
35
|
+
if mode == Contrast::Api::Settings::ProtectionRule::Mode::NO_ACTION ||
|
|
36
|
+
mode == Contrast::Api::Settings::ProtectionRule::Mode::PERMIT
|
|
37
|
+
|
|
38
|
+
return
|
|
39
|
+
end
|
|
36
40
|
|
|
37
41
|
result = find_postfilter_attacker(context, nil)
|
|
38
42
|
return unless result&.samples&.any?
|
|
@@ -40,14 +44,14 @@ module Contrast
|
|
|
40
44
|
append_to_activity(context, result)
|
|
41
45
|
return unless result.response == :BLOCKED
|
|
42
46
|
|
|
43
|
-
raise Contrast::SecurityException.new(self, "#{
|
|
47
|
+
raise Contrast::SecurityException.new(self, "#{ rule_name } triggered in postfilter. Response blocked.")
|
|
44
48
|
end
|
|
45
49
|
|
|
46
50
|
protected
|
|
47
51
|
|
|
48
52
|
def gather_ia_results context
|
|
49
53
|
context.speedracer_input_analysis.results.select do |ia_result|
|
|
50
|
-
ia_result.rule_id ==
|
|
54
|
+
ia_result.rule_id == rule_name
|
|
51
55
|
end
|
|
52
56
|
end
|
|
53
57
|
|
|
@@ -58,7 +62,7 @@ module Contrast
|
|
|
58
62
|
|
|
59
63
|
# Allows for the InputAnalysis from service to be extracted early
|
|
60
64
|
def find_attacker_with_results context, potential_attack_string, ia_results, **kwargs
|
|
61
|
-
logger.trace('Checking vectors for attacks', rule:
|
|
65
|
+
logger.trace('Checking vectors for attacks', rule: rule_name, input: potential_attack_string)
|
|
62
66
|
|
|
63
67
|
result = nil
|
|
64
68
|
ia_results.each do |ia_result|
|
|
@@ -18,7 +18,7 @@ module Contrast
|
|
|
18
18
|
NAME = 'cmd-injection'
|
|
19
19
|
CHAINED_COMMAND_CHARS = /[;&|<>]/.cs__freeze
|
|
20
20
|
|
|
21
|
-
def
|
|
21
|
+
def rule_name
|
|
22
22
|
NAME
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -34,20 +34,25 @@ module Contrast
|
|
|
34
34
|
Contrast::Agent::REQUEST_TRACKER.update_current_context(context)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
result = find_attacker_with_results(context, command, ia_results,
|
|
37
|
+
result = find_attacker_with_results(context, command, ia_results,
|
|
38
|
+
**{ classname: classname, method: method })
|
|
38
39
|
result ||= report_command_execution(context, command, **{ classname: classname, method: method })
|
|
39
40
|
return unless result
|
|
40
41
|
|
|
41
42
|
append_to_activity(context, result)
|
|
42
43
|
return unless blocked?
|
|
43
44
|
|
|
44
|
-
raise Contrast::SecurityException.new(
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
raise Contrast::SecurityException.new(self,
|
|
46
|
+
'Command Injection rule triggered. '\
|
|
47
|
+
"Call to #{ classname }.#{ method } blocked.")
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
def build_attack_with_match context, input_analysis_result, result, candidate_string, **kwargs
|
|
50
|
-
|
|
51
|
+
if mode == Contrast::Api::Settings::ProtectionRule::Mode::NO_ACTION ||
|
|
52
|
+
mode == Contrast::Api::Settings::ProtectionRule::Mode::PERMIT
|
|
53
|
+
|
|
54
|
+
return result
|
|
55
|
+
end
|
|
51
56
|
|
|
52
57
|
result ||= build_attack_result(context)
|
|
53
58
|
update_successful_attack_response(context, input_analysis_result, result, candidate_string)
|
|
@@ -60,14 +65,10 @@ module Contrast
|
|
|
60
65
|
# Because results are not necessarily on the context across
|
|
61
66
|
# processes; extract early and pass into the method
|
|
62
67
|
def find_attacker_with_results context, potential_attack_string, ia_results, **kwargs
|
|
63
|
-
logger.trace('Checking vectors for attacks', rule:
|
|
68
|
+
logger.trace('Checking vectors for attacks', rule: rule_name, input: potential_attack_string)
|
|
64
69
|
result = super(context, potential_attack_string, ia_results, **kwargs)
|
|
65
70
|
if result.nil? && potential_attack_string
|
|
66
|
-
result = find_probable_attacker(
|
|
67
|
-
context,
|
|
68
|
-
potential_attack_string,
|
|
69
|
-
ia_results,
|
|
70
|
-
**kwargs)
|
|
71
|
+
result = find_probable_attacker(context, potential_attack_string, ia_results, **kwargs)
|
|
71
72
|
end
|
|
72
73
|
result
|
|
73
74
|
end
|
|
@@ -109,12 +110,7 @@ module Contrast
|
|
|
109
110
|
likely_attacker = ia_results.find { |input_analysis_result| chained_command?(input_analysis_result.value) }
|
|
110
111
|
return unless likely_attacker
|
|
111
112
|
|
|
112
|
-
build_attack_with_match(
|
|
113
|
-
context,
|
|
114
|
-
likely_attacker,
|
|
115
|
-
nil,
|
|
116
|
-
potential_attack_string,
|
|
117
|
-
**kwargs)
|
|
113
|
+
build_attack_with_match(context, likely_attacker, nil, potential_attack_string, **kwargs)
|
|
118
114
|
end
|
|
119
115
|
|
|
120
116
|
def chained_command? command
|
|
@@ -17,10 +17,7 @@ module Contrast
|
|
|
17
17
|
BLOCK_MESSAGE = 'Untrusted Deserialization rule triggered. Deserialization blocked.'
|
|
18
18
|
|
|
19
19
|
# Gadgets that map to ERB modules
|
|
20
|
-
ERB_GADGETS = %W[
|
|
21
|
-
object:ERB
|
|
22
|
-
o:\bERB
|
|
23
|
-
].cs__freeze
|
|
20
|
+
ERB_GADGETS = %W[object:ERB o:\bERB].cs__freeze
|
|
24
21
|
|
|
25
22
|
# Gadgets that map to ActionDispatch modules
|
|
26
23
|
ACTION_DISPATCH_GADGETS = %w[
|
|
@@ -29,11 +26,7 @@ module Contrast
|
|
|
29
26
|
].cs__freeze
|
|
30
27
|
|
|
31
28
|
# Gadgets that map to Arel Modules
|
|
32
|
-
AREL_GADGETS = %w[
|
|
33
|
-
string:Arel::Nodes::SqlLiteral
|
|
34
|
-
object:Arel::Nodes
|
|
35
|
-
o:\bArel::Nodes
|
|
36
|
-
].cs__freeze
|
|
29
|
+
AREL_GADGETS = %w[string:Arel::Nodes::SqlLiteral object:Arel::Nodes o:\bArel::Nodes].cs__freeze
|
|
37
30
|
|
|
38
31
|
# Used to indicate to TeamServer the gadget is an ERB module
|
|
39
32
|
ERB = 'ERB'
|
|
@@ -45,7 +38,7 @@ module Contrast
|
|
|
45
38
|
|
|
46
39
|
# Return the TeamServer understood id / name of this rule.
|
|
47
40
|
# @return [String] the TeamServer understood id / name of this rule.
|
|
48
|
-
def
|
|
41
|
+
def rule_name
|
|
49
42
|
NAME
|
|
50
43
|
end
|
|
51
44
|
|
|
@@ -124,8 +117,8 @@ module Contrast
|
|
|
124
117
|
sample = build_base_sample(context, input_analysis_result)
|
|
125
118
|
sample.untrusted_deserialization = Contrast::Api::Dtm::UntrustedDeserializationDetails.new
|
|
126
119
|
|
|
127
|
-
deserializer = kwargs[:GADGET_TYPE]
|
|
128
|
-
sample.untrusted_deserialization.deserializer =
|
|
120
|
+
deserializer = Contrast::Utils::StringUtils.protobuf_safe_string(kwargs[:GADGET_TYPE])
|
|
121
|
+
sample.untrusted_deserialization.deserializer = deserializer
|
|
129
122
|
|
|
130
123
|
command = !!kwargs[:COMMAND_SCOPE]
|
|
131
124
|
sample.untrusted_deserialization.command = command
|
|
@@ -148,7 +141,7 @@ module Contrast
|
|
|
148
141
|
# of the analysis done by this rule.
|
|
149
142
|
def build_evaluation gadget_string
|
|
150
143
|
ia_result = Contrast::Api::Settings::InputAnalysisResult.new
|
|
151
|
-
ia_result.rule_id =
|
|
144
|
+
ia_result.rule_id = rule_name
|
|
152
145
|
ia_result.input_type = :UNKNOWN
|
|
153
146
|
ia_result.key = INPUT_NAME
|
|
154
147
|
ia_result.value = Contrast::Utils::StringUtils.protobuf_safe_string(gadget_string)
|
|
@@ -12,7 +12,7 @@ module Contrast
|
|
|
12
12
|
NAME = 'method-tampering'
|
|
13
13
|
STANDARD_METHODS = %w[GET HEAD POST PUT DELETE CONNECT OPTIONS TRACE PATCH].cs__freeze
|
|
14
14
|
|
|
15
|
-
def
|
|
15
|
+
def rule_name
|
|
16
16
|
NAME
|
|
17
17
|
end
|
|
18
18
|
|
|
@@ -30,20 +30,9 @@ module Contrast
|
|
|
30
30
|
|
|
31
31
|
method = ia_results.first.value
|
|
32
32
|
result = if response_code.to_s.start_with?('4', '5')
|
|
33
|
-
build_attack_without_match(
|
|
34
|
-
context,
|
|
35
|
-
nil,
|
|
36
|
-
nil,
|
|
37
|
-
method: method,
|
|
38
|
-
response_code: response_code)
|
|
33
|
+
build_attack_without_match(context, nil, nil, method: method, response_code: response_code)
|
|
39
34
|
else
|
|
40
|
-
build_attack_with_match(
|
|
41
|
-
context,
|
|
42
|
-
nil,
|
|
43
|
-
nil,
|
|
44
|
-
nil,
|
|
45
|
-
method: method,
|
|
46
|
-
response_code: response_code)
|
|
35
|
+
build_attack_with_match(context, nil, nil, nil, method: method, response_code: response_code)
|
|
47
36
|
end
|
|
48
37
|
append_to_activity(context, result) if result
|
|
49
38
|
end
|
|
@@ -12,7 +12,7 @@ module Contrast
|
|
|
12
12
|
NAME = 'nosql-injection'
|
|
13
13
|
BLOCK_MESSAGE = 'NoSQLi rule triggered. Response blocked.'
|
|
14
14
|
|
|
15
|
-
def
|
|
15
|
+
def rule_name
|
|
16
16
|
NAME
|
|
17
17
|
end
|
|
18
18
|
|
|
@@ -32,7 +32,11 @@ module Contrast
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def build_attack_with_match context, input_analysis_result, result, query_string, **kwargs
|
|
35
|
-
|
|
35
|
+
if mode == Contrast::Api::Settings::ProtectionRule::Mode::NO_ACTION ||
|
|
36
|
+
mode == Contrast::Api::Settings::ProtectionRule::Mode::PERMIT
|
|
37
|
+
|
|
38
|
+
return result
|
|
39
|
+
end
|
|
36
40
|
|
|
37
41
|
attack_string = input_analysis_result.value
|
|
38
42
|
regexp = Regexp.new(Regexp.escape(attack_string), Regexp::IGNORECASE)
|
|
@@ -14,9 +14,7 @@ module Contrast
|
|
|
14
14
|
# Is the current & next character '//' or are the current and
|
|
15
15
|
# subsequent characters '<--' ?
|
|
16
16
|
def start_line_comment? char, index, query
|
|
17
|
-
if char == Contrast::Utils::ObjectShare::SLASH &&
|
|
18
|
-
query[index + 1] == Contrast::Utils::ObjectShare::SLASH
|
|
19
|
-
|
|
17
|
+
if char == Contrast::Utils::ObjectShare::SLASH && query[index + 1] == Contrast::Utils::ObjectShare::SLASH
|
|
20
18
|
return true
|
|
21
19
|
end
|
|
22
20
|
|
|
@@ -29,7 +29,7 @@ module Contrast
|
|
|
29
29
|
/windows/repair/
|
|
30
30
|
].cs__freeze
|
|
31
31
|
|
|
32
|
-
def
|
|
32
|
+
def rule_name
|
|
33
33
|
NAME
|
|
34
34
|
end
|
|
35
35
|
|
|
@@ -42,9 +42,8 @@ module Contrast
|
|
|
42
42
|
append_to_activity(context, result)
|
|
43
43
|
return unless blocked?
|
|
44
44
|
|
|
45
|
-
raise Contrast::SecurityException.new(
|
|
46
|
-
|
|
47
|
-
"Path Traversal rule triggered. Call to File.#{ method } blocked.")
|
|
45
|
+
raise Contrast::SecurityException.new(self,
|
|
46
|
+
"Path Traversal rule triggered. Call to File.#{ method } blocked.")
|
|
48
47
|
end
|
|
49
48
|
|
|
50
49
|
protected
|
|
@@ -128,7 +127,8 @@ module Contrast
|
|
|
128
127
|
# return 'NUL' in str(e) or 'null byte' in str(e) or (PY34 and 'embedded NUL character' == str(e))
|
|
129
128
|
# except Exception as e:
|
|
130
129
|
# return 'null byte' in str(e).lower()
|
|
131
|
-
# return return any([bypass_markers.lower().rstrip('/') in realpath for bypass_markers in
|
|
130
|
+
# return return any([bypass_markers.lower().rstrip('/') in realpath for bypass_markers in
|
|
131
|
+
# PathTraversalREPMixin.KNOWN_SECURITY_BYPASS_MARKERS])
|
|
132
132
|
false
|
|
133
133
|
end
|
|
134
134
|
end
|
|
@@ -15,7 +15,7 @@ module Contrast
|
|
|
15
15
|
BLOCK_MESSAGE = 'XXE rule triggered. Response blocked.'
|
|
16
16
|
EXTERNAL_ENTITY_PATTERN = /<!ENTITY\s+[a-zA-Z0-f]+\s+(?:SYSTEM|PUBLIC)\s+(.*?)>/.cs__freeze
|
|
17
17
|
|
|
18
|
-
def
|
|
18
|
+
def rule_name
|
|
19
19
|
NAME
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -59,12 +59,7 @@ module Contrast
|
|
|
59
59
|
return unless xxe_details
|
|
60
60
|
|
|
61
61
|
ia_result = build_evaluation(xxe_details.xml)
|
|
62
|
-
build_attack_with_match(
|
|
63
|
-
context,
|
|
64
|
-
ia_result,
|
|
65
|
-
nil,
|
|
66
|
-
nil,
|
|
67
|
-
details: xxe_details)
|
|
62
|
+
build_attack_with_match(context, ia_result, nil, nil, details: xxe_details)
|
|
68
63
|
end
|
|
69
64
|
|
|
70
65
|
# Given an XML determined to be unsafe, build out the details of the
|
|
@@ -118,7 +113,7 @@ module Contrast
|
|
|
118
113
|
# supplied by the attacker.
|
|
119
114
|
def build_evaluation xml
|
|
120
115
|
ia_result = Contrast::Api::Settings::InputAnalysisResult.new
|
|
121
|
-
ia_result.rule_id =
|
|
116
|
+
ia_result.rule_id = rule_name
|
|
122
117
|
ia_result.input_type = :UNKNOWN
|
|
123
118
|
ia_result.value = Contrast::Utils::StringUtils.protobuf_safe_string(xml)
|
|
124
119
|
ia_result
|
|
@@ -133,10 +128,8 @@ module Contrast
|
|
|
133
128
|
|
|
134
129
|
def build_wrapper entity_wrapper
|
|
135
130
|
wrapper = Contrast::Api::Dtm::XxeWrapper.new
|
|
136
|
-
wrapper.system_id = Contrast::Utils::StringUtils.protobuf_safe_string(
|
|
137
|
-
|
|
138
|
-
wrapper.public_id = Contrast::Utils::StringUtils.protobuf_safe_string(
|
|
139
|
-
entity_wrapper.public_id)
|
|
131
|
+
wrapper.system_id = Contrast::Utils::StringUtils.protobuf_safe_string(entity_wrapper.system_id)
|
|
132
|
+
wrapper.public_id = Contrast::Utils::StringUtils.protobuf_safe_string(entity_wrapper.public_id)
|
|
140
133
|
wrapper
|
|
141
134
|
end
|
|
142
135
|
end
|