contrast-agent 7.4.1 → 7.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/cs__common/cs__common.c +5 -5
- data/ext/cs__contrast_patch/cs__contrast_patch.c +2 -1
- data/ext/cs__scope/cs__scope.c +6 -5
- data/lib/contrast/agent/assess/events/event_data.rb +11 -2
- data/lib/contrast/agent/assess/finalizers/freeze.rb +1 -0
- data/lib/contrast/agent/assess/finalizers/hash.rb +7 -0
- data/lib/contrast/agent/assess/policy/patcher.rb +2 -0
- data/lib/contrast/agent/assess/policy/policy.rb +4 -0
- data/lib/contrast/agent/assess/policy/policy_node.rb +29 -7
- data/lib/contrast/agent/assess/policy/preshift.rb +34 -1
- data/lib/contrast/agent/assess/policy/propagation_method.rb +16 -1
- data/lib/contrast/agent/assess/policy/propagation_node.rb +40 -1
- data/lib/contrast/agent/assess/policy/propagator/append.rb +5 -0
- data/lib/contrast/agent/assess/policy/propagator/base.rb +10 -0
- data/lib/contrast/agent/assess/policy/propagator/buffer.rb +6 -0
- data/lib/contrast/agent/assess/policy/propagator/center.rb +14 -0
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +6 -0
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +14 -0
- data/lib/contrast/agent/assess/policy/propagator/insert.rb +6 -0
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +38 -0
- data/lib/contrast/agent/assess/policy/propagator/next.rb +6 -0
- data/lib/contrast/agent/assess/policy/propagator/prepend.rb +5 -0
- data/lib/contrast/agent/assess/policy/propagator/remove.rb +4 -0
- data/lib/contrast/agent/assess/policy/propagator/replace.rb +5 -0
- data/lib/contrast/agent/assess/policy/propagator/reverse.rb +5 -0
- data/lib/contrast/agent/assess/policy/propagator/select.rb +30 -0
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +10 -0
- data/lib/contrast/agent/assess/policy/source_node.rb +5 -1
- data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +4 -0
- data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +16 -0
- data/lib/contrast/agent/assess/policy/trigger/xpath.rb +19 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +8 -1
- data/lib/contrast/agent/assess/policy/trigger_node.rb +11 -1
- data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +4 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +6 -0
- data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +6 -0
- data/lib/contrast/agent/hooks/at_exit_hook.rb +17 -1
- data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +14 -5
- data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +0 -26
- data/lib/contrast/agent/protect/rule/cmdi/cmd_injection.rb +5 -0
- data/lib/contrast/agent/protect/rule/input_classification/base.rb +1 -4
- data/lib/contrast/agent/protect/rule/input_classification/encoding.rb +34 -2
- data/lib/contrast/agent/reporting/input_analysis/input_type.rb +4 -34
- data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb +4 -4
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +6 -2
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +3 -3
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +19 -7
- data/lib/contrast/agent/request/request_handler.rb +1 -0
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/configuration.rb +1 -1
- data/lib/contrast/utils/json.rb +1 -1
- data/lib/contrast/utils/middleware_utils.rb +9 -0
- data/lib/contrast/utils/routes_sent.rb +3 -2
- data/lib/contrast.rb +2 -2
- data/resources/assess/policy.json +50 -1
- data/ruby-agent.gemspec +14 -13
- metadata +39 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '089a689fce3dfbc204455c12d29788d316553aa3ff6738fcf515e9f90730a7ae'
|
4
|
+
data.tar.gz: 5fc2d10ffc084070fc3c268a9cb05d1f479b48cb16974b2501887cb1b762d6f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d13b3205d1e0cb67c8974fdf6d12f78e5a95f2886c59a14439ddc59b9dd8a3b0d0ebd23c5ebfe687d02cf1a12c9b17b127d821ea8131f0876ab284dac62c8b1b
|
7
|
+
data.tar.gz: 73932d309fafe50ab5bc962655b58306cd5fae6a64729be1a4159274fe39c55c2138027c30525d07f773966476991685ba9b36cd0820527557d417324225af0d
|
data/ext/cs__common/cs__common.c
CHANGED
@@ -28,12 +28,12 @@ void patch_via_funchook(void *original_function, void *hook_function) {
|
|
28
28
|
|
29
29
|
void *funchook_lib_handle;
|
30
30
|
void *funchook_reference, *(*funchook_create)(void);
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
/* This variables are used to load the funchook dylib */
|
32
|
+
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
33
|
+
#pragma GCC diagnostic push
|
34
34
|
int prepareResult, (*funchook_prepare)(void *, void **, void *);
|
35
35
|
int installResult, (*funchook_install)(void *, int);
|
36
|
-
|
36
|
+
#pragma GCC diagnostic pop
|
37
37
|
|
38
38
|
funchook_lib_handle =
|
39
39
|
dlopen(StringValueCStr(funchook_path), RTLD_NOW | RTLD_GLOBAL);
|
@@ -198,7 +198,7 @@ extern VALUE contrast_lookout_prepended(VALUE self, VALUE object_name,
|
|
198
198
|
}
|
199
199
|
|
200
200
|
VALUE _contrast_check_prepended(VALUE object, VALUE method_name,
|
201
|
-
|
201
|
+
VALUE is_instance) {
|
202
202
|
VALUE entry, ancestors, entry_methods;
|
203
203
|
VALUE result = Qfalse;
|
204
204
|
VALUE object_idx = Qnil;
|
@@ -107,7 +107,8 @@ VALUE rescue_func(VALUE arg1) {
|
|
107
107
|
*
|
108
108
|
**/
|
109
109
|
VALUE contrast_patch_call_ensure(const VALUE *args) {
|
110
|
-
/* we do not need to ensure that post patch is called if no error was thrown
|
110
|
+
/* we do not need to ensure that post patch is called if no error was thrown
|
111
|
+
*/
|
111
112
|
if (!RTEST(rb_errinfo())) {
|
112
113
|
return Qnil;
|
113
114
|
}
|
data/ext/cs__scope/cs__scope.c
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
|
4
4
|
#include "cs__scope.h"
|
5
5
|
#include "../cs__common/cs__common.h"
|
6
|
+
#include <pthread.h>
|
6
7
|
#include <ruby.h>
|
7
8
|
#include <stdlib.h>
|
8
|
-
#include <pthread.h>
|
9
9
|
|
10
10
|
/*-----------------------------------------
|
11
11
|
| Calls to Contrast modules and classes
|
@@ -161,8 +161,8 @@ VALUE contrast_scope_application_update() {
|
|
161
161
|
return INT2FIX(env_var_set(eVar));
|
162
162
|
}
|
163
163
|
|
164
|
-
/**
|
165
|
-
* @brief Determines if the Contrast Scope should be set with the Trap Context.
|
164
|
+
/**
|
165
|
+
* @brief Determines if the Contrast Scope should be set with the Trap Context.
|
166
166
|
* @return 1 if set, 0 if not set.
|
167
167
|
*/
|
168
168
|
int contrast_scope_with_trap_context() {
|
@@ -556,7 +556,7 @@ VALUE contrast_scope_for_current_ec(VALUE self, VALUE args) {
|
|
556
556
|
* different thread, at once, but since the mutex stays in
|
557
557
|
* the C API context, this might work fine. Still use only
|
558
558
|
* when unusual conditions are met.
|
559
|
-
*
|
559
|
+
*
|
560
560
|
* In addition we could use C mutex lock just in case. Ruby
|
561
561
|
* Threads under the hood are C threads (pthread), so they
|
562
562
|
* should be treated as such. In theory only one thread can
|
@@ -894,7 +894,8 @@ void Init_cs__scope() {
|
|
894
894
|
rb_const_ec = "EXECUTION_CONTEXT";
|
895
895
|
rb_const_ec_keys = "EC_KEYS";
|
896
896
|
c_const_ctr_agent_app_scope = "CONTRAST__AGENT__RUBY__APPLICATION_SCOPE";
|
897
|
-
c_const_ctr_agent_scope_trap_context =
|
897
|
+
c_const_ctr_agent_scope_trap_context =
|
898
|
+
"CONTRAST__AGENT__SCOPE__WITH_TRAP_CONTEXT";
|
898
899
|
|
899
900
|
/* Symbols */
|
900
901
|
rb_sym_scope_mod = rb_intern("Scope");
|
@@ -5,9 +5,18 @@ module Contrast
|
|
5
5
|
module Agent
|
6
6
|
module Assess
|
7
7
|
module Events
|
8
|
-
# this class will gather and build event
|
8
|
+
# this class will gather and build event.
|
9
9
|
class EventData
|
10
|
-
|
10
|
+
# @return [Contrast::Agent::Assess::Policy::PolicyNode, nil] the node that governs this event.
|
11
|
+
attr_reader :policy_node
|
12
|
+
# @return [Object, nil] the Target to which this event pertains.
|
13
|
+
attr_reader :tagged
|
14
|
+
# @return [Object, nil] the Object on which the method was invoked.
|
15
|
+
attr_reader :object
|
16
|
+
# @return [Object, nil] the Return of the invoked method.
|
17
|
+
attr_reader :ret
|
18
|
+
# @return [Array<Object>, nil] the Arguments with which the method was invoked.
|
19
|
+
attr_reader :args
|
11
20
|
|
12
21
|
# Group event data together
|
13
22
|
#
|
@@ -8,6 +8,7 @@ require 'contrast/agent/assess/tracker'
|
|
8
8
|
class Object
|
9
9
|
alias_method :cs__patched_object_freeze, :freeze
|
10
10
|
|
11
|
+
# Applies the the freeze patch and handles the pre-finalizes the object.
|
11
12
|
def freeze
|
12
13
|
Contrast::Agent::Assess::Tracker.pre_freeze(self)
|
13
14
|
cs__patched_object_freeze
|
@@ -16,6 +16,10 @@ module Contrast
|
|
16
16
|
FROZEN_FINALIZED_IDS = Set.new
|
17
17
|
KEEP_AGE = 600_000.cs__freeze # 10 minutes
|
18
18
|
|
19
|
+
# Store the given Object in the Hash, using its __id__ as the key. If the Object is frozen, we need to
|
20
|
+
# pre-finalize it and store its __id__ in our tracking Set.
|
21
|
+
#
|
22
|
+
# @return [Object] the Object stored
|
19
23
|
def []= key, obj
|
20
24
|
return unless obj
|
21
25
|
return unless ::Contrast::AGENT.enabled? && ::Contrast::ASSESS.enabled?
|
@@ -29,6 +33,9 @@ module Contrast
|
|
29
33
|
super(key.__id__, obj)
|
30
34
|
end
|
31
35
|
|
36
|
+
# Retrieves the Object stored in the Hash by its __id__.
|
37
|
+
#
|
38
|
+
# @return [Object, nil] the Object stored.
|
32
39
|
def [] key
|
33
40
|
super(key.__id__)
|
34
41
|
end
|
@@ -34,6 +34,8 @@ module Contrast
|
|
34
34
|
# load. These methods only exist once a module or class eval has been
|
35
35
|
# called. This hook is provided so that patches to those methods can
|
36
36
|
# pass us execution flow once a new method has been made available.
|
37
|
+
#
|
38
|
+
# @param mod [Module]
|
37
39
|
def patch_assess_on_eval mod
|
38
40
|
return unless ::Contrast::ASSESS.enabled?
|
39
41
|
return if in_contrast_scope?
|
@@ -34,6 +34,8 @@ module Contrast
|
|
34
34
|
|
35
35
|
# Indicates is this feature has been disabled by the configuration,
|
36
36
|
# read at startup, and therefore can never be enabled.
|
37
|
+
#
|
38
|
+
# @return [Boolean] if this feature is disabled
|
37
39
|
def disabled_globally?
|
38
40
|
::Contrast::ASSESS.forcibly_disabled?
|
39
41
|
end
|
@@ -49,6 +51,8 @@ module Contrast
|
|
49
51
|
# This let's us be flexible and extensible
|
50
52
|
# * when we want to do lvl 2 rules, we could have the customers unzip
|
51
53
|
# our gem, insert things into the json, zip, and go *
|
54
|
+
#
|
55
|
+
# @param string [String]
|
52
56
|
def from_hash_string string
|
53
57
|
# The default behavior of the agent is to load the policy on startup,
|
54
58
|
# as at this point we do not know in which mode we'll be run.
|
@@ -26,8 +26,17 @@ module Contrast
|
|
26
26
|
JSON_TARGET = 'target'
|
27
27
|
TO_MARKER = '2'
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
# @return [Set<String>]
|
30
|
+
attr_accessor :tags
|
31
|
+
# @return [Symbol]
|
32
|
+
attr_accessor :type
|
33
|
+
attr_reader :sources
|
34
|
+
# @return [Array<String>]
|
35
|
+
attr_reader :targets
|
36
|
+
# @return [String]
|
37
|
+
attr_reader :source_string
|
38
|
+
# @return [String]
|
39
|
+
attr_reader :target_string
|
31
40
|
|
32
41
|
# Here are all methods that can use original objects without mutation the source.
|
33
42
|
# For methods with REMOVE action, their (!) bang alternative is not listed, since
|
@@ -68,6 +77,8 @@ module Contrast
|
|
68
77
|
# String#to_s => self or string. This method is included here to cover the situations such as
|
69
78
|
# String.to_s.html_safe, where normally the dynamic sources properties get lost. To solve this
|
70
79
|
# we will simply return the original object here.
|
80
|
+
#
|
81
|
+
# @param policy_hash [Hash]
|
71
82
|
def assign_on_bang_check policy_hash
|
72
83
|
return true if @_use_original_object && TO_S.include?(policy_hash[JSON_METHOD_NAME])
|
73
84
|
|
@@ -76,18 +87,24 @@ module Contrast
|
|
76
87
|
policy_hash[JSON_METHOD_NAME].end_with?(Contrast::Utils::ObjectShare::BANG)
|
77
88
|
end
|
78
89
|
|
90
|
+
# @return [String]
|
79
91
|
def feature
|
80
92
|
'Assess'
|
81
93
|
end
|
82
94
|
|
95
|
+
# @return [String]
|
83
96
|
def node_class
|
84
97
|
'Node'
|
85
98
|
end
|
86
99
|
|
100
|
+
# @return [Symbol]
|
87
101
|
def node_type
|
88
102
|
:TYPE_METHOD
|
89
103
|
end
|
90
104
|
|
105
|
+
# Set the target string.
|
106
|
+
#
|
107
|
+
# @param value [String]
|
91
108
|
def target_string= value
|
92
109
|
@target_string = value
|
93
110
|
@targets = convert_policy_markers(value)
|
@@ -96,6 +113,9 @@ module Contrast
|
|
96
113
|
# Sometimes we need to tie information to an event. We'll add a
|
97
114
|
# properties section to the patch node, which can pass them along to
|
98
115
|
# the pre-dtm event
|
116
|
+
#
|
117
|
+
# @param name [String]
|
118
|
+
# @param value [String]
|
99
119
|
def add_property name, value
|
100
120
|
return unless name && value
|
101
121
|
|
@@ -103,6 +123,8 @@ module Contrast
|
|
103
123
|
@properties[name] = value
|
104
124
|
end
|
105
125
|
|
126
|
+
# @param name [String]
|
127
|
+
# @return [String]
|
106
128
|
def get_property name
|
107
129
|
return unless @properties
|
108
130
|
|
@@ -112,6 +134,8 @@ module Contrast
|
|
112
134
|
# Don't let nodes be created that will be missing things we need
|
113
135
|
# later on. Really, if they don't have these things, they couldn't have
|
114
136
|
# done their jobs anyway.
|
137
|
+
#
|
138
|
+
# @raise [ArgumentError] raises if the node is invalid.
|
115
139
|
def validate
|
116
140
|
super
|
117
141
|
validate_tags
|
@@ -124,11 +148,10 @@ module Contrast
|
|
124
148
|
# isn't a matching ENUM in TS land, the database gets got. We really
|
125
149
|
# don't want to get them, so we're going to prevent the node from being
|
126
150
|
# made.
|
151
|
+
#
|
127
152
|
# @raise[ArgumentError] raises if any of the tags is invalid
|
128
153
|
def validate_tags
|
129
|
-
|
130
|
-
|
131
|
-
tags.each do |tag|
|
154
|
+
tags&.each do |tag|
|
132
155
|
next if Contrast::Agent::Reporting::FindingEventTaintRangeTags::VALID_TAGS.include?(tag) ||
|
133
156
|
Contrast::Agent::Reporting::FindingEventTaintRangeTags::VALID_SOURCE_TAGS.include?(tag)
|
134
157
|
|
@@ -159,8 +182,7 @@ module Contrast
|
|
159
182
|
# by changing them to 'A'
|
160
183
|
source = all_type?(source_string) ? ALL_TYPE : source_string
|
161
184
|
target = all_type?(target_string) ? ALL_TYPE : target_string
|
162
|
-
|
163
|
-
str.to_sym
|
185
|
+
(source[0] + TO_MARKER + target[0]).to_sym
|
164
186
|
end
|
165
187
|
end
|
166
188
|
|
@@ -21,7 +21,15 @@ module Contrast
|
|
21
21
|
UNDUPLICABLE_MODULES << IO::Buffer if RUBY_VERSION >= '3.1.0'
|
22
22
|
UNDUPLICABLE_MODULES.cs__freeze
|
23
23
|
|
24
|
-
|
24
|
+
# @return [Object] the object on which the method is to be called.
|
25
|
+
attr_accessor :object
|
26
|
+
# @return [Integer] the length of the object on which the method is to
|
27
|
+
# be called.
|
28
|
+
attr_accessor :object_length
|
29
|
+
# @return [Array<Object>] the arguments to be passed to the method.
|
30
|
+
attr_accessor :args
|
31
|
+
# @return [Array<Integer>] the lengths of the arguments to be passed to
|
32
|
+
attr_accessor :arg_lengths
|
25
33
|
|
26
34
|
class << self
|
27
35
|
# Save the state before we do the propagation. This is one of the
|
@@ -65,10 +73,23 @@ module Contrast
|
|
65
73
|
|
66
74
|
private
|
67
75
|
|
76
|
+
# Determine if the given object is an IO object that is closed, not in
|
77
|
+
# initialization, and therefore unsafe to use.
|
78
|
+
#
|
79
|
+
# @param object [Object] the object on which the method is to be
|
80
|
+
# called.
|
81
|
+
# @param initializing [Boolean] whether or not the method being
|
82
|
+
# called is the initialize method.
|
68
83
|
def unsafe_io_object? object, initializing
|
69
84
|
Contrast::Utils::DuckUtils.closable_io?(object) && !initializing && object.closed?
|
70
85
|
end
|
71
86
|
|
87
|
+
# check if object is duplicable
|
88
|
+
#
|
89
|
+
# @param initializing [Boolean] whether or not the method being
|
90
|
+
# called is the initialize method.
|
91
|
+
# @param object [Object] the object on which the method is to be
|
92
|
+
# called.
|
72
93
|
def can_dup? initializing, object
|
73
94
|
return false if initializing
|
74
95
|
|
@@ -76,6 +97,14 @@ module Contrast
|
|
76
97
|
!UNDUPLICABLE_MODULES.include?(check)
|
77
98
|
end
|
78
99
|
|
100
|
+
# Appends the object details to the given preshift and adds it to the LRU cache.
|
101
|
+
#
|
102
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] the preshift to
|
103
|
+
# which the object details should be appended.
|
104
|
+
# @param initializing [Boolean] whether or not the method being
|
105
|
+
# called is the initialize method.
|
106
|
+
# @param object [Object] the object on which the method is to be
|
107
|
+
# called.
|
79
108
|
def append_object_details preshift, initializing, object
|
80
109
|
can = can_dup?(initializing, object)
|
81
110
|
preshift.object = if @lru_cache.key?(object.__id__) && !Contrast::Agent::Assess::Tracker.tracked?(object)
|
@@ -97,6 +126,10 @@ module Contrast
|
|
97
126
|
@lru_cache[object.__id__] = object
|
98
127
|
end
|
99
128
|
|
129
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] the preshift to
|
130
|
+
# which the argument details should be appended.
|
131
|
+
# @param args [Array<Object>] the arguments to be passed to the
|
132
|
+
# method.
|
100
133
|
def append_arg_details preshift, args
|
101
134
|
args_length = args.length
|
102
135
|
preshift.args = Array.new(args_length)
|
@@ -88,6 +88,7 @@ module Contrast
|
|
88
88
|
end
|
89
89
|
|
90
90
|
# If this patcher has tags, apply them to the entire target
|
91
|
+
#
|
91
92
|
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
92
93
|
# propagation event.
|
93
94
|
# @param target [Object] the Target to which to propagate.
|
@@ -101,6 +102,9 @@ module Contrast
|
|
101
102
|
end
|
102
103
|
end
|
103
104
|
|
105
|
+
# Checks to see if the given target is valid for propagation.
|
106
|
+
#
|
107
|
+
# @return [Bool]
|
104
108
|
def context_available?
|
105
109
|
!!Contrast::Agent::REQUEST_TRACKER.current
|
106
110
|
end
|
@@ -121,7 +125,8 @@ module Contrast
|
|
121
125
|
|
122
126
|
private
|
123
127
|
|
124
|
-
# This is checked right before actual propagation
|
128
|
+
# This is checked right before actual propagation.
|
129
|
+
#
|
125
130
|
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
126
131
|
# propagation event.
|
127
132
|
# @param target [Object] the Target to which to propagate.
|
@@ -198,6 +203,10 @@ module Contrast
|
|
198
203
|
increment_event_count(propagation_node)
|
199
204
|
end
|
200
205
|
|
206
|
+
# @param propagation_class [Contrast::Agent::Assess::Policy::Propagator]
|
207
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
|
208
|
+
# @param source [Object] The object from which the propagation begins.
|
209
|
+
# @param target [Object] the Target to which to propagate.
|
201
210
|
def handle_propagation propagation_class, propagation_node, source, target
|
202
211
|
if propagation_node.patch_method
|
203
212
|
propagation_class.send(propagation_node.patch_method, propagation_node, source, target)
|
@@ -206,6 +215,12 @@ module Contrast
|
|
206
215
|
end
|
207
216
|
end
|
208
217
|
|
218
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
|
219
|
+
# @param target [Object] the Target to which to propagate.
|
220
|
+
# @param propagation_data [Contrast::Agent::Assess::Events::EventData] this will hold the
|
221
|
+
# object [Object] the Object on which the method was invoked
|
222
|
+
# ret [Object] the Return of the invoked method
|
223
|
+
# args [Array<Object>] the Arguments with which the method was invoked
|
209
224
|
def update_properties propagation_node, target, propagation_data
|
210
225
|
if propagation_node.use_original_on_bang_method?
|
211
226
|
properties = use_original_object_properties(propagation_data)
|
@@ -22,7 +22,34 @@ module Contrast
|
|
22
22
|
JSON_PATCH_CLASS = 'patch_class'
|
23
23
|
JSON_PATCH_METHOD = 'patch_method'
|
24
24
|
|
25
|
-
|
25
|
+
# @return action [String] the action to be taken by this propagation
|
26
|
+
# node. This can be one of the following:
|
27
|
+
# - 'CUSTOM' - the propagation node is a custom propagation node
|
28
|
+
# - 'DB_WRITE' - the propagation node is a database write propagation
|
29
|
+
# node
|
30
|
+
# - 'APPEND' - the propagation node is an append propagation node
|
31
|
+
# - 'CENTER' - the propagation node is a center propagation node
|
32
|
+
# - 'INSERT' - the propagation node is an insert propagation node
|
33
|
+
# - 'KEEP' - the propagation node is a keep propagation node
|
34
|
+
# - 'NEXT' - the propagation node is a next propagation node
|
35
|
+
# - 'BUFFER' - the propagation node is a buffer propagation node
|
36
|
+
# - 'NOOP' - the propagation node is a noop propagation node
|
37
|
+
# - 'PREPEND' - the propagation node is a prepend propagation node
|
38
|
+
# - 'REPLACE' - the propagation node is a replace propagation node
|
39
|
+
# - 'REMOVE' - the propagation node is a remove propagation node
|
40
|
+
# - 'REVERSE' - the propagation node is a reverse propagation node
|
41
|
+
# - 'RESPONSE' - the propagation node is a response propagation node
|
42
|
+
# - 'SPLAT' - the propagation node is a splat propagation node
|
43
|
+
# - 'SPLIT' - the propagation node is a split propagation node
|
44
|
+
attr_reader :action
|
45
|
+
# @return untags [Array<String>] the tags to be removed from the
|
46
|
+
# target of this propagation node.
|
47
|
+
attr_reader :untags
|
48
|
+
# @return patch_class [String] the class name of the class that
|
49
|
+
# contains the method to be called for this propagation node.
|
50
|
+
attr_reader :patch_method
|
51
|
+
# @return patch_method [Symbol] the name of the method to be called
|
52
|
+
# for this propagation node.
|
26
53
|
attr_accessor :patch_class
|
27
54
|
|
28
55
|
TAGGER = 'Tagger'
|
@@ -36,6 +63,9 @@ module Contrast
|
|
36
63
|
# Tags - array of tags to apply to the target, can be nil if no tags are added
|
37
64
|
# Untags - array of tags to remove from the target, can be nil if not tags are removed
|
38
65
|
# id, class_name, instance_method, method_name, source, target, action, tags = nil, untags = nil
|
66
|
+
#
|
67
|
+
# @param propagation_hash [Hash] the hash from which to build the
|
68
|
+
# propagation node.
|
39
69
|
def initialize propagation_hash = {}
|
40
70
|
super(propagation_hash)
|
41
71
|
@action = propagation_hash[JSON_ACTION]
|
@@ -49,6 +79,7 @@ module Contrast
|
|
49
79
|
nil
|
50
80
|
end
|
51
81
|
|
82
|
+
# @return [String] class name
|
52
83
|
def node_class
|
53
84
|
@_node_class ||= tagger? ? TAGGER : PROPAGATOR
|
54
85
|
end
|
@@ -56,12 +87,15 @@ module Contrast
|
|
56
87
|
# Unlike the other agents, we don't have separate tag & propagation
|
57
88
|
# events. To make TS happy, we need to have different types though.
|
58
89
|
# Pretty straight forward: if there's a tag, this is a tagger
|
90
|
+
#
|
91
|
+
# @return [Symbol] the type of node.
|
59
92
|
def node_type
|
60
93
|
tagger? ? :TYPE_TAG : :TYPE_PROPAGATION
|
61
94
|
end
|
62
95
|
|
63
96
|
# Standard validation + TS trace version two rules:
|
64
97
|
# Must have source, target, and action
|
98
|
+
#
|
65
99
|
# @raise[ArgumentError] raises if any of the required propagation node field is not valid, or is missing
|
66
100
|
def validate
|
67
101
|
super
|
@@ -100,6 +134,8 @@ module Contrast
|
|
100
134
|
end
|
101
135
|
end
|
102
136
|
|
137
|
+
# @return [Boolean]
|
138
|
+
# propagation node.
|
103
139
|
def needs_object?
|
104
140
|
if @_needs_object.nil?
|
105
141
|
@_needs_object = action == Contrast::Utils::Assess::PropagationMethodUtils::CUSTOM_ACTION ||
|
@@ -110,6 +146,7 @@ module Contrast
|
|
110
146
|
@_needs_object
|
111
147
|
end
|
112
148
|
|
149
|
+
# @return [Boolean]
|
113
150
|
def needs_args?
|
114
151
|
if @_needs_args.nil?
|
115
152
|
@_needs_args = action == Contrast::Utils::Assess::PropagationMethodUtils::CUSTOM_ACTION ||
|
@@ -124,6 +161,8 @@ module Contrast
|
|
124
161
|
# It indicates this method is more than just a transformation,
|
125
162
|
# it is an interesting security event that has a meaningful
|
126
163
|
# change.
|
164
|
+
#
|
165
|
+
# @return [Boolean]
|
127
166
|
def tagger?
|
128
167
|
@_tagger = tags&.any? || untags&.any? if @_tagger.nil?
|
129
168
|
@_tagger
|
@@ -15,6 +15,11 @@ module Contrast
|
|
15
15
|
# if the target length is greater than the source
|
16
16
|
# copy tags from the param to the target in chunks of param size or less
|
17
17
|
# if param is appended in space less than param length
|
18
|
+
#
|
19
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
|
20
|
+
# propagation action required by this method.
|
21
|
+
# @param preshift [Object] pre call state of the things.
|
22
|
+
# @param target [Object] the object to which the source is being appended
|
18
23
|
def propagate propagation_node, preshift, target
|
19
24
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
|
20
25
|
|
@@ -12,6 +12,10 @@ module Contrast
|
|
12
12
|
# to pass tags from it to a Target.
|
13
13
|
class Base
|
14
14
|
class << self
|
15
|
+
# Retrieve the source from the preshift state.
|
16
|
+
#
|
17
|
+
# @param source [Symbol] the source to retrieve.
|
18
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] the pre-call state of the things.
|
15
19
|
def find_source source, preshift
|
16
20
|
case source
|
17
21
|
when Contrast::Utils::ObjectShare::OBJECT_KEY
|
@@ -21,10 +25,16 @@ module Contrast
|
|
21
25
|
end
|
22
26
|
end
|
23
27
|
|
28
|
+
# Check if tags are present on the given target.
|
29
|
+
#
|
30
|
+
# @return [Boolean]
|
24
31
|
def tracked_value? value
|
25
32
|
Contrast::Agent::Assess::Tracker.tracked?(value)
|
26
33
|
end
|
27
34
|
|
35
|
+
# Propagate the tags from the source to the target.
|
36
|
+
# This method should be extended by the subclasses.
|
37
|
+
#
|
28
38
|
# @raise [NoMethodError] This is being raised if any of the implementing subclasses does not have
|
29
39
|
# that method implemented, but is being called on.
|
30
40
|
def propagate _propagation_node, _preshift, _target
|
@@ -17,6 +17,12 @@ module Contrast
|
|
17
17
|
# Once the tag is applied, shift it to the location of the insert
|
18
18
|
# Unlike additive propagation, this currently only supports one source
|
19
19
|
# We assume that insert changes the preshift target
|
20
|
+
#
|
21
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
|
22
|
+
# propagation action required by this method.
|
23
|
+
# @param preshift [Object] pre call state of the things.
|
24
|
+
# @param target [Object] the object to which the source is being appended
|
25
|
+
# @return [Object] the target with the tags applied
|
20
26
|
def propagate_insert propagation_node, preshift, target
|
21
27
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
|
22
28
|
|
@@ -11,6 +11,11 @@ module Contrast
|
|
11
11
|
# are unaffected beyond any merging of overlapping tags.
|
12
12
|
class Center < Contrast::Agent::Assess::Policy::Propagator::Base
|
13
13
|
class << self
|
14
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
|
15
|
+
# propagation action required by this method.
|
16
|
+
# @param preshift [Object] pre call state of the things.
|
17
|
+
# @param target [Object] the object to which the source is being appended
|
18
|
+
# @return [Object] the target with the tags applied
|
14
19
|
def propagate propagation_node, preshift, target
|
15
20
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
|
16
21
|
|
@@ -56,6 +61,15 @@ module Contrast
|
|
56
61
|
iterate_tags(target, propagation_node, source, end_index, target.length)
|
57
62
|
end
|
58
63
|
|
64
|
+
# This method will iterate over the tags of the source and apply
|
65
|
+
# them to the target.
|
66
|
+
#
|
67
|
+
# @param target [Object] the thing to apply tags to.
|
68
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
|
69
|
+
# the node that indicates how this propagation should be handled.
|
70
|
+
# @param source [Object] the thing to copy tags from.
|
71
|
+
# @param start [Integer] where to start copying tags from.
|
72
|
+
# @param stop [Integer] where to stop copying tags from.
|
59
73
|
def iterate_tags target, propagation_node, source, start, stop
|
60
74
|
properties = Contrast::Agent::Assess::Tracker.properties(target)
|
61
75
|
while start < stop
|
@@ -17,6 +17,12 @@ module Contrast
|
|
17
17
|
extend Contrast::Utils::Assess::EventLimitUtils
|
18
18
|
|
19
19
|
class << self
|
20
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
|
21
|
+
# propagation action required by this method.
|
22
|
+
# @param preshift [Object] pre call state of the things.
|
23
|
+
# @param ret [Object] the return value of the method.
|
24
|
+
# @param block [Proc] the block passed to the method.
|
25
|
+
# @return [Object] the return value of the method.
|
20
26
|
def propagate propagation_node, preshift, ret, block
|
21
27
|
clazz = propagation_node.patch_class
|
22
28
|
method = propagation_node.patch_method
|
@@ -16,6 +16,11 @@ module Contrast
|
|
16
16
|
extend Contrast::Utils::Assess::EventLimitUtils
|
17
17
|
|
18
18
|
class << self
|
19
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
|
20
|
+
# propagation action required by this method.
|
21
|
+
# @param preshift [Object] pre call state of the things.
|
22
|
+
# @param target [Object] the object to which the source is being appended
|
23
|
+
# @return [Object] the target with the tags applied
|
19
24
|
def propagate propagation_node, preshift, target
|
20
25
|
return unless Contrast::ASSESS.require_dynamic_sources?
|
21
26
|
|
@@ -41,6 +46,15 @@ module Contrast
|
|
41
46
|
|
42
47
|
private
|
43
48
|
|
49
|
+
# Handles the write propagation for the given source.
|
50
|
+
#
|
51
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
|
52
|
+
# propagation action required by this method.
|
53
|
+
# @param source [Symbol] the source to retrieve.
|
54
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] the pre-call state of the things.
|
55
|
+
# @param target [Object] the object to which the source is being appended
|
56
|
+
# @param known_tainted [Array] the list of known tainted columns
|
57
|
+
# @param tainted_columns [Hash] the hash of tainted columns
|
44
58
|
def handle_write propagation_node, source, preshift, target, known_tainted, tainted_columns
|
45
59
|
arg = preshift.args[source]
|
46
60
|
return unless arg.cs__respond_to?(:each_pair)
|
@@ -15,6 +15,12 @@ module Contrast
|
|
15
15
|
# Once the tag is applied, shift it to the location of the insert
|
16
16
|
# Unlike additive propagation, this currently only supports one source
|
17
17
|
# We assume that insert changes the preshift target
|
18
|
+
#
|
19
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the
|
20
|
+
# propagation action required by this method.
|
21
|
+
# @param preshift [Object] pre call state of the things.
|
22
|
+
# @param target [Object] the object to which the source is being appended
|
23
|
+
# @return [Object] the target with the tags applied
|
18
24
|
def propagate propagation_node, preshift, target
|
19
25
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
|
20
26
|
|