contrast-agent 4.3.2 → 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/.simplecov +1 -1
- data/Gemfile +1 -1
- data/LICENSE.txt +1 -1
- data/Rakefile +2 -3
- data/exe/contrast_service +1 -1
- data/ext/build_funchook.rb +4 -4
- data/ext/cs__assess_active_record_named/cs__active_record_named.c +1 -1
- data/ext/cs__assess_active_record_named/extconf.rb +1 -1
- data/ext/cs__assess_array/cs__assess_array.c +1 -1
- data/ext/cs__assess_array/extconf.rb +1 -1
- data/ext/cs__assess_basic_object/cs__assess_basic_object.c +1 -1
- data/ext/cs__assess_basic_object/extconf.rb +1 -1
- data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +1 -1
- data/ext/cs__assess_fiber_track/extconf.rb +1 -1
- data/ext/cs__assess_hash/cs__assess_hash.c +4 -2
- data/ext/cs__assess_hash/extconf.rb +1 -1
- data/ext/cs__assess_kernel/cs__assess_kernel.c +1 -1
- data/ext/cs__assess_kernel/extconf.rb +1 -1
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +1 -1
- data/ext/cs__assess_marshal_module/extconf.rb +1 -1
- data/ext/cs__assess_module/cs__assess_module.c +1 -1
- data/ext/cs__assess_module/extconf.rb +1 -1
- data/ext/cs__assess_regexp/cs__assess_regexp.c +1 -1
- data/ext/cs__assess_regexp/extconf.rb +1 -1
- data/ext/cs__assess_string/cs__assess_string.c +1 -1
- data/ext/cs__assess_string/extconf.rb +1 -1
- data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +1 -1
- data/ext/cs__assess_string_interpolation26/extconf.rb +1 -1
- data/ext/cs__assess_yield_track/cs__assess_yield_track.c +1 -1
- data/ext/cs__assess_yield_track/extconf.rb +1 -1
- data/ext/cs__common/cs__common.c +5 -5
- data/ext/cs__common/cs__common.h +4 -4
- data/ext/cs__common/extconf.rb +1 -1
- data/ext/cs__contrast_patch/cs__contrast_patch.c +22 -25
- data/ext/cs__contrast_patch/extconf.rb +1 -1
- data/ext/cs__protect_kernel/cs__protect_kernel.c +1 -1
- data/ext/cs__protect_kernel/extconf.rb +1 -1
- data/ext/extconf_common.rb +2 -6
- data/lib/contrast-agent.rb +1 -1
- data/lib/contrast.rb +20 -1
- data/lib/contrast/agent.rb +6 -4
- data/lib/contrast/agent/assess.rb +2 -11
- data/lib/contrast/agent/assess/contrast_event.rb +54 -71
- data/lib/contrast/agent/assess/contrast_object.rb +7 -4
- data/lib/contrast/agent/assess/events/event_factory.rb +3 -2
- data/lib/contrast/agent/assess/events/source_event.rb +7 -2
- data/lib/contrast/agent/assess/finalizers/freeze.rb +1 -1
- data/lib/contrast/agent/assess/finalizers/hash.rb +33 -34
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +34 -16
- data/lib/contrast/agent/assess/policy/patcher.rb +11 -18
- data/lib/contrast/agent/assess/policy/policy.rb +1 -1
- data/lib/contrast/agent/assess/policy/policy_node.rb +26 -34
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
- data/lib/contrast/agent/assess/policy/preshift.rb +4 -2
- data/lib/contrast/agent/assess/policy/propagation_method.rb +32 -30
- data/lib/contrast/agent/assess/policy/propagation_node.rb +20 -9
- data/lib/contrast/agent/assess/policy/propagator.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/append.rb +29 -14
- data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/center.rb +3 -2
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +22 -17
- data/lib/contrast/agent/assess/policy/propagator/insert.rb +4 -2
- data/lib/contrast/agent/assess/policy/propagator/keep.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +3 -2
- data/lib/contrast/agent/assess/policy/propagator/next.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/prepend.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/remove.rb +23 -19
- data/lib/contrast/agent/assess/policy/propagator/replace.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/reverse.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/select.rb +3 -13
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +24 -14
- data/lib/contrast/agent/assess/policy/propagator/split.rb +18 -15
- data/lib/contrast/agent/assess/policy/propagator/substitution.rb +32 -22
- data/lib/contrast/agent/assess/policy/propagator/trim.rb +64 -45
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +7 -4
- data/lib/contrast/agent/assess/policy/source_method.rb +92 -81
- data/lib/contrast/agent/assess/policy/source_node.rb +1 -1
- data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +8 -6
- data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +2 -4
- data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +7 -3
- data/lib/contrast/agent/assess/policy/trigger/xpath.rb +7 -8
- data/lib/contrast/agent/assess/policy/trigger_method.rb +109 -76
- data/lib/contrast/agent/assess/policy/trigger_node.rb +33 -11
- data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +60 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +3 -5
- data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +7 -5
- data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +4 -13
- data/lib/contrast/agent/assess/properties.rb +1 -3
- data/lib/contrast/agent/assess/property/evented.rb +9 -6
- data/lib/contrast/agent/assess/property/tagged.rb +38 -20
- data/lib/contrast/agent/assess/property/updated.rb +1 -1
- data/lib/contrast/agent/assess/rule/provider.rb +1 -1
- data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +12 -6
- data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +5 -2
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +4 -6
- data/lib/contrast/agent/assess/tag.rb +1 -1
- data/lib/contrast/agent/assess/tracker.rb +2 -2
- data/lib/contrast/agent/at_exit_hook.rb +1 -1
- data/lib/contrast/agent/class_reopener.rb +4 -2
- data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +1 -1
- data/lib/contrast/agent/deadzone/policy/policy.rb +7 -3
- data/lib/contrast/agent/disable_reaction.rb +2 -4
- data/lib/contrast/agent/exclusion_matcher.rb +6 -12
- data/lib/contrast/agent/inventory.rb +1 -2
- data/lib/contrast/agent/inventory/dependencies.rb +3 -1
- data/lib/contrast/agent/inventory/dependency_analysis.rb +1 -1
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +35 -23
- data/lib/contrast/agent/inventory/policy/datastores.rb +1 -1
- data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
- data/lib/contrast/agent/inventory/policy/trigger_node.rb +1 -1
- data/lib/contrast/agent/middleware.rb +111 -110
- data/lib/contrast/agent/module_data.rb +4 -4
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +1 -1
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +9 -4
- data/lib/contrast/agent/patching/policy/method_policy.rb +7 -3
- data/lib/contrast/agent/patching/policy/module_policy.rb +15 -8
- data/lib/contrast/agent/patching/policy/patch.rb +23 -29
- data/lib/contrast/agent/patching/policy/patch_status.rb +8 -9
- data/lib/contrast/agent/patching/policy/patcher.rb +72 -64
- data/lib/contrast/agent/patching/policy/policy.rb +14 -21
- data/lib/contrast/agent/patching/policy/policy_node.rb +15 -5
- data/lib/contrast/agent/patching/policy/trigger_node.rb +26 -10
- data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +2 -2
- data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +2 -2
- data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +2 -2
- data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +3 -4
- data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +2 -2
- data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +6 -10
- data/lib/contrast/agent/protect/policy/policy.rb +1 -1
- data/lib/contrast/agent/protect/policy/rule_applicator.rb +6 -6
- data/lib/contrast/agent/protect/policy/trigger_node.rb +1 -1
- data/lib/contrast/agent/protect/rule.rb +1 -1
- data/lib/contrast/agent/protect/rule/base.rb +19 -33
- data/lib/contrast/agent/protect/rule/base_service.rb +10 -6
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +15 -19
- data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -1
- data/lib/contrast/agent/protect/rule/deserialization.rb +7 -14
- data/lib/contrast/agent/protect/rule/http_method_tampering.rb +4 -15
- data/lib/contrast/agent/protect/rule/no_sqli.rb +7 -3
- data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +2 -4
- data/lib/contrast/agent/protect/rule/path_traversal.rb +6 -6
- data/lib/contrast/agent/protect/rule/sqli.rb +19 -13
- data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +1 -1
- data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +1 -1
- data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +2 -2
- data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +1 -1
- data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +2 -2
- data/lib/contrast/agent/protect/rule/xss.rb +2 -2
- data/lib/contrast/agent/protect/rule/xxe.rb +6 -13
- data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +2 -3
- data/lib/contrast/agent/railtie.rb +1 -1
- data/lib/contrast/agent/reaction_processor.rb +12 -11
- data/lib/contrast/agent/request.rb +25 -24
- data/lib/contrast/agent/request_context.rb +25 -23
- data/lib/contrast/agent/request_handler.rb +1 -1
- data/lib/contrast/agent/response.rb +1 -1
- data/lib/contrast/agent/rewriter.rb +6 -4
- data/lib/contrast/agent/rule_set.rb +3 -3
- data/lib/contrast/agent/scope.rb +1 -1
- data/lib/contrast/agent/service_heartbeat.rb +3 -4
- data/lib/contrast/agent/static_analysis.rb +1 -1
- data/lib/contrast/agent/thread.rb +2 -2
- data/lib/contrast/agent/thread_watcher.rb +21 -6
- data/lib/contrast/agent/tracepoint_hook.rb +2 -2
- data/lib/contrast/agent/version.rb +2 -2
- data/lib/contrast/agent/worker_thread.rb +1 -1
- data/lib/contrast/api.rb +1 -1
- data/lib/contrast/api/communication.rb +1 -1
- data/lib/contrast/api/communication/connection_status.rb +1 -1
- data/lib/contrast/api/communication/messaging_queue.rb +19 -22
- data/lib/contrast/api/communication/response_processor.rb +13 -8
- data/lib/contrast/api/communication/service_lifecycle.rb +5 -3
- data/lib/contrast/api/communication/socket.rb +1 -1
- data/lib/contrast/api/communication/socket_client.rb +30 -35
- data/lib/contrast/api/communication/speedracer.rb +6 -10
- data/lib/contrast/api/communication/tcp_socket.rb +1 -1
- data/lib/contrast/api/communication/unix_socket.rb +1 -1
- data/lib/contrast/api/decorators.rb +3 -1
- data/lib/contrast/api/decorators/address.rb +1 -1
- data/lib/contrast/api/decorators/agent_startup.rb +58 -0
- data/lib/contrast/api/decorators/application_settings.rb +1 -1
- data/lib/contrast/api/decorators/application_startup.rb +57 -0
- data/lib/contrast/api/decorators/application_update.rb +1 -1
- data/lib/contrast/api/decorators/http_request.rb +1 -1
- data/lib/contrast/api/decorators/input_analysis.rb +1 -1
- data/lib/contrast/api/decorators/instrumentation_mode.rb +37 -0
- data/lib/contrast/api/decorators/library.rb +9 -7
- data/lib/contrast/api/decorators/library_usage_update.rb +1 -1
- data/lib/contrast/api/decorators/message.rb +4 -4
- data/lib/contrast/api/decorators/rasp_rule_sample.rb +1 -1
- data/lib/contrast/api/decorators/route_coverage.rb +16 -6
- data/lib/contrast/api/decorators/server_features.rb +1 -1
- data/lib/contrast/api/decorators/trace_event.rb +46 -16
- data/lib/contrast/api/decorators/trace_event_object.rb +2 -4
- data/lib/contrast/api/decorators/trace_event_signature.rb +1 -1
- data/lib/contrast/api/decorators/trace_taint_range.rb +1 -1
- data/lib/contrast/api/decorators/trace_taint_range_tags.rb +2 -7
- data/lib/contrast/api/decorators/user_input.rb +1 -1
- data/lib/contrast/components/agent.rb +16 -15
- data/lib/contrast/components/app_context.rb +11 -29
- data/lib/contrast/components/assess.rb +6 -11
- data/lib/contrast/components/config.rb +3 -2
- data/lib/contrast/components/contrast_service.rb +8 -9
- data/lib/contrast/components/heap_dump.rb +1 -1
- data/lib/contrast/components/interface.rb +4 -3
- data/lib/contrast/components/inventory.rb +1 -1
- data/lib/contrast/components/logger.rb +1 -1
- data/lib/contrast/components/protect.rb +11 -14
- data/lib/contrast/components/sampling.rb +55 -7
- data/lib/contrast/components/scope.rb +2 -1
- data/lib/contrast/components/settings.rb +29 -99
- data/lib/contrast/config.rb +1 -1
- data/lib/contrast/config/agent_configuration.rb +1 -1
- data/lib/contrast/config/application_configuration.rb +1 -1
- data/lib/contrast/config/assess_configuration.rb +1 -1
- data/lib/contrast/config/assess_rules_configuration.rb +2 -4
- data/lib/contrast/config/base_configuration.rb +5 -6
- data/lib/contrast/config/default_value.rb +1 -1
- data/lib/contrast/config/exception_configuration.rb +2 -6
- data/lib/contrast/config/heap_dump_configuration.rb +13 -7
- data/lib/contrast/config/inventory_configuration.rb +1 -1
- data/lib/contrast/config/logger_configuration.rb +2 -6
- data/lib/contrast/config/protect_configuration.rb +1 -1
- data/lib/contrast/config/protect_rule_configuration.rb +23 -1
- data/lib/contrast/config/protect_rules_configuration.rb +1 -1
- data/lib/contrast/config/root_configuration.rb +1 -1
- data/lib/contrast/config/ruby_configuration.rb +1 -1
- data/lib/contrast/config/sampling_configuration.rb +1 -1
- data/lib/contrast/config/server_configuration.rb +1 -1
- data/lib/contrast/config/service_configuration.rb +1 -1
- data/lib/contrast/configuration.rb +4 -15
- data/lib/contrast/delegators/input_analysis.rb +12 -0
- data/lib/contrast/extension/assess.rb +1 -1
- data/lib/contrast/extension/assess/array.rb +2 -7
- data/lib/contrast/extension/assess/erb.rb +2 -8
- data/lib/contrast/extension/assess/eval_trigger.rb +3 -11
- data/lib/contrast/extension/assess/exec_trigger.rb +4 -14
- data/lib/contrast/extension/assess/fiber.rb +3 -13
- data/lib/contrast/extension/assess/hash.rb +1 -1
- data/lib/contrast/extension/assess/kernel.rb +3 -10
- data/lib/contrast/extension/assess/marshal.rb +3 -11
- data/lib/contrast/extension/assess/regexp.rb +2 -7
- data/lib/contrast/extension/assess/string.rb +4 -2
- data/lib/contrast/extension/delegator.rb +1 -1
- data/lib/contrast/extension/inventory.rb +1 -1
- data/lib/contrast/extension/kernel.rb +5 -3
- data/lib/contrast/extension/module.rb +1 -1
- data/lib/contrast/extension/protect.rb +1 -1
- data/lib/contrast/extension/protect/kernel.rb +1 -1
- data/lib/contrast/extension/protect/psych.rb +1 -1
- data/lib/contrast/extension/thread.rb +1 -1
- data/lib/contrast/framework/base_support.rb +1 -1
- data/lib/contrast/framework/manager.rb +14 -17
- data/lib/contrast/framework/platform_version.rb +1 -1
- data/lib/contrast/framework/rack/patch/session_cookie.rb +6 -19
- data/lib/contrast/framework/rack/patch/support.rb +7 -5
- data/lib/contrast/framework/rack/support.rb +1 -1
- data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +1 -1
- data/lib/contrast/framework/rails/patch/assess_configuration.rb +8 -3
- data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +4 -4
- data/lib/contrast/framework/rails/patch/support.rb +5 -3
- data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +5 -2
- data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +3 -1
- data/lib/contrast/framework/rails/rewrite/active_record_named.rb +3 -1
- data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +3 -1
- data/lib/contrast/framework/rails/support.rb +45 -46
- data/lib/contrast/framework/sinatra/support.rb +103 -42
- data/lib/contrast/funchook/funchook.rb +2 -6
- data/lib/contrast/logger/application.rb +13 -10
- data/lib/contrast/logger/format.rb +3 -6
- data/lib/contrast/logger/log.rb +36 -19
- data/lib/contrast/logger/request.rb +2 -3
- data/lib/contrast/logger/time.rb +1 -1
- data/lib/contrast/security_exception.rb +2 -2
- data/lib/contrast/tasks/config.rb +1 -1
- data/lib/contrast/tasks/service.rb +6 -2
- data/lib/contrast/utils/assess/sampling_util.rb +1 -1
- data/lib/contrast/utils/assess/tracking_util.rb +2 -3
- data/lib/contrast/utils/class_util.rb +18 -12
- data/lib/contrast/utils/duck_utils.rb +1 -1
- data/lib/contrast/utils/env_configuration_item.rb +1 -1
- data/lib/contrast/utils/hash_digest.rb +16 -24
- data/lib/contrast/utils/heap_dump_util.rb +104 -88
- data/lib/contrast/utils/invalid_configuration_util.rb +22 -13
- data/lib/contrast/utils/inventory_util.rb +1 -1
- data/lib/contrast/utils/io_util.rb +2 -2
- data/lib/contrast/utils/job_servers_running.rb +10 -5
- data/lib/contrast/utils/object_share.rb +1 -1
- data/lib/contrast/utils/os.rb +3 -2
- data/lib/contrast/utils/preflight_util.rb +1 -1
- data/lib/contrast/utils/resource_loader.rb +1 -1
- data/lib/contrast/utils/ruby_ast_rewriter.rb +3 -2
- data/lib/contrast/utils/sha256_builder.rb +1 -1
- data/lib/contrast/utils/stack_trace_utils.rb +1 -1
- data/lib/contrast/utils/string_utils.rb +1 -1
- data/lib/contrast/utils/tag_util.rb +1 -1
- data/lib/contrast/utils/thread_tracker.rb +1 -1
- data/lib/contrast/utils/timer.rb +1 -1
- data/resources/assess/policy.json +8 -11
- data/resources/deadzone/policy.json +7 -17
- data/ruby-agent.gemspec +66 -27
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- data/sonar-project.properties +9 -0
- metadata +154 -156
- data/lib/contrast/agent/assess/rule.rb +0 -18
- data/lib/contrast/agent/assess/rule/base.rb +0 -52
- data/lib/contrast/agent/assess/rule/redos.rb +0 -67
- data/lib/contrast/agent/inventory/gemfile_digest_cache.rb +0 -38
- data/lib/contrast/common_agent_configuration.rb +0 -87
- data/lib/contrast/framework/sinatra/patch/base.rb +0 -83
- data/lib/contrast/framework/sinatra/patch/support.rb +0 -27
- data/lib/contrast/utils/prevent_serialization.rb +0 -52
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'contrast/components/interface'
|
|
@@ -95,10 +95,8 @@ module Contrast
|
|
|
95
95
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties!(ret))
|
|
96
96
|
|
|
97
97
|
incoming_properties = Contrast::Agent::Assess::Tracker.properties(incoming)
|
|
98
|
-
|
|
99
|
-
parent_events << parent_event if parent_event
|
|
98
|
+
parent_events << incoming_properties&.event if incoming_properties&.event
|
|
100
99
|
|
|
101
|
-
pattern = preshift.args[0]
|
|
102
100
|
source = preshift.object
|
|
103
101
|
|
|
104
102
|
# We can't efficiently find the places that things were
|
|
@@ -111,6 +109,34 @@ module Contrast
|
|
|
111
109
|
|
|
112
110
|
# if it's just a straight insert, that we can do
|
|
113
111
|
# Copy the tags from us to the return
|
|
112
|
+
ranges = find_string_sub_insert(properties, preshift, incoming, ret, global)
|
|
113
|
+
|
|
114
|
+
properties.delete_tags_at_ranges(ranges)
|
|
115
|
+
properties.shift_tags(ranges)
|
|
116
|
+
return unless incoming_tracked
|
|
117
|
+
return unless incoming_properties
|
|
118
|
+
|
|
119
|
+
tags = incoming_properties.tag_keys
|
|
120
|
+
ranges.each do |range|
|
|
121
|
+
tags.each do |tag|
|
|
122
|
+
properties.add_tag(tag, range)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Find the points at which the new String was placed into the original
|
|
128
|
+
#
|
|
129
|
+
# @param properties [Contrast::Agent::Assess::Properties] the Properties of the ret
|
|
130
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] the capture of the state of the code just prior to
|
|
131
|
+
# the invocation of the patched method
|
|
132
|
+
# @param incoming [String] the new String going into the substitution
|
|
133
|
+
# @param ret [String] the result of the substitution
|
|
134
|
+
# @param global [Boolean] if this was a global or single substitution
|
|
135
|
+
# @return [Array<Range>] the Ranges where substitution occurred
|
|
136
|
+
def find_string_sub_insert properties, preshift, incoming, ret, global
|
|
137
|
+
pattern = preshift.args[0]
|
|
138
|
+
source = preshift.object
|
|
139
|
+
|
|
114
140
|
properties.copy_from(source, ret)
|
|
115
141
|
# Figure out where inserts occurred
|
|
116
142
|
last_idx = 0
|
|
@@ -126,17 +152,7 @@ module Contrast
|
|
|
126
152
|
ranges << (start_index...end_index)
|
|
127
153
|
break unless global
|
|
128
154
|
end
|
|
129
|
-
|
|
130
|
-
properties.shift_tags(ranges)
|
|
131
|
-
return unless incoming_tracked
|
|
132
|
-
return unless incoming_properties
|
|
133
|
-
|
|
134
|
-
tags = incoming_properties.tag_keys
|
|
135
|
-
ranges.each do |range|
|
|
136
|
-
tags.each do |tag|
|
|
137
|
-
properties.add_tag(tag, range)
|
|
138
|
-
end
|
|
139
|
-
end
|
|
155
|
+
ranges
|
|
140
156
|
end
|
|
141
157
|
|
|
142
158
|
def block_sub self_tracked, source, ret
|
|
@@ -170,13 +186,7 @@ module Contrast
|
|
|
170
186
|
|
|
171
187
|
properties = Contrast::Agent::Assess::Tracker.properties(ret)
|
|
172
188
|
args = preshift.args
|
|
173
|
-
properties.build_event(
|
|
174
|
-
patcher,
|
|
175
|
-
ret,
|
|
176
|
-
preshift.object,
|
|
177
|
-
ret,
|
|
178
|
-
args,
|
|
179
|
-
2)
|
|
189
|
+
properties.build_event(patcher, ret, preshift.object, ret, args, 2)
|
|
180
190
|
properties.event.instance_variable_set(:@_parent_events, parent_events)
|
|
181
191
|
end
|
|
182
192
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
module Contrast
|
|
@@ -8,50 +8,24 @@ module Contrast
|
|
|
8
8
|
module Propagator
|
|
9
9
|
# This class is specifically for String#tr(_s) propagation
|
|
10
10
|
#
|
|
11
|
-
# Disclaimer: there may be a better way, but we're
|
|
12
|
-
#
|
|
13
|
-
# a 'get it right' state soon.
|
|
11
|
+
# Disclaimer: there may be a better way, but we're in a 'get it work' state. hopefully, we'll be in a 'get it
|
|
12
|
+
# right' state soon.
|
|
14
13
|
module Trim
|
|
15
14
|
class << self
|
|
16
|
-
|
|
15
|
+
# @param policy_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
|
16
|
+
# propagation event.
|
|
17
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
|
18
|
+
# the invocation of the patched method.
|
|
19
|
+
# @param ret [nil, String] the target to which to propagate.
|
|
20
|
+
# @return [nil, String] ret
|
|
21
|
+
def tr_tagger policy_node, preshift, ret, _block
|
|
17
22
|
return ret unless ret && !ret.empty?
|
|
18
23
|
return ret unless (properties = Contrast::Agent::Assess::Tracker.properties!(ret))
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
properties.copy_from(source, ret)
|
|
23
|
-
replace_string = args[1]
|
|
24
|
-
source_chars = source.chars
|
|
25
|
-
# if the replace string is empty, then there's a bunch of deletes. this
|
|
26
|
-
# functions the same as the Removal propagation.
|
|
27
|
-
if replace_string == Contrast::Utils::ObjectShare::EMPTY_STRING
|
|
28
|
-
Contrast::Agent::Assess::Policy::Propagator::Remove.handle_removal(source_chars, ret)
|
|
29
|
-
else
|
|
30
|
-
remove_ranges = []
|
|
31
|
-
ret_chars = ret.chars
|
|
32
|
-
start = nil
|
|
33
|
-
source_chars.each_with_index do |char, idx|
|
|
34
|
-
if ret_chars[idx] == char
|
|
35
|
-
next unless start
|
|
25
|
+
properties.copy_from(preshift.object, ret)
|
|
26
|
+
handle_tr(policy_node, preshift, ret, properties)
|
|
36
27
|
|
|
37
|
-
|
|
38
|
-
start = nil
|
|
39
|
-
else
|
|
40
|
-
start ||= idx
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
# account for the last char being different
|
|
44
|
-
remove_ranges << (start...source_chars.length) if start
|
|
45
|
-
properties.delete_tags_at_ranges(remove_ranges, false)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
properties.build_event(
|
|
49
|
-
patcher,
|
|
50
|
-
ret,
|
|
51
|
-
source,
|
|
52
|
-
ret,
|
|
53
|
-
args,
|
|
54
|
-
1)
|
|
28
|
+
properties.build_event(policy_node, ret, preshift.object, ret, preshift.args, 1)
|
|
55
29
|
ret
|
|
56
30
|
end
|
|
57
31
|
|
|
@@ -62,14 +36,59 @@ module Contrast
|
|
|
62
36
|
source = preshift.object
|
|
63
37
|
args = preshift.args
|
|
64
38
|
properties.splat_from(source, ret)
|
|
65
|
-
properties.build_event(
|
|
66
|
-
patcher,
|
|
67
|
-
ret,
|
|
68
|
-
source,
|
|
69
|
-
ret,
|
|
70
|
-
args)
|
|
39
|
+
properties.build_event(patcher, ret, source, ret, args)
|
|
71
40
|
ret
|
|
72
41
|
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# @param policy_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
|
46
|
+
# propagation event.
|
|
47
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
|
48
|
+
# the invocation of the patched method.
|
|
49
|
+
# @param ret [String] the target to which to propagate.
|
|
50
|
+
# @param properties [Contrast::Agent::Assess::Properties] the properties of the ret
|
|
51
|
+
def handle_tr policy_node, preshift, ret, properties
|
|
52
|
+
source = preshift.object
|
|
53
|
+
replace_string = preshift.args[1]
|
|
54
|
+
|
|
55
|
+
# if the replace string is empty, then there's a bunch of deletes. this functions the same as the
|
|
56
|
+
# Removal propagation.
|
|
57
|
+
if replace_string == Contrast::Utils::ObjectShare::EMPTY_STRING
|
|
58
|
+
Contrast::Agent::Assess::Policy::Propagator::Remove.handle_removal(policy_node, source, ret)
|
|
59
|
+
return
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Otherwise, we need to target each insertion point. Based on the spec for #tr & #tr_s, the find is
|
|
63
|
+
# treated as a regexp range, excepting the `\` character, which we'll need to escape. This converts to
|
|
64
|
+
# that form, wrapping the input in `[]`.
|
|
65
|
+
find_string = preshift.args[0]
|
|
66
|
+
find_string += '\\' if find_string.end_with?('\\')
|
|
67
|
+
find_regexp = Regexp.new("[#{ find_string }]")
|
|
68
|
+
|
|
69
|
+
# Find the first instance to be replaced. If there isn't one, than nothing changed here.
|
|
70
|
+
idx = source.index(find_regexp)
|
|
71
|
+
return unless idx
|
|
72
|
+
|
|
73
|
+
# Iterate over each change and record where it happened. B/c this is a one to one replace, the index of
|
|
74
|
+
# the replacement is always one; however, there may be adjacent replacements which become a single
|
|
75
|
+
# range.
|
|
76
|
+
start = idx
|
|
77
|
+
stop = idx + 1
|
|
78
|
+
remove_ranges = []
|
|
79
|
+
while (idx = source.index(find_regexp, idx + 1))
|
|
80
|
+
# If the previous range ends at this index, we can expand that range to include this index.
|
|
81
|
+
# Otherwise, we need to record the held range and start a new one.
|
|
82
|
+
if stop != idx
|
|
83
|
+
remove_ranges << (start...stop)
|
|
84
|
+
start = idx
|
|
85
|
+
end
|
|
86
|
+
stop = idx + 1
|
|
87
|
+
end
|
|
88
|
+
# Be sure to capture the last range in the holder.
|
|
89
|
+
remove_ranges << (start...stop)
|
|
90
|
+
properties.delete_tags_at_ranges(remove_ranges, false)
|
|
91
|
+
end
|
|
73
92
|
end
|
|
74
93
|
end
|
|
75
94
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
+
return unless RUBY_VERSION < '2.6.0' # TODO: RUBY-714 remove guard w/ EOL of 2.5
|
|
5
|
+
|
|
4
6
|
require 'contrast/agent/patching/policy/patch_status'
|
|
5
7
|
require 'contrast/agent/module_data'
|
|
6
8
|
require 'contrast/agent/rewriter'
|
|
@@ -41,7 +43,9 @@ module Contrast
|
|
|
41
43
|
module_name = mod.cs__name
|
|
42
44
|
return unless module_name
|
|
43
45
|
|
|
44
|
-
if module_name.start_with?(Contrast::Utils::ObjectShare::CONTRAST_MODULE_START,
|
|
46
|
+
if module_name.start_with?(Contrast::Utils::ObjectShare::CONTRAST_MODULE_START,
|
|
47
|
+
Contrast::Utils::ObjectShare::ANONYMOUS_CLASS_MARKER)
|
|
48
|
+
|
|
45
49
|
status.no_rewrite!
|
|
46
50
|
return
|
|
47
51
|
|
|
@@ -64,8 +68,7 @@ module Contrast
|
|
|
64
68
|
# To get around this, we have those methods tell us the class
|
|
65
69
|
# isn't ready
|
|
66
70
|
def mid_defining? mod
|
|
67
|
-
mod.instance_variable_defined?(:@cs__defining_class) &&
|
|
68
|
-
mod.instance_variable_get(:@cs__defining_class)
|
|
71
|
+
mod.instance_variable_defined?(:@cs__defining_class) && mod.instance_variable_get(:@cs__defining_class)
|
|
69
72
|
end
|
|
70
73
|
|
|
71
74
|
def agent_should_rewrite?
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c)
|
|
1
|
+
# Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'set'
|
|
@@ -11,10 +11,9 @@ module Contrast
|
|
|
11
11
|
module Agent
|
|
12
12
|
module Assess
|
|
13
13
|
module Policy
|
|
14
|
-
# This class controls the actions we take on Sources, as determined by
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# dataflows used in Assess vulnerability detection.
|
|
14
|
+
# This class controls the actions we take on Sources, as determined by our Assess policy. It indicates what
|
|
15
|
+
# actions we should take in order to mark data as User Input and treat it as untrusted, starting the dataflows
|
|
16
|
+
# used in Assess vulnerability detection.
|
|
18
17
|
module SourceMethod
|
|
19
18
|
include Contrast::Components::Interface
|
|
20
19
|
access_component :analysis, :logging
|
|
@@ -27,22 +26,17 @@ module Contrast
|
|
|
27
26
|
COOKIE_KEY_TYPE = 'COOKIE_KEY'
|
|
28
27
|
|
|
29
28
|
class << self
|
|
30
|
-
# This is called from within our woven proc. It will be called as if it
|
|
31
|
-
#
|
|
29
|
+
# This is called from within our woven proc. It will be called as if it were inline in the Rack
|
|
30
|
+
# application.
|
|
32
31
|
#
|
|
33
|
-
# @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy]
|
|
34
|
-
#
|
|
32
|
+
# @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy] the policy that applies to the
|
|
33
|
+
# method being called
|
|
35
34
|
# @param object [Object] the Object on which the method was invoked
|
|
36
35
|
# @param ret [Object] the Return of the invoked method
|
|
37
|
-
# @param args [Array<Object>] the Arguments with which the method
|
|
38
|
-
#
|
|
39
|
-
# @return [Object, nil] the tracked Return or nil if no changes
|
|
40
|
-
# were made
|
|
36
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
37
|
+
# @return [Object, nil] the tracked Return or nil if no changes were made
|
|
41
38
|
def source_patchers method_policy, object, ret, args
|
|
42
|
-
return
|
|
43
|
-
|
|
44
|
-
current_context = Contrast::Agent::REQUEST_TRACKER.current
|
|
45
|
-
return unless current_context&.analyze_request? && ASSESS.enabled?
|
|
39
|
+
return unless analyze?(method_policy, object, ret, args)
|
|
46
40
|
|
|
47
41
|
source_node = method_policy.source_node
|
|
48
42
|
target = determine_target(source_node, object, ret, args)
|
|
@@ -62,29 +56,26 @@ module Contrast
|
|
|
62
56
|
# double check that we were able to finalize the replaced return
|
|
63
57
|
return unless Contrast::Agent::Assess::Tracker.trackable?(target)
|
|
64
58
|
end
|
|
65
|
-
apply_source(
|
|
59
|
+
apply_source(Contrast::Agent::REQUEST_TRACKER.current, source_node, target, object, ret,
|
|
60
|
+
source_node.type, nil, *args)
|
|
66
61
|
restore_frozen_state ? ret : nil
|
|
67
62
|
end
|
|
68
63
|
|
|
69
64
|
private
|
|
70
65
|
|
|
71
|
-
# This is our method that actually taints the object our
|
|
72
|
-
# source_node targets.
|
|
66
|
+
# This is our method that actually taints the object our source_node targets.
|
|
73
67
|
#
|
|
74
|
-
# @param context [Contrast::Utils::ThreadTracker] the current request
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
# the node to direct applying this source event
|
|
68
|
+
# @param context [Contrast::Utils::ThreadTracker] the current request context
|
|
69
|
+
# @param source_node [Contrast::Agent::Assess::Policy::SourceNode] the node to direct applying this source
|
|
70
|
+
# event
|
|
78
71
|
# @param target [Object] the target of the Source Event
|
|
79
72
|
# @param object [Object] the Object on which the method was invoked
|
|
80
73
|
# @param ret [Object] the Return of the invoked method
|
|
81
|
-
# @param source_type [String] the type of this source, from the
|
|
82
|
-
#
|
|
83
|
-
# @param source_name [String, nil] the name of this source, i.e.
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
# @param args [Array<Object>] the Arguments with which the method
|
|
87
|
-
# was invoked
|
|
74
|
+
# @param source_type [String] the type of this source, from the source_node, or a KEY_TYPE if invoked for a
|
|
75
|
+
# map
|
|
76
|
+
# @param source_name [String, nil] the name of this source, i.e. the key used to accessed if from a map or
|
|
77
|
+
# nil if a type like BODY
|
|
78
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
88
79
|
def apply_source context, source_node, target, object, ret, source_type, source_name = nil, *args
|
|
89
80
|
return unless context && source_node && target
|
|
90
81
|
|
|
@@ -95,37 +86,34 @@ module Contrast
|
|
|
95
86
|
apply_tags(source_node, target, object, ret, source_type, source_name, *args)
|
|
96
87
|
elsif Contrast::Utils::DuckUtils.iterable_hash?(target)
|
|
97
88
|
apply_hash_tags(context, source_node, target, object, ret, source_type, *args)
|
|
98
|
-
# While we don't taint arrays themselves, we may taint the things
|
|
99
|
-
#
|
|
100
|
-
# try again
|
|
89
|
+
# While we don't taint arrays themselves, we may taint the things they hold. Let's pass their keys and
|
|
90
|
+
# values back to ourselves and try again
|
|
101
91
|
elsif Contrast::Utils::DuckUtils.iterable_enumerable?(target)
|
|
102
|
-
target.each
|
|
92
|
+
target.each do |value|
|
|
93
|
+
apply_source(context, source_node, value, object, ret, source_type, source_name, *args)
|
|
94
|
+
end
|
|
103
95
|
end
|
|
104
96
|
rescue StandardError => e
|
|
105
97
|
logger.warn('Unable to apply source', e, node_id: source_node.id)
|
|
106
98
|
end
|
|
107
99
|
|
|
108
|
-
# While we don't taint hashes themselves, we may taint the things
|
|
109
|
-
#
|
|
110
|
-
# try again
|
|
100
|
+
# While we don't taint hashes themselves, we may taint the things they hold. Let's pass their keys and
|
|
101
|
+
# values back to ourselves and try again
|
|
111
102
|
#
|
|
112
|
-
# @param context [Contrast::Utils::ThreadTracker] the current request
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
# the node to direct applying this source event
|
|
103
|
+
# @param context [Contrast::Utils::ThreadTracker] the current request context
|
|
104
|
+
# @param source_node [Contrast::Agent::Assess::Policy::SourceNode] the node to direct applying this source
|
|
105
|
+
# event
|
|
116
106
|
# @param target [Object] the target of the Source Event
|
|
117
107
|
# @param object [Object] the Object on which the method was invoked
|
|
118
108
|
# @param ret [Object] the Return of the invoked method
|
|
119
|
-
# @param source_type [String] the type of this source, from the
|
|
120
|
-
#
|
|
121
|
-
# @param args [Array<Object>] the Arguments with which the method
|
|
122
|
-
# was invoked
|
|
109
|
+
# @param source_type [String] the type of this source, from the source_node, or a KEY_TYPE if invoked for a
|
|
110
|
+
# map
|
|
111
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
123
112
|
def apply_hash_tags context, source_node, target, object, ret, source_type, *args
|
|
124
113
|
to_replace = []
|
|
125
114
|
target.each_pair do |key, value|
|
|
126
|
-
# We only do this for Strings b/c of the way Hash lookup works.
|
|
127
|
-
#
|
|
128
|
-
# therefore, the application
|
|
115
|
+
# We only do this for Strings b/c of the way Hash lookup works. To replace another object would break
|
|
116
|
+
# hash lookup and, therefore, the application
|
|
129
117
|
if replace_hash_key?(key, target)
|
|
130
118
|
key = key.dup
|
|
131
119
|
to_replace << key
|
|
@@ -136,10 +124,8 @@ module Contrast
|
|
|
136
124
|
handle_hash_key(target, to_replace)
|
|
137
125
|
end
|
|
138
126
|
|
|
139
|
-
# Given an unfrozen hash, if the key is a String, we should replace
|
|
140
|
-
#
|
|
141
|
-
# This method handles checking if that replace can and should
|
|
142
|
-
# occur.
|
|
127
|
+
# Given an unfrozen hash, if the key is a String, we should replace it with one that we can finalize,
|
|
128
|
+
# allowing us to track that key. This method handles checking if that replace can and should occur.
|
|
143
129
|
#
|
|
144
130
|
# @param key [Object] the key in the hash that may need replacing.
|
|
145
131
|
# @param hash [Hash] the hash to which the key belongs.
|
|
@@ -160,9 +146,8 @@ module Contrast
|
|
|
160
146
|
nil
|
|
161
147
|
end
|
|
162
148
|
|
|
163
|
-
# Hash is designed to keep one instance of the string key in it.
|
|
164
|
-
#
|
|
165
|
-
# tracked one.
|
|
149
|
+
# Hash is designed to keep one instance of the string key in it. We need to remove the existing one and
|
|
150
|
+
# replace it with our new tracked one.
|
|
166
151
|
def handle_hash_key target, to_replace
|
|
167
152
|
to_replace.each do |key|
|
|
168
153
|
Contrast::Agent::Assess::Tracker.pre_freeze(key)
|
|
@@ -175,25 +160,19 @@ module Contrast
|
|
|
175
160
|
def apply_tags source_node, target, object, ret, source_type, source_name, *args
|
|
176
161
|
# don't apply tags if we can't track the thing
|
|
177
162
|
return unless Contrast::Agent::Assess::Tracker.trackable?(target)
|
|
178
|
-
# don't apply second source -- probably needs tuning later if we
|
|
179
|
-
# use more than 'UNTRUSTED' in our sources
|
|
163
|
+
# don't apply second source -- probably needs tuning later if we use more than 'UNTRUSTED' in our sources
|
|
180
164
|
return if Contrast::Agent::Assess::Tracker.tracked?(target)
|
|
181
165
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
|
|
182
166
|
|
|
183
|
-
# otherwise for each tag this source_node applies, create a tag range
|
|
184
|
-
#
|
|
185
|
-
# I realize this looping is counter-intuitive from the above
|
|
186
|
-
# message, that's why we're revisiting.
|
|
167
|
+
# otherwise for each tag this source_node applies, create a tag range on the target object. I realize
|
|
168
|
+
# this looping is counter-intuitive from the above message, that's why we're revisiting.
|
|
187
169
|
source_node.tags.each do |tag|
|
|
188
170
|
next unless Contrast::Agent::Assess::Policy::SourceValidation.valid?(tag, source_type, source_name)
|
|
189
171
|
|
|
190
172
|
length = Contrast::Utils::StringUtils.ret_length(target)
|
|
191
173
|
properties.add_tag(tag, 0...length)
|
|
192
174
|
properties.add_properties(source_node.properties)
|
|
193
|
-
logger.trace('Source detected',
|
|
194
|
-
node_id: source_node.id,
|
|
195
|
-
target_id: target.__id__,
|
|
196
|
-
tag: tag)
|
|
175
|
+
logger.trace('Source detected', node_id: source_node.id, target_id: target.__id__, tag: tag)
|
|
197
176
|
end
|
|
198
177
|
# make a representation of this method that TeamServer can render
|
|
199
178
|
properties.build_event(source_node, target, object, ret, args, source_type, source_name)
|
|
@@ -201,15 +180,13 @@ module Contrast
|
|
|
201
180
|
|
|
202
181
|
# Find the name of the source
|
|
203
182
|
#
|
|
204
|
-
# @param source_node [Contrast::Agent::Assess::Policy::SourceNode]
|
|
205
|
-
#
|
|
183
|
+
# @param source_node [Contrast::Agent::Assess::Policy::SourceNode] the node to direct applying this source
|
|
184
|
+
# event
|
|
206
185
|
# @param object [Object] the Object on which the method was invoked
|
|
207
186
|
# @param ret [Object] the Return of the invoked method
|
|
208
|
-
# @param args [Array<Object>] the Arguments with which the method
|
|
209
|
-
#
|
|
210
|
-
#
|
|
211
|
-
# which this source event applies, or nil if none provided by the
|
|
212
|
-
# node
|
|
187
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
188
|
+
# @return [String, nil] the human readable name of the target to which this source event applies, or nil if
|
|
189
|
+
# none provided by the node
|
|
213
190
|
def determine_source_name source_node, object, ret, *args
|
|
214
191
|
return source_node.get_property('dynamic_source_name') if source_node.type == 'UNTRUSTED_DATABASE'
|
|
215
192
|
|
|
@@ -226,14 +203,50 @@ module Contrast
|
|
|
226
203
|
end
|
|
227
204
|
end
|
|
228
205
|
|
|
206
|
+
# Determine if we should analyze this method invocation for a Source or not. We should if we have enough
|
|
207
|
+
# information to build the context of this invocation, we're not disabled, and we can't immediately
|
|
208
|
+
# determine the invocation was done safely.
|
|
209
|
+
#
|
|
210
|
+
# @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy] the policy that applies to the
|
|
211
|
+
# method being called
|
|
212
|
+
# @param object [Object] the Object on which the method was invoked
|
|
213
|
+
# @param ret [Object] the Return of the invoked method
|
|
214
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
215
|
+
# @return [boolean] if the invocation of this method should be analyzed
|
|
216
|
+
def analyze? method_policy, object, ret, args
|
|
217
|
+
return false unless method_policy&.source_node
|
|
218
|
+
return false unless ASSESS.enabled?
|
|
219
|
+
return false unless Contrast::Agent::REQUEST_TRACKER.current&.analyze_request?
|
|
220
|
+
|
|
221
|
+
!safe_invocation?(method_policy.source_node, object, ret, args)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Determine if the method was invoked safely.
|
|
225
|
+
#
|
|
226
|
+
# @param source_node [Contrast::Agent::Assess::Policy::SourceNode] the node to direct applying this source
|
|
227
|
+
# event
|
|
228
|
+
# @param _object [Object] the Object on which the method was invoked
|
|
229
|
+
# @param _ret [Object] the Return of the invoked method
|
|
230
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
231
|
+
# @return [boolean] if the invocation of this method was safe
|
|
232
|
+
def safe_invocation? source_node, _object, _ret, args
|
|
233
|
+
# According the the Rack Specification https://github.com/rack/rack/blob/master/SPEC.rdoc, any header
|
|
234
|
+
# from the Request will start with HTTP_. As such, only Headers with that key should be considered for
|
|
235
|
+
# tracking, as the others have come from the Framework or Middleware stashing in the ENV. Rails, for
|
|
236
|
+
# instance, uses action_dispatch. to store several values. Technically, you can't call
|
|
237
|
+
# Rack::Request#get_header without a parameter, and that parameter should be a String, but trust no one.
|
|
238
|
+
source_node.id == 'Assess:Source:Rack::Request::Env#get_header' &&
|
|
239
|
+
args&.any? &&
|
|
240
|
+
!args[0].to_s.start_with?('HTTP_')
|
|
241
|
+
end
|
|
242
|
+
|
|
229
243
|
# Find the literal target of the propagation
|
|
230
244
|
#
|
|
231
|
-
# @param source_node [Contrast::Agent::Assess::Policy::SourceNode]
|
|
232
|
-
#
|
|
245
|
+
# @param source_node [Contrast::Agent::Assess::Policy::SourceNode] the node to direct applying this source
|
|
246
|
+
# event
|
|
233
247
|
# @param object [Object] the Object on which the method was invoked
|
|
234
248
|
# @param ret [Object] the Return of the invoked method
|
|
235
|
-
# @param args [Array<Object>] the Arguments with which the method
|
|
236
|
-
# was invoked
|
|
249
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
237
250
|
# @return [Object] the target to which this source event applies
|
|
238
251
|
def determine_target source_node, object, ret, args
|
|
239
252
|
source_target = source_node.targets[0]
|
|
@@ -247,12 +260,10 @@ module Contrast
|
|
|
247
260
|
end
|
|
248
261
|
end
|
|
249
262
|
|
|
250
|
-
# Simple helper method to flip the type from value to key when the
|
|
251
|
-
# source is the key of a Hash
|
|
263
|
+
# Simple helper method to flip the type from value to key when the source is the key of a Hash
|
|
252
264
|
#
|
|
253
265
|
# @param source_type [String] the original value source type
|
|
254
|
-
# @return [String] the key form of the source type, if one exists,
|
|
255
|
-
# else the original source type
|
|
266
|
+
# @return [String] the key form of the source type, if one exists, else the original source type
|
|
256
267
|
def key_type source_type
|
|
257
268
|
case source_type
|
|
258
269
|
when PARAMETER_TYPE
|