contrast-agent 6.6.5 → 6.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/.gitignore +3 -0
- data/.gitmodules +0 -3
- data/ext/cs__scope/cs__scope.c +1 -1
- data/lib/contrast/agent/assess/contrast_event.rb +2 -24
- data/lib/contrast/agent/assess/events/source_event.rb +7 -61
- data/lib/contrast/agent/assess/finalizers/hash.rb +11 -0
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +0 -55
- data/lib/contrast/agent/assess/policy/policy_node.rb +3 -3
- data/lib/contrast/agent/assess/policy/policy_node_utils.rb +0 -1
- data/lib/contrast/agent/assess/policy/propagation_node.rb +4 -4
- data/lib/contrast/agent/assess/policy/source_method.rb +24 -1
- data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +7 -5
- data/lib/contrast/agent/assess/policy/trigger/xpath.rb +6 -1
- data/lib/contrast/agent/assess/policy/trigger_method.rb +36 -132
- data/lib/contrast/agent/assess/policy/trigger_node.rb +3 -3
- data/lib/contrast/agent/assess/property/evented.rb +2 -12
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +42 -84
- data/lib/contrast/agent/assess/rule/response/base_rule.rb +11 -27
- data/lib/contrast/agent/assess/rule/response/body_rule.rb +1 -3
- data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +77 -62
- data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +1 -1
- data/lib/contrast/agent/assess/rule/response/framework/rails_support.rb +6 -1
- data/lib/contrast/agent/assess/rule/response/header_rule.rb +5 -5
- data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +1 -1
- data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +1 -1
- data/lib/contrast/agent/assess/tracker.rb +1 -7
- data/lib/contrast/agent/excluder.rb +206 -0
- data/lib/contrast/agent/exclusion_matcher.rb +6 -0
- data/lib/contrast/agent/inventory/database_config.rb +6 -10
- data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +4 -0
- data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +1 -0
- data/lib/contrast/agent/protect/rule/base.rb +49 -5
- data/lib/contrast/agent/protect/rule/base_service.rb +1 -0
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +18 -105
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +129 -0
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +169 -0
- data/lib/contrast/agent/protect/rule/deserialization.rb +2 -1
- data/lib/contrast/agent/protect/rule/sqli/sqli_base_rule.rb +51 -0
- data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +67 -0
- data/lib/contrast/agent/protect/rule/sqli.rb +6 -31
- data/lib/contrast/agent/protect/rule/xxe.rb +2 -0
- data/lib/contrast/agent/protect/rule.rb +3 -1
- data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +6 -0
- data/lib/contrast/agent/reporting/details/sqli_dangerous_functions.rb +22 -0
- data/lib/contrast/agent/reporting/reporter.rb +1 -2
- data/lib/contrast/agent/reporting/reporting_events/agent_startup.rb +2 -2
- data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +1 -4
- data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +0 -23
- data/lib/contrast/agent/reporting/reporting_events/finding.rb +19 -49
- data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +12 -9
- data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +23 -21
- data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +5 -18
- data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +1 -0
- data/lib/contrast/{api/decorators/trace_taint_range_tags.rb → agent/reporting/reporting_events/finding_event_taint_range_tags.rb} +7 -6
- data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +2 -2
- data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +10 -14
- data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +11 -0
- data/lib/contrast/agent/reporting/reporting_events/route_coverage.rb +3 -1
- data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +11 -23
- data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +8 -26
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb +4 -7
- data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +3 -3
- data/lib/contrast/agent/request.rb +2 -2
- data/lib/contrast/agent/request_context.rb +8 -20
- data/lib/contrast/agent/request_context_extend.rb +15 -36
- data/lib/contrast/agent/request_handler.rb +0 -8
- data/lib/contrast/agent/response.rb +0 -18
- data/lib/contrast/agent/telemetry/events/event.rb +1 -1
- data/lib/contrast/agent/telemetry/events/metric_event.rb +1 -1
- data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +3 -3
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/communication/messaging_queue.rb +2 -3
- data/lib/contrast/api/communication/socket_client.rb +4 -4
- data/lib/contrast/api/communication/speedracer.rb +4 -8
- data/lib/contrast/api/decorators/agent_startup.rb +5 -6
- data/lib/contrast/api/decorators/application_settings.rb +2 -1
- data/lib/contrast/api/decorators/application_startup.rb +6 -6
- data/lib/contrast/api/decorators/message.rb +0 -4
- data/lib/contrast/api/decorators/rasp_rule_sample.rb +0 -6
- data/lib/contrast/api/decorators.rb +0 -6
- data/lib/contrast/api/dtm.pb.rb +0 -489
- data/lib/contrast/components/agent.rb +16 -12
- data/lib/contrast/components/api.rb +10 -10
- data/lib/contrast/components/app_context.rb +3 -3
- data/lib/contrast/components/app_context_extend.rb +1 -1
- data/lib/contrast/components/assess.rb +92 -38
- data/lib/contrast/components/assess_rules.rb +36 -0
- data/lib/contrast/components/config.rb +54 -12
- data/lib/contrast/components/contrast_service.rb +8 -8
- data/lib/contrast/components/heap_dump.rb +1 -1
- data/lib/contrast/components/protect.rb +5 -5
- data/lib/contrast/components/ruby_component.rb +81 -0
- data/lib/contrast/components/sampling.rb +1 -1
- data/lib/contrast/components/security_logger.rb +23 -0
- data/lib/contrast/components/service.rb +55 -0
- data/lib/contrast/components/settings.rb +12 -4
- data/lib/contrast/config/base_configuration.rb +1 -1
- data/lib/contrast/config/protect_rules_configuration.rb +17 -3
- data/lib/contrast/config/server_configuration.rb +1 -1
- data/lib/contrast/config.rb +0 -6
- data/lib/contrast/configuration.rb +81 -17
- data/lib/contrast/extension/assess/exec_trigger.rb +3 -1
- data/lib/contrast/extension/assess/marshal.rb +3 -2
- data/lib/contrast/extension/assess/string.rb +0 -1
- data/lib/contrast/extension/extension.rb +1 -1
- data/lib/contrast/framework/base_support.rb +0 -5
- data/lib/contrast/framework/grape/support.rb +1 -23
- data/lib/contrast/framework/manager.rb +0 -10
- data/lib/contrast/framework/rails/support.rb +5 -58
- data/lib/contrast/framework/sinatra/support.rb +2 -21
- data/lib/contrast/logger/cef_log.rb +21 -3
- data/lib/contrast/logger/log.rb +1 -11
- data/lib/contrast/tasks/config.rb +4 -2
- data/lib/contrast/utils/assess/event_limit_utils.rb +5 -8
- data/lib/contrast/utils/assess/trigger_method_utils.rb +10 -18
- data/lib/contrast/utils/findings.rb +6 -5
- data/lib/contrast/utils/hash_digest.rb +9 -24
- data/lib/contrast/utils/hash_digest_extend.rb +6 -6
- data/lib/contrast/utils/invalid_configuration_util.rb +21 -58
- data/lib/contrast/utils/log_utils.rb +32 -8
- data/lib/contrast/utils/net_http_base.rb +2 -2
- data/lib/contrast/utils/patching/policy/patch_utils.rb +3 -2
- data/lib/contrast/utils/stack_trace_utils.rb +0 -25
- data/lib/contrast/utils/string_utils.rb +9 -0
- data/lib/contrast/utils/telemetry_client.rb +13 -7
- data/lib/contrast.rb +5 -10
- metadata +22 -28
- data/lib/contrast/agent/reporting/reporting_events/trace_event_source.rb +0 -30
- data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -36
- data/lib/contrast/api/decorators/activity.rb +0 -33
- data/lib/contrast/api/decorators/architecture_component.rb +0 -36
- data/lib/contrast/api/decorators/finding.rb +0 -29
- data/lib/contrast/api/decorators/route_coverage.rb +0 -91
- data/lib/contrast/api/decorators/trace_event.rb +0 -120
- data/lib/contrast/api/decorators/trace_event_object.rb +0 -63
- data/lib/contrast/api/decorators/trace_event_signature.rb +0 -69
- data/lib/contrast/api/decorators/trace_taint_range.rb +0 -52
- data/lib/contrast/config/assess_configuration.rb +0 -93
- data/lib/contrast/config/assess_rules_configuration.rb +0 -32
- data/lib/contrast/config/root_configuration.rb +0 -90
- data/lib/contrast/config/ruby_configuration.rb +0 -81
- data/lib/contrast/config/service_configuration.rb +0 -49
- data/lib/contrast/utils/preflight_util.rb +0 -13
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'contrast/agent/reporting/details/sqli_dangerous_functions'
|
|
5
|
+
|
|
6
|
+
module Contrast
|
|
7
|
+
module Agent
|
|
8
|
+
module Protect
|
|
9
|
+
module Rule
|
|
10
|
+
# This class will include the check for SQL Injection Semantic Dangerous Functions
|
|
11
|
+
class SqliDangerousFunctions < Contrast::Agent::Protect::Rule::SqliBaseRule
|
|
12
|
+
NAME = 'sql-injection-semantic-dangerous-functions'
|
|
13
|
+
BLOCK_MESSAGE = 'SQLi Semantic Dangerous Functions rule triggered. Response blocked.'
|
|
14
|
+
|
|
15
|
+
SQL_DANGEROUS_FUNCTIONS = %w[unhex waitfor xp_cmdshell exec].cs__freeze
|
|
16
|
+
|
|
17
|
+
def rule_name
|
|
18
|
+
NAME
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def infilter context, query_string
|
|
22
|
+
return unless infilter?(context)
|
|
23
|
+
return unless violated?(query_string)
|
|
24
|
+
|
|
25
|
+
result = build_violation(context, query_string)
|
|
26
|
+
return unless result
|
|
27
|
+
|
|
28
|
+
append_to_activity(context, result)
|
|
29
|
+
|
|
30
|
+
cef_logging(result, :successful_attack)
|
|
31
|
+
raise(Contrast::SecurityException.new(self, BLOCK_MESSAGE)) if blocked?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
def violated? attack_string
|
|
37
|
+
SQL_DANGEROUS_FUNCTIONS.any? { |dang_func| attack_string.downcase.include?(dang_func) }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def build_violation context, potential_attack_string
|
|
41
|
+
result = build_attack_result(context)
|
|
42
|
+
update_successful_attack_response(context, nil, result, potential_attack_string)
|
|
43
|
+
append_sample(context, nil, result, potential_attack_string)
|
|
44
|
+
result
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Override if rule can make use of the candidate string or kwargs to
|
|
48
|
+
# build rasp rule sample.
|
|
49
|
+
def build_sample context, ia_result, candidate_string, **_kwargs
|
|
50
|
+
sample = build_base_sample(context, nil)
|
|
51
|
+
sample.details = Contrast::Agent::Reporting::Details::SqliDangerousFunctions.new
|
|
52
|
+
sample.details.query = candidate_string
|
|
53
|
+
|
|
54
|
+
if ia_result.nil?
|
|
55
|
+
ui = Contrast::Agent::Reporting::UserInput.new
|
|
56
|
+
ui.input_type = :UNKNOWN
|
|
57
|
+
ui.value = candidate_string
|
|
58
|
+
sample.user_input = ui
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
sample
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -5,13 +5,15 @@ require 'contrast/agent/protect/rule/base_service'
|
|
|
5
5
|
require 'contrast/agent/protect/policy/applies_sqli_rule'
|
|
6
6
|
require 'contrast/agent/protect/rule/sql_sample_builder'
|
|
7
7
|
require 'contrast/agent/reporting/input_analysis/input_type'
|
|
8
|
+
require 'contrast/agent/protect/rule/sqli/sqli_base_rule'
|
|
9
|
+
require 'contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions'
|
|
8
10
|
|
|
9
11
|
module Contrast
|
|
10
12
|
module Agent
|
|
11
13
|
module Protect
|
|
12
14
|
module Rule
|
|
13
15
|
# The Ruby implementation of the Protect SQL Injection rule.
|
|
14
|
-
class Sqli < Contrast::Agent::Protect::Rule::
|
|
16
|
+
class Sqli < Contrast::Agent::Protect::Rule::SqliBaseRule
|
|
15
17
|
# Generate a sample for the SQLI injection detection rule, allowing for reporting to and rendering
|
|
16
18
|
# by TeamServer
|
|
17
19
|
include SqlSampleBuilder::SqliSample
|
|
@@ -22,28 +24,9 @@ module Contrast
|
|
|
22
24
|
include Contrast::Agent::Reporting::InputType
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
APPLICABLE_USER_INPUTS = [
|
|
26
|
-
BODY, COOKIE_NAME, COOKIE_VALUE, HEADER,
|
|
27
|
-
PARAMETER_NAME, PARAMETER_VALUE, JSON_VALUE,
|
|
28
|
-
MULTIPART_VALUE, MULTIPART_FIELD_NAME,
|
|
29
|
-
XML_VALUE, DWR_VALUE
|
|
30
|
-
].cs__freeze
|
|
31
27
|
NAME = 'sql-injection'
|
|
32
|
-
BLOCK_MESSAGE = 'SQLi rule triggered. Response blocked.'
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
# @param attack_sample [Contrast::Api::Dtm::RaspRuleSample]
|
|
36
|
-
# @return [Hash] the details for this specific rule
|
|
37
|
-
def extract_details attack_sample
|
|
38
|
-
{
|
|
39
|
-
start: attack_sample.sqli.start_idx,
|
|
40
|
-
end: attack_sample.sqli.end_idx,
|
|
41
|
-
boundaryOverrunIndex: attack_sample.sqli.boundary_overrun_idx,
|
|
42
|
-
inputBoundaryIndex: attack_sample.sqli.input_boundary_idx,
|
|
43
|
-
query: attack_sample.sqli.query
|
|
44
|
-
}
|
|
45
|
-
end
|
|
46
|
-
end
|
|
29
|
+
SUB_RULES = [Contrast::Agent::Protect::Rule::SqliDangerousFunctions.new].cs__freeze
|
|
47
30
|
|
|
48
31
|
def rule_name
|
|
49
32
|
NAME
|
|
@@ -53,16 +36,8 @@ module Contrast
|
|
|
53
36
|
BLOCK_MESSAGE
|
|
54
37
|
end
|
|
55
38
|
|
|
56
|
-
def
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
result = find_attacker(context, query_string, database: database)
|
|
60
|
-
return unless result
|
|
61
|
-
|
|
62
|
-
append_to_activity(context, result)
|
|
63
|
-
|
|
64
|
-
cef_logging(result, :successful_attack, value: query_string)
|
|
65
|
-
raise(Contrast::SecurityException.new(self, BLOCK_MESSAGE)) if blocked?
|
|
39
|
+
def sub_rules
|
|
40
|
+
SUB_RULES
|
|
66
41
|
end
|
|
67
42
|
end
|
|
68
43
|
end
|
|
@@ -59,6 +59,8 @@ module Contrast
|
|
|
59
59
|
# @raise [Contrast::SecurityException] Security exception if an XXE
|
|
60
60
|
# attack is found and the rule is in block mode.
|
|
61
61
|
def infilter context, framework, xml
|
|
62
|
+
return if protect_excluded_by_url?(context)
|
|
63
|
+
|
|
62
64
|
result = find_attacker(context, xml, framework: framework)
|
|
63
65
|
return unless result
|
|
64
66
|
|
|
@@ -28,12 +28,14 @@ require 'contrast/agent/protect/rule/sqli/default_sql_scanner'
|
|
|
28
28
|
require 'contrast/agent/protect/rule/sqli/mysql_sql_scanner'
|
|
29
29
|
require 'contrast/agent/protect/rule/sqli/postgres_sql_scanner'
|
|
30
30
|
require 'contrast/agent/protect/rule/sqli/sqlite_sql_scanner'
|
|
31
|
+
require 'contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions'
|
|
31
32
|
|
|
32
33
|
# The classes required for Path Traversal
|
|
33
34
|
require 'contrast/agent/protect/rule/path_traversal'
|
|
34
35
|
|
|
35
|
-
# The classes required for Command Injection
|
|
36
|
+
# The classes required for Command Injection and sub-rules
|
|
36
37
|
require 'contrast/agent/protect/rule/cmd_injection'
|
|
38
|
+
require 'contrast/agent/protect/rule/cmdi/cmdi_backdoors'
|
|
37
39
|
|
|
38
40
|
# The classes required for XXE
|
|
39
41
|
require 'contrast/agent/protect/rule/xxe'
|
|
@@ -25,6 +25,10 @@ module Contrast
|
|
|
25
25
|
attr_accessor :virtual_patch
|
|
26
26
|
|
|
27
27
|
class << self
|
|
28
|
+
# @param context [Contrast::Agent::RequestContext]
|
|
29
|
+
# @param ia_result [Contrast::Api::Settings::InputAnalysisResult] the analysis of the input that was
|
|
30
|
+
# determined to be an attack
|
|
31
|
+
# @return [Contrast::Agent::Reporting::RaspRuleSample]
|
|
28
32
|
def build context, ia_result
|
|
29
33
|
sample = new
|
|
30
34
|
sample.time_stamp = context&.timer&.start_ms
|
|
@@ -35,6 +39,8 @@ module Contrast
|
|
|
35
39
|
sample
|
|
36
40
|
end
|
|
37
41
|
|
|
42
|
+
# @param ia_result [Contrast::Api::Settings::InputAnalysisResult] the analysis of the input that was
|
|
43
|
+
# determined to be an attack
|
|
38
44
|
def build_user_input_from_ia ia_result
|
|
39
45
|
# TODO: RUBY-99999 remove once only using Agent IA
|
|
40
46
|
result = if ia_result.cs__is_a?(Contrast::Api::Settings::InputAnalysisResult)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'contrast/agent/reporting/details/protect_rule_details'
|
|
5
|
+
|
|
6
|
+
module Contrast
|
|
7
|
+
module Agent
|
|
8
|
+
module Reporting
|
|
9
|
+
module Details
|
|
10
|
+
# SqliDangerousFunctions IA result details info.
|
|
11
|
+
class SqliDangerousFunctions < ProtectRuleDetails
|
|
12
|
+
# @return [String]
|
|
13
|
+
attr_accessor :query
|
|
14
|
+
|
|
15
|
+
def to_controlled_hash
|
|
16
|
+
{ query: query }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -125,8 +125,7 @@ module Contrast
|
|
|
125
125
|
#
|
|
126
126
|
# @return [Boolean]
|
|
127
127
|
def app_create_complete?
|
|
128
|
-
return true if Contrast::
|
|
129
|
-
return true if Contrast::Agent.messaging_queue&.speedracer&.status&.startup_messages_sent?
|
|
128
|
+
return true if Contrast::APP_CONTEXT.session_id
|
|
130
129
|
|
|
131
130
|
logger.debug('Service startup incomplete; Application may not be created; sleeping')
|
|
132
131
|
sleep(5)
|
|
@@ -23,8 +23,8 @@ module Contrast
|
|
|
23
23
|
|
|
24
24
|
def to_controlled_hash
|
|
25
25
|
{
|
|
26
|
-
environment: ::Contrast::CONFIG.
|
|
27
|
-
tags: ::Contrast::CONFIG.
|
|
26
|
+
environment: ::Contrast::CONFIG.server.environment,
|
|
27
|
+
tags: ::Contrast::CONFIG.server.tags,
|
|
28
28
|
version: Contrast::Agent::VERSION
|
|
29
29
|
}
|
|
30
30
|
end
|
|
@@ -19,14 +19,11 @@ module Contrast
|
|
|
19
19
|
attr_accessor :query_count
|
|
20
20
|
# @return [Array]
|
|
21
21
|
attr_accessor :routes
|
|
22
|
-
# @return [Array]
|
|
23
|
-
attr_accessor :dynamic_sources
|
|
24
22
|
# @return [Contrast::Agent::Response]
|
|
25
23
|
attr_accessor :response
|
|
26
24
|
|
|
27
25
|
def initialize
|
|
28
26
|
@routes = []
|
|
29
|
-
@dynamic_sources = {}
|
|
30
27
|
@query_count = 0
|
|
31
28
|
@event_method = :PUT
|
|
32
29
|
@event_type = :application_activity
|
|
@@ -77,7 +74,7 @@ module Contrast
|
|
|
77
74
|
results << case response_type
|
|
78
75
|
when BLOCKED, BLOCK_AT_PERIMETER
|
|
79
76
|
attacker.protection_rules[rule_id].blocked
|
|
80
|
-
when
|
|
77
|
+
when MONITORED
|
|
81
78
|
attacker.protection_rules[rule_id].exploited
|
|
82
79
|
when PROBED
|
|
83
80
|
attacker.protection_rules[rule_id].ineffective
|
|
@@ -29,18 +29,6 @@ module Contrast
|
|
|
29
29
|
AC_TYPE_DB = 'db'
|
|
30
30
|
VALID_TYPES = %w[db ldap ws].cs__freeze
|
|
31
31
|
|
|
32
|
-
# class << self
|
|
33
|
-
# # Convert a DTM for SpeedRacer to an Event for TeamServer.
|
|
34
|
-
# #
|
|
35
|
-
# # @param component_dtm [Contrast::Api::Dtm::ArchitectureComponent]
|
|
36
|
-
# # @return [Contrast::Agent::Reporting::ArchitectureComponent]
|
|
37
|
-
# def convert component_dtm
|
|
38
|
-
# report = new
|
|
39
|
-
# report.attach_data(component_dtm)
|
|
40
|
-
# report
|
|
41
|
-
# end
|
|
42
|
-
# end
|
|
43
|
-
|
|
44
32
|
class << self
|
|
45
33
|
def build_database
|
|
46
34
|
msg = new
|
|
@@ -49,17 +37,6 @@ module Contrast
|
|
|
49
37
|
end
|
|
50
38
|
end
|
|
51
39
|
|
|
52
|
-
# # Attach the data from the protobuf models to this reporter so that it can be sent to TeamServer directly.
|
|
53
|
-
# #
|
|
54
|
-
# # @param component_dtm [Contrast::Api::Dtm::ArchitectureComponent]
|
|
55
|
-
# def attach_data component_dtm
|
|
56
|
-
# @remote_host = component_dtm.remote_host
|
|
57
|
-
# @remote_port = component_dtm.remote_port
|
|
58
|
-
# @type = component_dtm.type
|
|
59
|
-
# @url = component_dtm.url
|
|
60
|
-
# @vendor = component_dtm.vendor
|
|
61
|
-
# end
|
|
62
|
-
|
|
63
40
|
# Convert the instance variables on the class, and other information, into the identifiers required for
|
|
64
41
|
# TeamServer to process the JSON form of this message.
|
|
65
42
|
#
|
|
@@ -29,14 +29,14 @@ module Contrast
|
|
|
29
29
|
# @return [Array<Contrast::Agent::Reporting::FindingEvent>] the events associated with this finding, if the
|
|
30
30
|
# finding is event (dataflow) based.
|
|
31
31
|
attr_reader :events
|
|
32
|
-
# @return [String] the evidence associated with this finding, if the finding is event based. deprecated in
|
|
33
|
-
# favor of properties
|
|
32
|
+
# # @return [String] the evidence associated with this finding, if the finding is event based. deprecated in
|
|
33
|
+
# # favor of properties
|
|
34
34
|
# attr_reader :evidence
|
|
35
35
|
# @return [Hash<String,String>] properties that prove the violation of the rule for this finding
|
|
36
36
|
attr_reader :properties
|
|
37
37
|
# @return [Contrast::Agent::Reporting::FindingRequest] the request associated with this finding, if the finding
|
|
38
38
|
# is request based
|
|
39
|
-
|
|
39
|
+
attr_accessor :request
|
|
40
40
|
# @return [String] the uniquely identifying hash of this finding
|
|
41
41
|
attr_accessor :hash_code
|
|
42
42
|
|
|
@@ -54,16 +54,6 @@ module Contrast
|
|
|
54
54
|
xxssprotection-header-disabled
|
|
55
55
|
].cs__freeze
|
|
56
56
|
|
|
57
|
-
class << self
|
|
58
|
-
# @param finding_dtm [Contrast::Api::Dtm::Finding]
|
|
59
|
-
# @return [Contrast::Agent::Reporting::Finding]
|
|
60
|
-
def convert finding_dtm
|
|
61
|
-
report = new(finding_dtm.rule_id)
|
|
62
|
-
report.attach_property_data(finding_dtm)
|
|
63
|
-
report
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
57
|
def initialize rule_id
|
|
68
58
|
@event_method = :PUT
|
|
69
59
|
@event_endpoint = "#{ Contrast::API.api_url }/api/ng/traces"
|
|
@@ -100,28 +90,10 @@ module Contrast
|
|
|
100
90
|
event_data = Contrast::Agent::Assess::Events::EventData.new(trigger_node, source, object, ret, args)
|
|
101
91
|
contrast_event = Contrast::Agent::Assess::ContrastEvent.new(event_data)
|
|
102
92
|
events << Contrast::Agent::Reporting::FindingEvent.convert(contrast_event)
|
|
103
|
-
attach_properties
|
|
104
93
|
return unless request
|
|
105
94
|
|
|
106
95
|
@request = Contrast::Agent::Reporting::FindingRequest.convert(request)
|
|
107
|
-
@routes <<
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
# Attach the data from a Contrast::Api::Dtm::Finding required for property based findings generated during
|
|
111
|
-
# response analysis.
|
|
112
|
-
#
|
|
113
|
-
# @param finding_dtm [Contrast::Api::Dtm::Finding]
|
|
114
|
-
def attach_property_data finding_dtm
|
|
115
|
-
@hash_code = finding_dtm.hash_code
|
|
116
|
-
@rule_id = finding_dtm.rule_id
|
|
117
|
-
finding_dtm.properties.each_pair do |key, value|
|
|
118
|
-
@properties[key] = value
|
|
119
|
-
end
|
|
120
|
-
finding_dtm.routes.each do |route|
|
|
121
|
-
@routes << Contrast::Agent::Reporting::RouteDiscovery.convert(route)
|
|
122
|
-
end
|
|
123
|
-
request = Contrast::Agent::REQUEST_TRACKER.current&.request
|
|
124
|
-
@request = Contrast::Agent::Reporting::FindingRequest.convert(request) if request
|
|
96
|
+
@routes << request.discovered_route if request.discovered_route
|
|
125
97
|
end
|
|
126
98
|
|
|
127
99
|
# Convert the instance variables on the class, and other information, into the identifiers required for
|
|
@@ -137,16 +109,9 @@ module Contrast
|
|
|
137
109
|
return
|
|
138
110
|
end
|
|
139
111
|
|
|
140
|
-
hsh =
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
ruleId: rule_id,
|
|
144
|
-
session_id: ::Contrast::ASSESS.session_id,
|
|
145
|
-
version: 4
|
|
146
|
-
}
|
|
147
|
-
hsh[:events] = events.map(&:to_controlled_hash) if event_based?
|
|
148
|
-
# hsh[:evidence] = evidence unless event_based? || property_based?
|
|
149
|
-
hsh[:properties] = properties if property_based?
|
|
112
|
+
hsh = base_hash
|
|
113
|
+
hsh[:events] = events.map(&:to_controlled_hash) if events.any?
|
|
114
|
+
hsh[:properties] = properties if properties.any?
|
|
150
115
|
hsh[:tags] = Contrast::ASSESS.tags if Contrast::ASSESS.tags
|
|
151
116
|
return hsh unless request_based?
|
|
152
117
|
|
|
@@ -155,6 +120,17 @@ module Contrast
|
|
|
155
120
|
hsh
|
|
156
121
|
end
|
|
157
122
|
|
|
123
|
+
# @return [Hash] the base of every finding, regardless of type
|
|
124
|
+
def base_hash
|
|
125
|
+
{
|
|
126
|
+
created: created,
|
|
127
|
+
hash: hash_code.to_s,
|
|
128
|
+
ruleId: rule_id,
|
|
129
|
+
session_id: ::Contrast::ASSESS.session_id,
|
|
130
|
+
version: 4
|
|
131
|
+
}
|
|
132
|
+
end
|
|
133
|
+
|
|
158
134
|
# @raise [ArgumentError]
|
|
159
135
|
def validate
|
|
160
136
|
raise(ArgumentError, "#{ self } did not have a proper rule. Unable to continue.") unless @rule_id
|
|
@@ -174,12 +150,6 @@ module Contrast
|
|
|
174
150
|
|
|
175
151
|
private
|
|
176
152
|
|
|
177
|
-
# Our events have properties on them. To report them to TeamServer, we need to pull them from our object up to
|
|
178
|
-
# the Contrast::Agent::Reporting::Finding level.
|
|
179
|
-
#
|
|
180
|
-
# TODO: RUBY-99999 put properties on events, not just on DTM
|
|
181
|
-
def attach_properties; end
|
|
182
|
-
|
|
183
153
|
def build_events events, event
|
|
184
154
|
return unless event
|
|
185
155
|
|
|
@@ -196,7 +166,7 @@ module Contrast
|
|
|
196
166
|
#
|
|
197
167
|
# @return [Boolean]
|
|
198
168
|
def event_based?
|
|
199
|
-
!property_based? && !config_based?
|
|
169
|
+
!property_based? && !config_based? && !hardcoded?
|
|
200
170
|
end
|
|
201
171
|
|
|
202
172
|
# Rules which are property based must have a property to be sent to TeamServer. Eventually, each rule may own
|
|
@@ -100,6 +100,10 @@ module Contrast
|
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
def initialize
|
|
104
|
+
@event_sources = []
|
|
105
|
+
end
|
|
106
|
+
|
|
103
107
|
# Parse the data from a Contrast::Agent::Assess::ContrastEvent to attach what is required for reporting to
|
|
104
108
|
# TeamServer to this Contrast::Agent::Reporting::FindingEvent
|
|
105
109
|
#
|
|
@@ -208,11 +212,9 @@ module Contrast
|
|
|
208
212
|
#
|
|
209
213
|
# @param event [Contrast::Agent::Assess::ContrastEvent]
|
|
210
214
|
def event_sources! event
|
|
211
|
-
@event_sources = []
|
|
212
215
|
return unless event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
|
|
213
216
|
|
|
214
|
-
|
|
215
|
-
event_sources << source if source
|
|
217
|
+
event_sources << event.event_source if event.event_source
|
|
216
218
|
end
|
|
217
219
|
|
|
218
220
|
# Convert the parent id's of the given ContrastEvent to the reportable form for this FindingEvent.
|
|
@@ -237,12 +239,13 @@ module Contrast
|
|
|
237
239
|
#
|
|
238
240
|
# @param event [Contrast::Agent::Assess::ContrastEvent]
|
|
239
241
|
def stack! event
|
|
240
|
-
@stack =
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
242
|
+
@stack = if event.stack_trace
|
|
243
|
+
event.stack_trace.compact.map! do |stack_event|
|
|
244
|
+
Contrast::Agent::Reporting::FindingEventStack.new(stack_event)
|
|
245
|
+
end
|
|
246
|
+
else
|
|
247
|
+
Contrast::Utils::ObjectShare::EMPTY_ARRAY
|
|
248
|
+
end
|
|
246
249
|
end
|
|
247
250
|
|
|
248
251
|
# Convert the taint ranges of the given ContrastEvent to the reportable form for this FindingEvent.
|
|
@@ -61,7 +61,7 @@ module Contrast
|
|
|
61
61
|
# 8 is STATIC in Java... we have to placate them for now it has been requested that flags be removed since it
|
|
62
62
|
# isn't used
|
|
63
63
|
@flags = 8 unless node.instance_method?
|
|
64
|
-
@method_name = node.method_name
|
|
64
|
+
@method_name = node.method_name.to_s
|
|
65
65
|
@return_type = type_name(event.ret)
|
|
66
66
|
# if there's a ret, then this method isn't nil. not 100% full proof since you can return nil, but this is the
|
|
67
67
|
# best we've got currently.
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'base64'
|
|
5
|
-
require 'contrast/agent/assess/contrast_event'
|
|
6
|
-
require 'contrast/agent/assess/events/source_event'
|
|
7
5
|
require 'contrast/components/logger'
|
|
8
6
|
|
|
9
7
|
module Contrast
|
|
@@ -21,25 +19,11 @@ module Contrast
|
|
|
21
19
|
# @return [String] the type of the source
|
|
22
20
|
attr_reader :type
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
report = new
|
|
31
|
-
report.attach_data(event)
|
|
32
|
-
report
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Parse the data from a Contrast::Agent::Assess::Events::SourceEvent to attach what is required for reporting
|
|
37
|
-
# to TeamServer to this Contrast::Agent::Reporting::FindingEventSource
|
|
38
|
-
#
|
|
39
|
-
# @param event [Contrast::Agent::Assess::Events::SourceEvent] the event to pull the source off of
|
|
40
|
-
def attach_data event
|
|
41
|
-
@name = event.source_name
|
|
42
|
-
@type = event.source_type
|
|
22
|
+
# @param type [String]
|
|
23
|
+
# @param name [String]
|
|
24
|
+
def initialize type, name
|
|
25
|
+
@type = type
|
|
26
|
+
@name = name
|
|
43
27
|
end
|
|
44
28
|
|
|
45
29
|
# Convert the instance variables on the class, and other information, into the identifiers required for
|
|
@@ -61,6 +45,24 @@ module Contrast
|
|
|
61
45
|
}
|
|
62
46
|
end
|
|
63
47
|
|
|
48
|
+
# Convert this EventSource into the format expected for route observation
|
|
49
|
+
#
|
|
50
|
+
# @return [Hash]
|
|
51
|
+
# @raise [ArgumentError]
|
|
52
|
+
def to_controlled_observation_hash
|
|
53
|
+
begin
|
|
54
|
+
validate
|
|
55
|
+
rescue ArgumentError => e
|
|
56
|
+
logger.error('FindingEventSource observation validation failed with: ', e)
|
|
57
|
+
return
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
{
|
|
61
|
+
name: name, # rubocop:disable Security/Module/Name
|
|
62
|
+
type: type
|
|
63
|
+
}
|
|
64
|
+
end
|
|
65
|
+
|
|
64
66
|
# @raise [ArgumentError]
|
|
65
67
|
def validate
|
|
66
68
|
raise(ArgumentError, "#{ self } did not have a proper type. Unable to continue.") unless type && !type.empty?
|
|
@@ -28,25 +28,12 @@ module Contrast
|
|
|
28
28
|
|
|
29
29
|
AGENT_CLASS_MARKER = '/lib/contrast/'
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# @return [Contrast::Agent::Reporting::FindingEventStack,nil]
|
|
34
|
-
def convert stack
|
|
35
|
-
return unless stack
|
|
36
|
-
return if stack.include?(AGENT_CLASS_MARKER)
|
|
37
|
-
|
|
38
|
-
report = new
|
|
39
|
-
report.attach_data(stack)
|
|
40
|
-
report
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Parse the data from a Contrast::Agent::Assess::Tag to attach what is required for reporting to TeamServer to
|
|
45
|
-
# this Contrast::Agent::Reporting::FindingEventTaintRange
|
|
31
|
+
# To play nice with the way that TeamServer is rendering these values, we only populate the file_name field with
|
|
32
|
+
# exactly what we want them to display.
|
|
46
33
|
#
|
|
47
|
-
# @param
|
|
48
|
-
def
|
|
49
|
-
@file =
|
|
34
|
+
# @param file_name [String] the caller location this stack frame represents.
|
|
35
|
+
def initialize file_name
|
|
36
|
+
@file = file_name
|
|
50
37
|
end
|
|
51
38
|
|
|
52
39
|
# Convert the instance variables on the class, and other information, into the identifiers required for
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
module Contrast
|
|
5
|
-
module
|
|
6
|
-
module
|
|
7
|
-
# A holder for the valid tags that can be sent to
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
module TraceTaintRangeTags
|
|
5
|
+
module Agent
|
|
6
|
+
module Reporting
|
|
7
|
+
# A holder for the valid tags that can be sent to TeamServer that we have to honor. Placed here so as not to
|
|
8
|
+
# clutter other code.
|
|
9
|
+
module FindingEventTaintRangeTags
|
|
11
10
|
# EventTagTypeDTM
|
|
11
|
+
# @return [Array<Symbol>]
|
|
12
12
|
VALID_TAGS = %w[
|
|
13
13
|
XML_ENCODED
|
|
14
14
|
XML_DECODED
|
|
@@ -97,6 +97,7 @@ module Contrast
|
|
|
97
97
|
DATABASE_WRITE
|
|
98
98
|
].cs__freeze
|
|
99
99
|
|
|
100
|
+
# @return [Array<Symbol>]
|
|
100
101
|
VALID_SOURCE_TAGS = %w[NO_NEWLINES UNTRUSTED CROSS_SITE LIMITED_CHARS].cs__freeze
|
|
101
102
|
end
|
|
102
103
|
end
|
|
@@ -11,7 +11,7 @@ module Contrast
|
|
|
11
11
|
include Contrast::Components::Logger::InstanceMethods
|
|
12
12
|
|
|
13
13
|
# @param [String] Sha256Sum of library as identified by the agent
|
|
14
|
-
|
|
14
|
+
attr_reader :id
|
|
15
15
|
# @param [Array<String>] List of file paths that have been loaded out of or executed by the library
|
|
16
16
|
attr_reader :names
|
|
17
17
|
|
|
@@ -24,7 +24,7 @@ module Contrast
|
|
|
24
24
|
attr_accessor :url
|
|
25
25
|
# @param [String] the HTTP Verb used to access the method in the route.
|
|
26
26
|
attr_accessor :verb
|
|
27
|
-
# @param [Array<Contrast::Agent::Reporting::
|
|
27
|
+
# @param [Array<Contrast::Agent::Reporting::FindingEventSource>] the sources of user input accessed during this
|
|
28
28
|
# request. Used for remediation determinations in TeamServer.
|
|
29
29
|
attr_reader :sources
|
|
30
30
|
|
|
@@ -56,7 +56,7 @@ module Contrast
|
|
|
56
56
|
|
|
57
57
|
{
|
|
58
58
|
session_id: ::Contrast::ASSESS.session_id,
|
|
59
|
-
sources: @sources.map(&:
|
|
59
|
+
sources: @sources.map(&:to_controlled_observation_hash),
|
|
60
60
|
signature: @signature,
|
|
61
61
|
verb: @verb,
|
|
62
62
|
url: @url
|