contrast-agent 6.1.1 → 6.3.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/ext/cs__assess_basic_object/cs__assess_basic_object.c +7 -5
- data/ext/cs__assess_kernel/cs__assess_kernel.c +14 -3
- data/ext/cs__assess_kernel/cs__assess_kernel.h +2 -0
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +10 -3
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +2 -1
- data/ext/cs__assess_regexp/cs__assess_regexp.c +9 -7
- data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.c → cs__assess_string_interpolation/cs__assess_string_interpolation.c} +14 -3
- data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.h → cs__assess_string_interpolation/cs__assess_string_interpolation.h} +1 -1
- data/ext/{cs__assess_string_interpolation26 → cs__assess_string_interpolation}/extconf.rb +0 -0
- data/ext/cs__common/cs__common.c +5 -4
- data/ext/cs__contrast_patch/cs__contrast_patch.c +3 -10
- data/lib/contrast/agent/assess/events/source_event.rb +16 -12
- data/lib/contrast/agent/assess/policy/policy_node.rb +6 -0
- data/lib/contrast/agent/assess/policy/propagation_method.rb +3 -39
- data/lib/contrast/agent/assess/policy/propagation_node.rb +8 -0
- data/lib/contrast/agent/assess/policy/propagator/base.rb +2 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +2 -47
- data/lib/contrast/agent/assess/policy/source_node.rb +1 -0
- data/lib/contrast/agent/assess/policy/trigger_node.rb +8 -0
- data/lib/contrast/agent/assess/property/evented.rb +4 -18
- data/lib/contrast/agent/assess/tag.rb +19 -0
- data/lib/contrast/agent/at_exit_hook.rb +9 -8
- data/lib/contrast/agent/inventory/database_config.rb +18 -7
- data/lib/contrast/agent/inventory/dependency_analysis.rb +3 -2
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +13 -9
- data/lib/contrast/agent/middleware.rb +4 -0
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +27 -2
- data/lib/contrast/agent/patching/policy/policy.rb +5 -0
- data/lib/contrast/agent/patching/policy/policy_node.rb +6 -0
- data/lib/contrast/agent/patching/policy/trigger_node.rb +3 -0
- data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +3 -4
- data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -0
- data/lib/contrast/agent/protect/policy/rule_applicator.rb +2 -2
- data/lib/contrast/agent/protect/rule/base.rb +1 -0
- data/lib/contrast/agent/protect/rule/no_sqli.rb +2 -0
- data/lib/contrast/agent/protect/rule/xss.rb +4 -0
- data/lib/contrast/agent/reporting/reporter.rb +33 -17
- data/lib/contrast/agent/reporting/reporter_heartbeat.rb +21 -15
- data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +3 -18
- data/lib/contrast/agent/reporting/reporting_events/application_update.rb +5 -24
- data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +8 -1
- data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +83 -16
- data/lib/contrast/agent/reporting/reporting_events/finding.rb +9 -3
- data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +10 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +12 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +10 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +29 -32
- data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +18 -20
- data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +11 -24
- data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +13 -6
- data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +10 -4
- data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +10 -4
- data/lib/contrast/agent/reporting/reporting_events/route_coverage.rb +9 -0
- data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +10 -1
- data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +11 -4
- data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +0 -8
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +2 -6
- data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -32
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -4
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -11
- data/lib/contrast/agent/reporting/reporting_utilities/response.rb +60 -2
- data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +32 -10
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +58 -26
- data/lib/contrast/agent/reporting/settings/application_settings.rb +8 -23
- data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +27 -33
- data/lib/contrast/agent/reporting/settings/bot_blocker.rb +68 -0
- data/lib/contrast/agent/reporting/settings/code_exclusion.rb +27 -0
- data/lib/contrast/agent/reporting/settings/exclusion_base.rb +33 -0
- data/lib/contrast/agent/reporting/settings/exclusions.rb +39 -57
- data/lib/contrast/agent/reporting/settings/helpers.rb +56 -0
- data/lib/contrast/agent/reporting/settings/input_exclusion.rb +37 -0
- data/lib/contrast/agent/reporting/settings/ip_filter.rb +35 -0
- data/lib/contrast/agent/reporting/settings/keyword.rb +74 -0
- data/lib/contrast/agent/reporting/settings/log_enhancer.rb +65 -0
- data/lib/contrast/agent/reporting/settings/protect.rb +4 -2
- data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +62 -115
- data/lib/contrast/agent/reporting/settings/reaction.rb +11 -2
- data/lib/contrast/agent/reporting/settings/rule_definition.rb +63 -0
- data/lib/contrast/agent/reporting/settings/sampling.rb +10 -0
- data/lib/contrast/agent/reporting/settings/sanitizer.rb +38 -0
- data/lib/contrast/agent/reporting/settings/sensitive_data_masking.rb +9 -1
- data/lib/contrast/agent/reporting/settings/sensitive_data_masking_rule.rb +7 -0
- data/lib/contrast/agent/reporting/settings/server_features.rb +8 -0
- data/lib/contrast/agent/reporting/settings/syslog.rb +176 -0
- data/lib/contrast/agent/reporting/settings/url_exclusion.rb +42 -0
- data/lib/contrast/agent/reporting/settings/validator.rb +17 -0
- data/lib/contrast/agent/request.rb +5 -7
- data/lib/contrast/agent/request_context.rb +8 -13
- data/lib/contrast/agent/request_context_extend.rb +8 -9
- data/lib/contrast/agent/request_handler.rb +10 -35
- data/lib/contrast/agent/rule_set.rb +4 -0
- data/lib/contrast/agent/service_heartbeat.rb +1 -1
- data/lib/contrast/agent/static_analysis.rb +6 -15
- data/lib/contrast/agent/telemetry/base.rb +35 -35
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +2 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +2 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +5 -2
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +3 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +3 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +0 -1
- data/lib/contrast/agent/thread_watcher.rb +2 -6
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/agent.rb +1 -3
- data/lib/contrast/api/communication/socket.rb +1 -0
- data/lib/contrast/api/decorators/message.rb +0 -6
- data/lib/contrast/api/decorators.rb +0 -3
- data/lib/contrast/components/assess.rb +0 -6
- data/lib/contrast/components/config.rb +18 -2
- data/lib/contrast/config/base_configuration.rb +0 -13
- data/lib/contrast/config/root_configuration.rb +1 -0
- data/lib/contrast/config/ruby_configuration.rb +2 -9
- data/lib/contrast/configuration.rb +0 -2
- data/lib/contrast/extension/assess/eval_trigger.rb +0 -4
- data/lib/contrast/extension/assess/hash.rb +3 -2
- data/lib/contrast/extension/assess/kernel.rb +22 -0
- data/lib/contrast/extension/assess/marshal.rb +16 -0
- data/lib/contrast/extension/assess/string.rb +21 -20
- data/lib/contrast/framework/base_support.rb +13 -4
- data/lib/contrast/framework/grape/support.rb +6 -6
- data/lib/contrast/framework/manager.rb +7 -23
- data/lib/contrast/framework/manager_extend.rb +1 -1
- data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +11 -15
- data/lib/contrast/framework/rails/support.rb +9 -2
- data/lib/contrast/framework/sinatra/support.rb +3 -2
- data/lib/contrast/logger/aliased_logging.rb +33 -26
- data/lib/contrast/utils/assess/source_method_utils.rb +0 -9
- data/lib/contrast/utils/lru_cache.rb +3 -0
- data/lib/contrast/utils/middleware_utils.rb +2 -0
- data/lib/contrast/utils/response_utils.rb +14 -1
- data/lib/contrast/utils/telemetry.rb +9 -0
- data/lib/contrast/utils/telemetry_client.rb +7 -7
- data/lib/contrast/utils/telemetry_hash.rb +36 -12
- data/lib/contrast/utils/telemetry_identifier.rb +8 -0
- data/lib/contrast/utils/thread_tracker.rb +26 -9
- data/lib/contrast/utils/timer.rb +6 -1
- data/lib/contrast.rb +1 -3
- data/resources/assess/policy.json +2 -11
- data/ruby-agent.gemspec +1 -1
- metadata +36 -22
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +0 -30
- data/lib/contrast/api/decorators/application_update.rb +0 -52
- data/lib/contrast/api/decorators/library.rb +0 -56
- data/lib/contrast/api/decorators/library_usage_update.rb +0 -31
- data/lib/contrast/framework/platform_version.rb +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b7fbfe09d8f01268274ec60a3861fc4377278e0e33aafadd29a13aec59348bb
|
|
4
|
+
data.tar.gz: caf12a68dca338f4e1ed0e04483857cd7c55140d8698f1aa55b82c6f85d210c6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd9eb2d8fd9faf79ad16e0d32889806c93178f696ad64aa58cdc046e46c1cb5e0ff463e54cf81e491518fd732a664f5838147f83c791c869d3689695b1255384
|
|
7
|
+
data.tar.gz: '097d53ac525825b0b3b305dafe1be2cc178f7198e057f292561e7ffa4801476dcf151d9a51d6277033dbaf149f6ed0d9b52606aebebeffc7636564eea59bbf74'
|
|
@@ -17,9 +17,10 @@
|
|
|
17
17
|
* }
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
VALUE contrast_check_and_register_instance_patch(
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
VALUE contrast_check_and_register_instance_patch(const char *module_name,
|
|
21
|
+
const char *method_name,
|
|
22
|
+
VALUE(c_fn)(const int, VALUE *,
|
|
23
|
+
const VALUE));
|
|
23
24
|
|
|
24
25
|
void contrast_assess_instance_eval_trigger_check(VALUE self, VALUE source,
|
|
25
26
|
VALUE ret) {
|
|
@@ -65,6 +66,7 @@ void Init_cs__assess_basic_object(void) {
|
|
|
65
66
|
* but if someone else patched BasicObject#instance_eval,
|
|
66
67
|
* IDK if this is intentional... noting it. -ajm
|
|
67
68
|
*/
|
|
68
|
-
contrast_check_and_register_instance_patch(
|
|
69
|
-
|
|
69
|
+
contrast_check_and_register_instance_patch(
|
|
70
|
+
"BasicObject", "instance_eval",
|
|
71
|
+
contrast_assess_basic_object_instance_eval);
|
|
70
72
|
}
|
|
@@ -26,14 +26,25 @@ contrast_patched_kernel_exec(const int argc, const VALUE *argv,
|
|
|
26
26
|
return rb_funcall(self, rb_sym_assess_kernel_exec, argc, *argv);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/* Check and see if the Kernel#exec is already prepended */
|
|
30
|
+
VALUE contrast_is_kernel_exec_prepended() {
|
|
31
|
+
return contrast_check_prepended(
|
|
32
|
+
rb_const_get(rb_cObject, rb_intern("Kernel")), rb_sym_kernel_exec,
|
|
33
|
+
Qfalse);
|
|
34
|
+
}
|
|
35
|
+
|
|
29
36
|
void Init_cs__assess_kernel(void) {
|
|
37
|
+
VALUE rb_sym_kernel_exec = ID2SYM(rb_intern("exec"));
|
|
30
38
|
kernel_propagator = rb_define_module_under(core_assess, "KernelPropagator");
|
|
31
39
|
exec_apply_trigger = rb_intern("apply_trigger");
|
|
32
40
|
|
|
33
41
|
rb_sym_assess_kernel_exec =
|
|
34
42
|
contrast_register_patch("Kernel", "exec", contrast_patched_kernel_exec);
|
|
35
43
|
|
|
36
|
-
/*
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
/* check if prepended and register singleton patch if true */
|
|
45
|
+
if (contrast_is_kernel_exec_prepended() == Qtrue) {
|
|
46
|
+
/* should return the same value as above */
|
|
47
|
+
rb_sym_assess_kernel_exec = contrast_register_singleton_patch(
|
|
48
|
+
"Kernel", "exec", contrast_patched_kernel_exec);
|
|
49
|
+
}
|
|
39
50
|
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* return rb_marshal_load_with_proc(port, proc);
|
|
19
19
|
* }
|
|
20
20
|
*/
|
|
21
|
-
static VALUE
|
|
21
|
+
static VALUE contrast_marshal_module_prepend(const int argc, const VALUE *argv) {
|
|
22
22
|
VALUE result;
|
|
23
23
|
VALUE source_string;
|
|
24
24
|
|
|
@@ -67,6 +67,13 @@ void Init_cs__assess_marshal_module(void) {
|
|
|
67
67
|
rb_sym_assess_marshal_load = rb_intern("cs__load_assess");
|
|
68
68
|
rb_sym_protect_marshal_load = rb_intern("cs__load_protect");
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
/* check if prepended called form the after_load_patcher */
|
|
71
|
+
VALUE marshal = rb_const_get(rb_cObject, rb_intern("Marshal"));
|
|
72
|
+
VALUE marshal_load = ID2SYM(rb_intern("load"));
|
|
73
|
+
VALUE is_prepended = contrast_check_prepended(marshal, marshal_load, Qfalse);
|
|
74
|
+
|
|
75
|
+
if (is_prepended == Qtrue) {
|
|
76
|
+
contrast_register_singleton_prepend_patch("Marshal", "load",
|
|
77
|
+
&contrast_marshal_module_prepend);
|
|
78
|
+
}
|
|
72
79
|
}
|
|
@@ -5,6 +5,7 @@ static VALUE marshal_propagator;
|
|
|
5
5
|
static VALUE rb_sym_assess_marshal_load;
|
|
6
6
|
static VALUE rb_sym_protect_marshal_load;
|
|
7
7
|
static VALUE properties_hash;
|
|
8
|
+
static VALUE marshal, marshal_load, is_prepended;
|
|
8
9
|
|
|
9
10
|
/*
|
|
10
11
|
* Rails is a jerk. In Rails 5, they decided to do away with the alias chaining
|
|
@@ -14,7 +15,7 @@ static VALUE properties_hash;
|
|
|
14
15
|
* special case this for now.
|
|
15
16
|
* -HM (shamelessly commenting on DP's work)
|
|
16
17
|
*/
|
|
17
|
-
static VALUE
|
|
18
|
+
static VALUE contrast_marshal_module_prepend(const int argc,
|
|
18
19
|
const VALUE *argv);
|
|
19
20
|
|
|
20
21
|
void Init_cs__assess_marshal_module(void);
|
|
@@ -7,15 +7,15 @@
|
|
|
7
7
|
#include <ruby.h>
|
|
8
8
|
|
|
9
9
|
extern VALUE contrast_force_patch(const int argc, VALUE *argv) {
|
|
10
|
-
|
|
10
|
+
return contrast_check_and_register_instance_patch(
|
|
11
11
|
"Regexp", "=~", contrast_assess_regexp_equal_squiggle);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/* check if method is prepended and register instance alias or prepend patch */
|
|
15
15
|
VALUE contrast_check_and_register_instance_patch(const char *module_name,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const char *method_name,
|
|
17
|
+
VALUE(c_fn)(const int, VALUE *,
|
|
18
|
+
const VALUE));
|
|
19
19
|
|
|
20
20
|
void contrast_alias_method(const VALUE target, const char *to,
|
|
21
21
|
const char *from);
|
|
@@ -58,8 +58,10 @@ void Init_cs__assess_regexp(void) {
|
|
|
58
58
|
rb_global_variable(&rb_sym_string);
|
|
59
59
|
rb_sym_back_ref = ID2SYM(rb_intern("back_ref"));
|
|
60
60
|
rb_global_variable(&rb_sym_back_ref);
|
|
61
|
-
rb_define_singleton_method(assess, "contrast_force_repatch_regexp",
|
|
61
|
+
rb_define_singleton_method(assess, "contrast_force_repatch_regexp",
|
|
62
|
+
contrast_force_patch, 0);
|
|
62
63
|
|
|
63
|
-
rb_sym_assess_regexp_equal_squiggle =
|
|
64
|
-
|
|
64
|
+
rb_sym_assess_regexp_equal_squiggle =
|
|
65
|
+
contrast_check_and_register_instance_patch(
|
|
66
|
+
"Regexp", "=~", contrast_assess_regexp_equal_squiggle);
|
|
65
67
|
}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
/* Copyright (c) 2022 Contrast Security, Inc. See
|
|
2
2
|
* https://www.contrastsecurity.com/enduser-terms-0317a for more details. */
|
|
3
3
|
|
|
4
|
-
#include "
|
|
4
|
+
#include "cs__assess_string_interpolation.h"
|
|
5
5
|
#include "../cs__common/cs__common.h"
|
|
6
|
+
#include "../cs__scope/cs__scope.h"
|
|
6
7
|
#include <ruby.h>
|
|
7
8
|
|
|
8
9
|
static VALUE rb_str_concat_literals_hook(size_t num, VALUE *strary) {
|
|
9
10
|
VALUE result = rb_str_concat_literals_original(num, strary);
|
|
10
11
|
VALUE rb_params = rb_ary_new_from_values((int)num, strary);
|
|
11
|
-
|
|
12
|
+
VALUE in_contrast_scope = inst_methods_in_cntr_scope(contrast_patcher(), 0);
|
|
13
|
+
|
|
14
|
+
if (in_contrast_scope == Qfalse) {
|
|
15
|
+
/* enter scope */
|
|
16
|
+
inst_methods_enter_cntr_scope(contrast_patcher(), 0);
|
|
17
|
+
rb_funcall(string_propagator, track_interpolation, 2, rb_params,
|
|
18
|
+
result);
|
|
19
|
+
/* exit scope */
|
|
20
|
+
inst_methods_exit_cntr_scope(contrast_patcher(), 0);
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
return result;
|
|
13
24
|
}
|
|
14
25
|
|
|
@@ -20,7 +31,7 @@ static int install_hooks() {
|
|
|
20
31
|
return 0;
|
|
21
32
|
}
|
|
22
33
|
|
|
23
|
-
void
|
|
34
|
+
void Init_cs__assess_string_interpolation(void) {
|
|
24
35
|
string_propagator =
|
|
25
36
|
rb_define_class_under(core_assess, "StringPropagator", rb_cObject);
|
|
26
37
|
track_interpolation = rb_intern("track_interpolation");
|
|
File without changes
|
data/ext/cs__common/cs__common.c
CHANGED
|
@@ -97,9 +97,10 @@ VALUE contrast_register_singleton_prepend_patch(const char *module_name,
|
|
|
97
97
|
/* module name c_char "Module"; */
|
|
98
98
|
/* method name c_char "method"; */
|
|
99
99
|
/* c_func => pointer */
|
|
100
|
-
VALUE contrast_check_and_register_instance_patch(
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
VALUE contrast_check_and_register_instance_patch(const char *module_name,
|
|
101
|
+
const char *method_name,
|
|
102
|
+
VALUE(c_fn)(const int, VALUE *,
|
|
103
|
+
const VALUE)) {
|
|
103
104
|
|
|
104
105
|
VALUE object, method, is_prepended, patch_type;
|
|
105
106
|
/* check if method is prepended */
|
|
@@ -291,5 +292,5 @@ void Init_cs__common(void) {
|
|
|
291
292
|
contrast_check_prepended, 2);
|
|
292
293
|
/* defined for object lookout */
|
|
293
294
|
rb_define_singleton_method(assess, "cs__object_method_prepended?",
|
|
294
|
-
contrast_lookout_prepended,
|
|
295
|
+
contrast_lookout_prepended, 3);
|
|
295
296
|
}
|
|
@@ -222,19 +222,12 @@ VALUE contrast_run_patches(const VALUE *wrapped_args) {
|
|
|
222
222
|
* call site. This means the rest of this function is not executed.
|
|
223
223
|
*/
|
|
224
224
|
|
|
225
|
-
/* Invoke Contrast post-call patching.
|
|
226
|
-
|
|
227
|
-
* hence the assignment.
|
|
228
|
-
*/
|
|
229
|
-
transformed_ret = contrast_call_post_patch(method_policy, preshift, object,
|
|
225
|
+
/* Invoke Contrast post-call patching. */
|
|
226
|
+
contrast_call_post_patch(method_policy, preshift, object,
|
|
230
227
|
original_ret, argc, argv);
|
|
231
228
|
|
|
232
229
|
/* Special case for tracking frozen sources */
|
|
233
|
-
|
|
234
|
-
return transformed_ret;
|
|
235
|
-
} else {
|
|
236
|
-
return original_ret;
|
|
237
|
-
}
|
|
230
|
+
return original_ret;
|
|
238
231
|
}
|
|
239
232
|
|
|
240
233
|
VALUE contrast_ensure_function(const VALUE method_policy) {
|
|
@@ -56,18 +56,8 @@ module Contrast
|
|
|
56
56
|
|
|
57
57
|
# Probably only for source events, but we'll go with source_type instead. java & .net support source_type
|
|
58
58
|
# in propagation events, so we'll future proof this
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return unless source_type
|
|
62
|
-
|
|
63
|
-
dtm = Contrast::Api::Dtm::TraceEventSource.new
|
|
64
|
-
dtm.type = forced_source_type
|
|
65
|
-
dtm.name = forced_source_name
|
|
66
|
-
dtm
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# Probably only for source events, but we'll go with source_type instead. java & .net support source_type
|
|
70
|
-
# in propagation events, so we'll future proof this
|
|
59
|
+
#
|
|
60
|
+
# @return [Contrast::Agent::Reporting::TraceEventSource, nil]
|
|
71
61
|
def build_event_source
|
|
72
62
|
# You can have a source w/o a name, but not w/o a type
|
|
73
63
|
return unless source_type
|
|
@@ -89,6 +79,20 @@ module Contrast
|
|
|
89
79
|
event_dtm.target = @policy_node.target_string
|
|
90
80
|
@policy_node.targets[0]
|
|
91
81
|
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
# Probably only for source events, but we'll go with source_type instead. java & .net support source_type
|
|
86
|
+
# in propagation events, so we'll future proof this
|
|
87
|
+
def build_event_source_dtm
|
|
88
|
+
# You can have a source w/o a name, but not w/o a type
|
|
89
|
+
return unless source_type
|
|
90
|
+
|
|
91
|
+
dtm = Contrast::Api::Dtm::TraceEventSource.new
|
|
92
|
+
dtm.type = forced_source_type
|
|
93
|
+
dtm.name = forced_source_name
|
|
94
|
+
dtm
|
|
95
|
+
end
|
|
92
96
|
end
|
|
93
97
|
end
|
|
94
98
|
end
|
|
@@ -5,6 +5,7 @@ require 'contrast/agent/patching/policy/policy_node'
|
|
|
5
5
|
require 'contrast/api/decorators/trace_taint_range_tags'
|
|
6
6
|
require 'contrast/utils/object_share'
|
|
7
7
|
require 'contrast/agent/assess/policy/policy_node_utils'
|
|
8
|
+
require 'contrast/components/logger'
|
|
8
9
|
|
|
9
10
|
module Contrast
|
|
10
11
|
module Agent
|
|
@@ -13,6 +14,7 @@ module Contrast
|
|
|
13
14
|
# This class functions to translate our policy.json into an actionable
|
|
14
15
|
# Ruby object, allowing for dynamic patching over hardcoded patching.
|
|
15
16
|
class PolicyNode < Contrast::Agent::Patching::Policy::PolicyNode
|
|
17
|
+
include Contrast::Components::Logger::InstanceMethods
|
|
16
18
|
include PolicyNodeUtils
|
|
17
19
|
JSON_TAGS = 'tags'
|
|
18
20
|
JSON_DATAFLOW = 'dataflow'
|
|
@@ -107,12 +109,16 @@ module Contrast
|
|
|
107
109
|
def validate
|
|
108
110
|
super
|
|
109
111
|
validate_tags
|
|
112
|
+
rescue ArgumentError => e
|
|
113
|
+
logger.debug('Validation of policy node failed with: ', e)
|
|
114
|
+
nil
|
|
110
115
|
end
|
|
111
116
|
|
|
112
117
|
# TeamServer is picky. The tags here match to ENUMs there. If there
|
|
113
118
|
# isn't a matching ENUM in TS land, the database gets got. We really
|
|
114
119
|
# don't want to get them, so we're going to prevent the node from being
|
|
115
120
|
# made.
|
|
121
|
+
# @raise[ArgumentError] raises if any of the tags is invalid
|
|
116
122
|
def validate_tags
|
|
117
123
|
return unless tags
|
|
118
124
|
|
|
@@ -133,16 +133,6 @@ module Contrast
|
|
|
133
133
|
true
|
|
134
134
|
end
|
|
135
135
|
|
|
136
|
-
# Safely duplicate the target, or return nil
|
|
137
|
-
#
|
|
138
|
-
# @param target [Object] the thing to check for duplication
|
|
139
|
-
# @return [Object, nil]
|
|
140
|
-
def safe_dup target
|
|
141
|
-
target.dup
|
|
142
|
-
rescue StandardError => _e
|
|
143
|
-
nil
|
|
144
|
-
end
|
|
145
|
-
|
|
146
136
|
# Iterate over each key and value in a hash to allow for propagation to each.
|
|
147
137
|
#
|
|
148
138
|
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
|
@@ -199,25 +189,11 @@ module Contrast
|
|
|
199
189
|
return unless can_propagate?(propagation_node, preshift, target)
|
|
200
190
|
return unless (propagation_class = find_propagation_class(propagation_node))
|
|
201
191
|
|
|
202
|
-
restore_frozen_state = false
|
|
203
|
-
if target.cs__frozen? && !Contrast::Agent::Assess::Tracker.trackable?(target)
|
|
204
|
-
return unless can_handle_frozen?(propagation_node)
|
|
205
|
-
return unless (dup = safe_dup(propagation_data.ret))
|
|
206
|
-
|
|
207
|
-
restore_frozen_state = true
|
|
208
|
-
ret = dup
|
|
209
|
-
target = ret
|
|
210
|
-
Contrast::Agent::Assess::Tracker.pre_freeze(ret)
|
|
211
|
-
ret.cs__freeze
|
|
212
|
-
# double check that we were able to finalize the replaced return
|
|
213
|
-
return unless Contrast::Agent::Assess::Tracker.trackable?(target)
|
|
214
|
-
end
|
|
215
|
-
|
|
216
192
|
# If we are using the original object tracking, the preshift object is not created.
|
|
217
193
|
# Instead identify the source as the original object itself and propagate with it.
|
|
218
194
|
source = propagation_node.use_original_object? ? propagation_data.object : preshift
|
|
219
195
|
handle_propagation(propagation_class, propagation_node, source, target)
|
|
220
|
-
update_properties(
|
|
196
|
+
update_properties(propagation_node, target, propagation_data)
|
|
221
197
|
end
|
|
222
198
|
|
|
223
199
|
def handle_propagation propagation_class, propagation_node, source, target
|
|
@@ -228,7 +204,7 @@ module Contrast
|
|
|
228
204
|
end
|
|
229
205
|
end
|
|
230
206
|
|
|
231
|
-
def update_properties
|
|
207
|
+
def update_properties propagation_node, target, propagation_data
|
|
232
208
|
if propagation_node.use_original_on_bang_method?
|
|
233
209
|
properties = use_original_object_properties(propagation_data)
|
|
234
210
|
|
|
@@ -248,11 +224,10 @@ module Contrast
|
|
|
248
224
|
event_data = Contrast::Agent::Assess::Events::EventData.new(propagation_node,
|
|
249
225
|
target,
|
|
250
226
|
propagation_data.object,
|
|
251
|
-
ret,
|
|
227
|
+
propagation_data.ret,
|
|
252
228
|
propagation_data.args)
|
|
253
229
|
properties.build_event(event_data)
|
|
254
230
|
logger.trace('Propagation detected', node_id: propagation_node.id, target_id: target.__id__)
|
|
255
|
-
restore_frozen_state ? ret : nil
|
|
256
231
|
end
|
|
257
232
|
|
|
258
233
|
# Find the propagation class from the given node, if one exists.
|
|
@@ -269,17 +244,6 @@ module Contrast
|
|
|
269
244
|
propagation_class
|
|
270
245
|
end
|
|
271
246
|
|
|
272
|
-
# We can handle frozen propagation iff we're allowed to, as determined by configuration, and the target of
|
|
273
|
-
# the propagation is a return, as that's a replaceable value.
|
|
274
|
-
#
|
|
275
|
-
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs a
|
|
276
|
-
# propagation event.
|
|
277
|
-
# @return [Boolean]
|
|
278
|
-
def can_handle_frozen? propagation_node
|
|
279
|
-
::Contrast::ASSESS.track_frozen_sources? &&
|
|
280
|
-
propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
|
|
281
|
-
end
|
|
282
|
-
|
|
283
247
|
# For certain bang methods we return the same object, no need to create expensive new properties.
|
|
284
248
|
#
|
|
285
249
|
# @param propagation_data [Contrast::Agent::Assess::Events::EventData] used to hold object, args
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
require 'contrast/agent/assess/policy/policy_node'
|
|
5
5
|
require 'contrast/api/decorators/trace_taint_range_tags'
|
|
6
|
+
require 'contrast/components/logger'
|
|
6
7
|
|
|
7
8
|
module Contrast
|
|
8
9
|
module Agent
|
|
@@ -14,6 +15,8 @@ module Contrast
|
|
|
14
15
|
# untrusted data (indicate points in the application where user
|
|
15
16
|
# controlled input is modified).
|
|
16
17
|
class PropagationNode < PolicyNode
|
|
18
|
+
include Contrast::Components::Logger::InstanceMethods
|
|
19
|
+
|
|
17
20
|
JSON_ACTION = 'action'
|
|
18
21
|
JSON_UNTAGS = 'untags'
|
|
19
22
|
JSON_PATCH_CLASS = 'patch_class'
|
|
@@ -41,6 +44,9 @@ module Contrast
|
|
|
41
44
|
@patch_method = propagation_hash[JSON_PATCH_METHOD]
|
|
42
45
|
@patch_method = @patch_method.to_sym if @patch_method
|
|
43
46
|
validate
|
|
47
|
+
rescue ArgumentError => e
|
|
48
|
+
logger.error('Propagation Node Initialization failed with: ', e)
|
|
49
|
+
nil
|
|
44
50
|
end
|
|
45
51
|
|
|
46
52
|
def node_class
|
|
@@ -56,6 +62,7 @@ module Contrast
|
|
|
56
62
|
|
|
57
63
|
# Standard validation + TS trace version two rules:
|
|
58
64
|
# Must have source, target, and action
|
|
65
|
+
# @raise[ArgumentError] raises if any of the required propagation node field is not valid, or is missing
|
|
59
66
|
def validate
|
|
60
67
|
super
|
|
61
68
|
raise(ArgumentError, "Propagator #{ id } did not have a proper action. Unable to create.") unless action
|
|
@@ -78,6 +85,7 @@ module Contrast
|
|
|
78
85
|
validate_untags
|
|
79
86
|
end
|
|
80
87
|
|
|
88
|
+
# @raise[ArgumentError] raises if any of the tags is invalid
|
|
81
89
|
def validate_untags
|
|
82
90
|
return unless untags
|
|
83
91
|
|
|
@@ -25,6 +25,8 @@ module Contrast
|
|
|
25
25
|
Contrast::Agent::Assess::Tracker.tracked?(value)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
# @raise [NoMethodError] This is being raised if any of the implementing subclasses does not have
|
|
29
|
+
# that method implemented, but is being called on.
|
|
28
30
|
def propagate _propagation_node, _preshift, _target
|
|
29
31
|
raise(NoMethodError("Expected Base propagator subclass: #{ cs__class } to implement #propagate"))
|
|
30
32
|
end
|
|
@@ -35,30 +35,17 @@ module Contrast
|
|
|
35
35
|
# @param object [Object] the Object on which the method was invoked
|
|
36
36
|
# @param ret [Object] the Return of the invoked method
|
|
37
37
|
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
38
|
-
# @return [Object, nil] the tracked Return or nil if no changes were made
|
|
39
38
|
def apply_source method_policy, object, ret, args
|
|
40
39
|
return unless analyze?(method_policy, object, ret, args)
|
|
41
40
|
return unless (source_node = method_policy.source_node)
|
|
42
41
|
|
|
43
42
|
# used to hold the object and ret
|
|
44
43
|
source_data = Contrast::Agent::Assess::Events::EventData.new(nil, nil, object, ret, nil)
|
|
45
|
-
return unless (target = determine_target(source_node, source_data, args))
|
|
46
|
-
|
|
47
|
-
return_val = nil
|
|
48
|
-
if target.cs__frozen? && !Contrast::Agent::Assess::Tracker.trackable?(target)
|
|
49
|
-
return unless ::Contrast::ASSESS.track_frozen_sources?
|
|
50
|
-
return unless source_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
|
|
51
|
-
return unless (dup = safe_dup(source_data.ret))
|
|
52
|
-
return unless Contrast::Agent::Assess::Tracker.trackable?(dup)
|
|
53
44
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
target = dup
|
|
57
|
-
end
|
|
45
|
+
return unless (target = determine_target(source_node, source_data, args))
|
|
46
|
+
return if target.cs__frozen? && !Contrast::Agent::Assess::Tracker.trackable?(target)
|
|
58
47
|
|
|
59
48
|
process_source(source_node, target, source_data, source_node.type, nil, *args)
|
|
60
|
-
|
|
61
|
-
return_val
|
|
62
49
|
end
|
|
63
50
|
Contrast::Components::Logger.add_trace_log_timing_for(SourceMethod, :apply_source)
|
|
64
51
|
|
|
@@ -108,42 +95,10 @@ module Contrast
|
|
|
108
95
|
# map
|
|
109
96
|
# @param args [Array<Object>] the Arguments with which the method was invoked
|
|
110
97
|
def apply_hash_tags source_node, target, source_data, source_type, *args
|
|
111
|
-
to_replace = []
|
|
112
98
|
target.each_pair do |key, value|
|
|
113
|
-
# We only do this for Strings b/c of the way Hash lookup works. To replace another object would break
|
|
114
|
-
# hash lookup and, therefore, the application
|
|
115
|
-
if replace_hash_key?(key, target)
|
|
116
|
-
key = key.dup
|
|
117
|
-
to_replace << key
|
|
118
|
-
end
|
|
119
99
|
process_source(source_node, key, source_data, key_type(source_type), key, *args)
|
|
120
100
|
process_source(source_node, value, source_data, source_type, key, *args)
|
|
121
101
|
end
|
|
122
|
-
handle_hash_key(target, to_replace)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# Given an unfrozen hash, if the key is a String, we should replace it with one that we can finalize,
|
|
126
|
-
# allowing us to track that key. This method handles checking if that replace can and should occur.
|
|
127
|
-
#
|
|
128
|
-
# @param key [Object] the key in the hash that may need replacing.
|
|
129
|
-
# @param hash [Hash] the hash to which the key belongs.
|
|
130
|
-
# @return [Boolean] whether replace the key in the hash or not.
|
|
131
|
-
def replace_hash_key? key, hash
|
|
132
|
-
::Contrast::ASSESS.track_frozen_sources? &&
|
|
133
|
-
!hash.cs__frozen? &&
|
|
134
|
-
key.is_a?(String) &&
|
|
135
|
-
!Contrast::Agent::Assess::Tracker.trackable?(key)
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
# Hash is designed to keep one instance of the string key in it. We need to remove the existing one and
|
|
139
|
-
# replace it with our new tracked one.
|
|
140
|
-
def handle_hash_key target, to_replace
|
|
141
|
-
to_replace.each do |key|
|
|
142
|
-
Contrast::Agent::Assess::Tracker.pre_freeze(key)
|
|
143
|
-
key.cs__freeze
|
|
144
|
-
value = target.delete(key)
|
|
145
|
-
target[key] = value
|
|
146
|
-
end
|
|
147
102
|
end
|
|
148
103
|
|
|
149
104
|
# @param source_node [Contrast::Agent::Assess::Policy::SourceNode] the node to direct applying this source
|
|
@@ -35,6 +35,7 @@ module Contrast
|
|
|
35
35
|
|
|
36
36
|
# Standard validation + TS trace version two rules:
|
|
37
37
|
# Must have source and type
|
|
38
|
+
# @raise[ArgumentError] raises if any of the required fields is missing or invalid
|
|
38
39
|
def validate
|
|
39
40
|
super
|
|
40
41
|
raise(ArgumentError, "Source #{ id } did not have a proper target. Unable to create.") unless targets&.any?
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
require 'contrast/agent/assess/policy/trigger/reflected_xss'
|
|
5
5
|
require 'contrast/agent/assess/policy/trigger/xpath'
|
|
6
6
|
require 'contrast/api/decorators/trace_taint_range_tags'
|
|
7
|
+
require 'contrast/components/logger'
|
|
7
8
|
|
|
8
9
|
module Contrast
|
|
9
10
|
module Agent
|
|
@@ -15,6 +16,8 @@ module Contrast
|
|
|
15
16
|
# vulnerability (indicate points in the application where uncontrolled
|
|
16
17
|
# user input can do damage).
|
|
17
18
|
class TriggerNode < PolicyNode # rubocop:disable Metrics/ClassLength
|
|
19
|
+
include Contrast::Components::Logger::InstanceMethods
|
|
20
|
+
|
|
18
21
|
JSON_BAD_VALUE = 'bad_value'
|
|
19
22
|
JSON_GOOD_VALUE = 'good_value'
|
|
20
23
|
JSON_DISALLOWED_TAGS = 'disallowed_tags'
|
|
@@ -59,6 +62,9 @@ module Contrast
|
|
|
59
62
|
@trigger_method = trigger_hash['trigger_method']
|
|
60
63
|
@trigger_method = @trigger_method.to_sym if @trigger_method
|
|
61
64
|
validate
|
|
65
|
+
rescue ArgumentError => e
|
|
66
|
+
logger.error('Trigger Node initialization failed with: ', e)
|
|
67
|
+
nil
|
|
62
68
|
end
|
|
63
69
|
|
|
64
70
|
def node_class
|
|
@@ -143,6 +149,7 @@ module Contrast
|
|
|
143
149
|
|
|
144
150
|
# Standard validation + TS trace version two rules:
|
|
145
151
|
# Must have source
|
|
152
|
+
# @raise[ArgumentError] raises if any of the required fields is invalid or missing
|
|
146
153
|
def validate
|
|
147
154
|
super
|
|
148
155
|
# If this isn't a dataflow rule, it can't have a source
|
|
@@ -172,6 +179,7 @@ module Contrast
|
|
|
172
179
|
@disallowed_tags << (VALIDATOR_START + loud_name)
|
|
173
180
|
end
|
|
174
181
|
|
|
182
|
+
# @raise[ArgumentError] raises if any of the tags is invalid
|
|
175
183
|
def validate_rule_tags tags
|
|
176
184
|
return unless tags
|
|
177
185
|
|
|
@@ -42,27 +42,13 @@ module Contrast
|
|
|
42
42
|
return unless event.source_type
|
|
43
43
|
return unless (current_request = Contrast::Agent::REQUEST_TRACKER.current)
|
|
44
44
|
|
|
45
|
-
append_to_dtm(current_request, event)
|
|
46
45
|
append_to_ruby_object(current_request, event)
|
|
47
46
|
end
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
source.type == event.forced_source_type &&
|
|
52
|
-
source.name == event.forced_source_name # rubocop:disable Security/Module/Name
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
return
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
event_source_dtm = event.build_event_source_dtm
|
|
59
|
-
return unless event_source_dtm
|
|
60
|
-
|
|
61
|
-
current_request.observed_route.sources << event_source_dtm
|
|
62
|
-
end
|
|
63
|
-
|
|
48
|
+
# @param current_request [Contrast::Agent::RequestContext]
|
|
49
|
+
# @param event [Contrast::Agent::Assess::Events::ContrastEvent]
|
|
64
50
|
def append_to_ruby_object current_request, event
|
|
65
|
-
if current_request.
|
|
51
|
+
if current_request.observed_route.sources.any? do |source|
|
|
66
52
|
source.type == event.forced_source_type &&
|
|
67
53
|
source.name == event.forced_source_name # rubocop:disable Security/Module/Name
|
|
68
54
|
end
|
|
@@ -73,7 +59,7 @@ module Contrast
|
|
|
73
59
|
event_source = event.build_event_source
|
|
74
60
|
return unless event_source
|
|
75
61
|
|
|
76
|
-
current_request.
|
|
62
|
+
current_request.observed_route.sources << event_source
|
|
77
63
|
end
|
|
78
64
|
end
|
|
79
65
|
end
|