tcell_agent 0.2.29 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Readme.txt +7 -0
- data/bin/tcell_agent +9 -0
- data/lib/tcell_agent/agent/policy_manager.rb +3 -0
- data/lib/tcell_agent/agent/policy_types.rb +4 -1
- data/lib/tcell_agent/appsensor/injections_matcher.rb +20 -0
- data/lib/tcell_agent/appsensor/injections_reporter.rb +15 -56
- data/lib/tcell_agent/appsensor/meta_data.rb +56 -2
- data/lib/tcell_agent/appsensor/rules/baserules.json +371 -138
- data/lib/tcell_agent/cmdi.rb +113 -0
- data/lib/tcell_agent/config/unknown_options.rb +2 -0
- data/lib/tcell_agent/configuration.rb +30 -16
- data/lib/tcell_agent/hooks/login_fraud.rb +79 -0
- data/lib/tcell_agent/instrumentation.rb +6 -11
- data/lib/tcell_agent/patches/meta_data.rb +14 -11
- data/lib/tcell_agent/policies/appsensor/injection_sensor.rb +5 -9
- data/lib/tcell_agent/policies/appsensor_policy.rb +22 -206
- data/lib/tcell_agent/policies/clickjacking_policy.rb +4 -2
- data/lib/tcell_agent/policies/command_injection_policy.rb +196 -0
- data/lib/tcell_agent/policies/content_security_policy.rb +3 -2
- data/lib/tcell_agent/policies/dataloss_policy.rb +3 -1
- data/lib/tcell_agent/policies/honeytokens_policy.rb +3 -1
- data/lib/tcell_agent/policies/http_redirect_policy.rb +51 -37
- data/lib/tcell_agent/policies/http_tx_policy.rb +5 -1
- data/lib/tcell_agent/policies/login_fraud_policy.rb +6 -1
- data/lib/tcell_agent/policies/patches_policy.rb +3 -1
- data/lib/tcell_agent/policies/policy.rb +10 -0
- data/lib/tcell_agent/policies/secure_headers_policy.rb +5 -2
- data/lib/tcell_agent/rails/auth/devise.rb +12 -23
- data/lib/tcell_agent/rails/csrf_exception.rb +1 -1
- data/lib/tcell_agent/rails/dlp.rb +50 -54
- data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +0 -1
- data/lib/tcell_agent/rails/middleware/context_middleware.rb +0 -1
- data/lib/tcell_agent/rails/middleware/global_middleware.rb +0 -1
- data/lib/tcell_agent/rails/middleware/headers_middleware.rb +7 -10
- data/lib/tcell_agent/rails/on_start.rb +0 -1
- data/lib/tcell_agent/rails/tcell_body_proxy.rb +4 -4
- data/lib/tcell_agent/rails.rb +0 -2
- data/lib/tcell_agent/rust/libtcellagent-0.6.1.dylib +0 -0
- data/lib/tcell_agent/rust/libtcellagent-0.6.1.so +0 -0
- data/lib/tcell_agent/rust/models.rb +61 -0
- data/lib/tcell_agent/rust/tcellagent-0.6.1.dll +0 -0
- data/lib/tcell_agent/rust/whisperer.rb +112 -0
- data/lib/tcell_agent/sensor_events/appsensor_event.rb +25 -21
- data/lib/tcell_agent/sensor_events/appsensor_meta_event.rb +31 -24
- data/lib/tcell_agent/sensor_events/command_injection.rb +58 -0
- data/lib/tcell_agent/sensor_events/discovery.rb +1 -1
- data/lib/tcell_agent/sensor_events/login_fraud.rb +3 -13
- data/lib/tcell_agent/sensor_events/sensor.rb +81 -77
- data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +8 -0
- data/lib/tcell_agent/start_background_thread.rb +12 -3
- data/lib/tcell_agent/utils/io.rb +4 -1
- data/lib/tcell_agent/utils/params.rb +1 -0
- data/lib/tcell_agent/version.rb +1 -1
- data/lib/tcell_agent.rb +0 -1
- data/spec/lib/tcell_agent/appsensor/injections_matcher_spec.rb +27 -9
- data/spec/lib/tcell_agent/appsensor/injections_reporter_spec.rb +143 -193
- data/spec/lib/tcell_agent/appsensor/meta_data_spec.rb +67 -0
- data/spec/lib/tcell_agent/appsensor/rules/appsensor_rule_manager_spec.rb +0 -10
- data/spec/lib/tcell_agent/cmdi_spec.rb +748 -0
- data/spec/lib/tcell_agent/config/unknown_options_spec.rb +8 -0
- data/spec/lib/tcell_agent/configuration_spec.rb +138 -6
- data/spec/lib/tcell_agent/hooks/login_fraud_spec.rb +357 -0
- data/spec/lib/tcell_agent/patches/block_rule_spec.rb +70 -87
- data/spec/lib/tcell_agent/patches_spec.rb +9 -4
- data/spec/lib/tcell_agent/policies/appsensor/xss_sensor_spec.rb +186 -9
- data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +309 -484
- data/spec/lib/tcell_agent/policies/command_injection_policy_spec.rb +736 -0
- data/spec/lib/tcell_agent/policies/http_redirect_policy_spec.rb +222 -41
- data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +56 -32
- data/spec/lib/tcell_agent/rails/middleware/appsensor_middleware_spec.rb +161 -85
- data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +40 -72
- data/spec/lib/tcell_agent/rust/whisperer_spec.rb +267 -0
- data/spec/lib/tcell_agent/sensor_events/appsensor_meta_event_spec.rb +20 -15
- data/spec/spec_helper.rb +0 -9
- data/tcell_agent.gemspec +8 -3
- metadata +40 -39
- data/lib/tcell_agent/appsensor/sensor.rb +0 -52
- data/lib/tcell_agent/policies/appsensor/database_sensor.rb +0 -56
- data/lib/tcell_agent/policies/appsensor/misc_sensor.rb +0 -59
- data/lib/tcell_agent/policies/appsensor/payloads_policy.rb +0 -150
- data/lib/tcell_agent/policies/appsensor/request_size_sensor.rb +0 -25
- data/lib/tcell_agent/policies/appsensor/response_codes_sensor.rb +0 -73
- data/lib/tcell_agent/policies/appsensor/response_size_sensor.rb +0 -25
- data/lib/tcell_agent/policies/appsensor/size_sensor.rb +0 -71
- data/lib/tcell_agent/policies/appsensor/user_agent_sensor.rb +0 -47
- data/lib/tcell_agent/rails/auth/hooks.rb +0 -79
- data/lib/tcell_agent/sensor_events/util/redirect_utils.rb +0 -22
- data/spec/lib/tcell_agent/policies/appsensor/database_sensor_spec.rb +0 -165
- data/spec/lib/tcell_agent/policies/appsensor/misc_sensor_spec.rb +0 -429
- data/spec/lib/tcell_agent/policies/appsensor/payloads_policy_apply_spec.rb +0 -466
- data/spec/lib/tcell_agent/policies/appsensor/payloads_policy_from_json_spec.rb +0 -890
- data/spec/lib/tcell_agent/policies/appsensor/payloads_policy_log_spec.rb +0 -417
- data/spec/lib/tcell_agent/policies/appsensor/request_size_sensor_spec.rb +0 -236
- data/spec/lib/tcell_agent/policies/appsensor/response_codes_sensor_spec.rb +0 -297
- data/spec/lib/tcell_agent/policies/appsensor/response_size_sensor_spec.rb +0 -241
- data/spec/lib/tcell_agent/policies/appsensor/user_agent_sensor_spec.rb +0 -172
- data/spec/lib/tcell_agent/rails/auth/hooks_spec.rb +0 -246
- data/spec/lib/tcell_agent/sensor_events/util/redirect_utils_spec.rb +0 -25
- data/spec/support/resources/baserules.json +0 -155
@@ -1,231 +1,47 @@
|
|
1
1
|
require 'tcell_agent/instrumentation'
|
2
2
|
require 'tcell_agent/appsensor/injections_reporter'
|
3
|
-
require 'tcell_agent/
|
4
|
-
require 'tcell_agent/
|
5
|
-
require 'tcell_agent/policies/
|
6
|
-
require 'tcell_agent/policies/appsensor/misc_sensor'
|
7
|
-
require 'tcell_agent/policies/appsensor/nullbyte_sensor'
|
8
|
-
require 'tcell_agent/policies/appsensor/payloads_policy'
|
9
|
-
require 'tcell_agent/policies/appsensor/request_size_sensor'
|
10
|
-
require 'tcell_agent/policies/appsensor/response_codes_sensor'
|
11
|
-
require 'tcell_agent/policies/appsensor/response_size_sensor'
|
12
|
-
require 'tcell_agent/policies/appsensor/retr_sensor'
|
13
|
-
require 'tcell_agent/policies/appsensor/sqli_sensor'
|
14
|
-
require 'tcell_agent/policies/appsensor/user_agent_sensor'
|
15
|
-
require 'tcell_agent/policies/appsensor/xss_sensor'
|
16
|
-
require 'tcell_agent/utils/params'
|
3
|
+
require 'tcell_agent/rust/models'
|
4
|
+
require 'tcell_agent/rust/whisperer'
|
5
|
+
require 'tcell_agent/policies/policy'
|
17
6
|
|
18
7
|
|
19
8
|
module TCellAgent
|
20
9
|
module Policies
|
21
10
|
|
22
|
-
class AppSensorPolicy
|
23
|
-
|
24
|
-
"req_res_size",
|
25
|
-
"resp_codes",
|
26
|
-
"ua",
|
27
|
-
"errors",
|
28
|
-
"database"]
|
11
|
+
class AppSensorPolicy < Policy
|
12
|
+
attr_reader :appfirewall_enabled, :appfirewall_ptr
|
29
13
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
"resp_codes" => ResponseCodesSensor,
|
34
|
-
"xss" => XssSensor,
|
35
|
-
"sqli" => SqliSensor,
|
36
|
-
"cmdi" => CmdiSensor,
|
37
|
-
"fpt" => FptSensor,
|
38
|
-
"nullbyte" => NullbyteSensor,
|
39
|
-
"retr" => RetrSensor,
|
40
|
-
"ua" => UserAgentSensor,
|
41
|
-
"errors" => MiscSensor,
|
42
|
-
"database" => DatabaseSensor
|
43
|
-
}
|
44
|
-
|
45
|
-
DETECTION_POINTS_V2_NON_INJECTION = {
|
46
|
-
"req_size" => RequestSizeSensor,
|
47
|
-
"resp_size" => ResponseSizeSensor,
|
48
|
-
"resp_codes" => ResponseCodesSensor,
|
49
|
-
"ua" => UserAgentSensor,
|
50
|
-
"errors" => MiscSensor,
|
51
|
-
"database" => DatabaseSensor
|
52
|
-
}
|
53
|
-
|
54
|
-
attr_accessor :policy_id, :options, :enabled, :injections_reporter
|
55
|
-
|
56
|
-
def initialize
|
57
|
-
@policy_id = nil
|
58
|
-
@options = Hash.new
|
59
|
-
@enabled = false
|
60
|
-
@injections_reporter =
|
61
|
-
TCellAgent::AppSensor::InjectionsReporter.from_json(0, {}, PayloadsPolicy.new)
|
14
|
+
def initialize(appfirewall_enabled=false, appfirewall_ptr=nil)
|
15
|
+
@appfirewall_ptr = appfirewall_ptr
|
16
|
+
@appfirewall_enabled = appfirewall_enabled
|
62
17
|
end
|
63
18
|
|
64
19
|
def process_meta_event(appsensor_meta)
|
65
|
-
return unless @
|
66
|
-
|
67
|
-
check_user_agent(appsensor_meta)
|
68
|
-
check_request_size(appsensor_meta)
|
69
|
-
check_response_size(appsensor_meta)
|
70
|
-
check_response_code(appsensor_meta)
|
71
|
-
|
72
|
-
@injections_reporter.check(appsensor_meta)
|
73
|
-
end
|
74
|
-
|
75
|
-
def process_db_rows(tcell_data, number_of_records)
|
76
|
-
return unless @enabled
|
77
|
-
|
78
|
-
TCellAgent::Instrumentation.safe_block("AppSensor Testing Number of DB Rows") do
|
79
|
-
if self.options.has_key?("database")
|
80
|
-
self.options["database"].check(tcell_data, number_of_records)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def check_user_agent(appsensor_meta)
|
86
|
-
TCellAgent::Instrumentation.safe_block("AppSensor Checking User Agent") do
|
87
|
-
if self.options.has_key?("ua")
|
88
|
-
self.options["ua"].check(appsensor_meta)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def check_request_size(appsensor_meta)
|
94
|
-
TCellAgent::Instrumentation.safe_block("AppSensor Testing Response Size") do
|
95
|
-
if self.options.has_key?("req_size")
|
96
|
-
self.options["req_size"].check(appsensor_meta)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def check_response_size(appsensor_meta)
|
102
|
-
return unless @enabled
|
103
|
-
|
104
|
-
TCellAgent::Instrumentation.safe_block("AppSensor Testing Response Size") do
|
105
|
-
if self.options.has_key?("resp_size")
|
106
|
-
self.options["resp_size"].check(appsensor_meta)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def check_response_code(appsensor_meta)
|
112
|
-
TCellAgent::Instrumentation.safe_block("AppSensor Testing Response Code") do
|
113
|
-
if self.options.has_key?("resp_codes")
|
114
|
-
self.options["resp_codes"].check(appsensor_meta, appsensor_meta.response_code)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
20
|
+
return unless @appfirewall_enabled && @appfirewall_ptr
|
118
21
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
end
|
22
|
+
TCellAgent::Instrumentation.safe_block("AppSensor inspection") do
|
23
|
+
request_response = TCellAgent::Rust::Models.create_request_response(appsensor_meta)
|
24
|
+
whisper = TCellAgent::Rust::Whisperer.apply_appfirewall(@appfirewall_ptr, request_response)
|
25
|
+
TCellAgent::AppSensor::InjectionsReporter.report_and_log(whisper["apply_response"])
|
124
26
|
end
|
125
27
|
end
|
126
28
|
|
127
|
-
def
|
128
|
-
TCellAgent::
|
129
|
-
if self.options.has_key?("errors")
|
130
|
-
self.options["errors"].sql_exception_detected(tcell_data, exception)
|
131
|
-
end
|
132
|
-
end
|
29
|
+
def free_native_memory
|
30
|
+
TCellAgent::Rust::Whisperer.free_appfirewall(@appfirewall_ptr) if @appfirewall_ptr
|
133
31
|
end
|
134
32
|
|
135
33
|
def self.from_json(policy_json)
|
136
34
|
return nil unless policy_json
|
137
|
-
policy_json = policy_json.deep_dup
|
138
35
|
|
139
|
-
|
140
|
-
|
141
|
-
|
36
|
+
whisper = TCellAgent::Rust::Whisperer.init_appfirewall(
|
37
|
+
policy_json, TCellAgent.configuration.allow_payloads
|
38
|
+
)
|
39
|
+
if whisper["error"]
|
40
|
+
TCellAgent.logger.debug("Error initializing AppFirewall Policy: #{whisper['error']}")
|
41
|
+
return AppSensorPolicy.new
|
142
42
|
else
|
143
|
-
|
144
|
-
end
|
145
|
-
|
146
|
-
if policy_json.has_key?("data")
|
147
|
-
data_json = policy_json["data"]
|
148
|
-
|
149
|
-
if policy_json["version"] && policy_json["version"] == 2
|
150
|
-
if data_json
|
151
|
-
sensors_json = data_json.fetch("sensors", {})
|
152
|
-
|
153
|
-
if sensors_json.empty?
|
154
|
-
sensor_policy.enabled = false
|
155
|
-
|
156
|
-
else
|
157
|
-
sensor_policy.enabled = true
|
158
|
-
|
159
|
-
options_hash = data_json.fetch("options", {})
|
160
|
-
collect_full_uri = options_hash.fetch("uri_options", {}).fetch("collect_full_uri", false)
|
161
|
-
|
162
|
-
DETECTION_POINTS_V2_NON_INJECTION.each do |sensor_name, sensor_class|
|
163
|
-
settings = sensors_json.fetch(sensor_name, {})
|
164
|
-
updated_settings = {
|
165
|
-
"enabled" => sensors_json.has_key?(sensor_name),
|
166
|
-
"collect_full_uri" => collect_full_uri
|
167
|
-
}.merge(settings)
|
168
|
-
|
169
|
-
sensor_policy.options[sensor_name] =
|
170
|
-
sensor_class.new(updated_settings)
|
171
|
-
end
|
172
|
-
|
173
|
-
payloads_policy = PayloadsPolicy.from_json(options_hash)
|
174
|
-
sensor_policy.injections_reporter =
|
175
|
-
TCellAgent::AppSensor::InjectionsReporter.from_json(
|
176
|
-
2, sensors_json, payloads_policy, collect_full_uri)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
else
|
181
|
-
if data_json
|
182
|
-
options_json = data_json.fetch("options", {})
|
183
|
-
|
184
|
-
if options_json.empty?
|
185
|
-
sensor_policy.enabled = false
|
186
|
-
|
187
|
-
else
|
188
|
-
sensor_policy.enabled = true
|
189
|
-
|
190
|
-
payloads_policy = PayloadsPolicy.from_json({
|
191
|
-
"payloads" => {
|
192
|
-
"send_payloads" => true,
|
193
|
-
"log_payloads" => true
|
194
|
-
}
|
195
|
-
})
|
196
|
-
|
197
|
-
sensor_policy.injections_reporter =
|
198
|
-
TCellAgent::AppSensor::InjectionsReporter.from_json(1, data_json, payloads_policy)
|
199
|
-
|
200
|
-
enabled = options_json.fetch("req_res_size", false)
|
201
|
-
sensor_policy.options["req_size"] = RequestSizeSensor.new({"enabled" => enabled})
|
202
|
-
sensor_policy.options["resp_size"] = ResponseSizeSensor.new({"enabled" => enabled})
|
203
|
-
|
204
|
-
enabled = options_json.fetch("resp_codes", false)
|
205
|
-
sensor_policy.options["resp_codes"] = ResponseCodesSensor.new({
|
206
|
-
"enabled" => enabled,
|
207
|
-
"series_400_enabled" => true,
|
208
|
-
"series_500_enabled" => true})
|
209
|
-
|
210
|
-
sensor_policy.options["ua"] = UserAgentSensor.new({
|
211
|
-
"enabled" => false, "empty_enabled" => false
|
212
|
-
})
|
213
|
-
|
214
|
-
sensor_policy.options["errors"] = MiscSensor.new({
|
215
|
-
"enabled" => false,
|
216
|
-
"csrf_exception_enabled" => false,
|
217
|
-
"sql_exception_enabled" => false
|
218
|
-
})
|
219
|
-
|
220
|
-
sensor_policy.options["database"] = DatabaseSensor.new({
|
221
|
-
"enabled" => false
|
222
|
-
})
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
43
|
+
return AppSensorPolicy.new(whisper["enabled"], whisper["policy_ptr"])
|
226
44
|
end
|
227
|
-
|
228
|
-
return sensor_policy
|
229
45
|
end
|
230
46
|
end
|
231
47
|
|
@@ -2,10 +2,11 @@
|
|
2
2
|
# See the file "LICENSE" for the full license governing this code.
|
3
3
|
|
4
4
|
require 'uri'
|
5
|
+
require 'tcell_agent/policies/policy'
|
5
6
|
|
6
7
|
module TCellAgent
|
7
8
|
module Policies
|
8
|
-
class ClickjackingPolicy
|
9
|
+
class ClickjackingPolicy < Policy
|
9
10
|
class ContentSecurityPolicyHeader
|
10
11
|
@@approved_headers = [
|
11
12
|
"csp"
|
@@ -71,8 +72,9 @@ module TCellAgent
|
|
71
72
|
end
|
72
73
|
result.each(&block)
|
73
74
|
end
|
75
|
+
|
74
76
|
def self.from_json(policy_json)
|
75
|
-
if (!policy_json)
|
77
|
+
if (!policy_json)
|
76
78
|
return nil
|
77
79
|
end
|
78
80
|
csp = ClickjackingPolicy.new
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'tcell_agent/rust/whisperer'
|
2
|
+
require 'tcell_agent/sensor_events/command_injection'
|
3
|
+
require 'tcell_agent/policies/policy'
|
4
|
+
|
5
|
+
|
6
|
+
module TCellAgent
|
7
|
+
module Policies
|
8
|
+
|
9
|
+
class CommandRule
|
10
|
+
IGNORE = "ignore"
|
11
|
+
REPORT = "report"
|
12
|
+
BLOCK = "block"
|
13
|
+
|
14
|
+
attr_reader :rule_id, :action, :command
|
15
|
+
|
16
|
+
def initialize(policy_json)
|
17
|
+
@rule_id = nil
|
18
|
+
@action = nil
|
19
|
+
@command = nil
|
20
|
+
|
21
|
+
if policy_json
|
22
|
+
@rule_id = policy_json["rule_id"]
|
23
|
+
@action = policy_json["action"]
|
24
|
+
@command = policy_json["command"]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def ignore?
|
29
|
+
@action == IGNORE
|
30
|
+
end
|
31
|
+
|
32
|
+
def report?
|
33
|
+
@action == REPORT
|
34
|
+
end
|
35
|
+
|
36
|
+
def block?
|
37
|
+
@action == BLOCK
|
38
|
+
end
|
39
|
+
|
40
|
+
def valid?
|
41
|
+
!!@rule_id && [IGNORE, REPORT, BLOCK].include?(@action)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class CommandInjectionPolicy < Policy
|
46
|
+
attr_accessor :policy_id, :version, :enabled, :overall_action, :command_rules, :compound_statement_rule,
|
47
|
+
:collect_full_commandline
|
48
|
+
|
49
|
+
def initialize
|
50
|
+
@enabled = false
|
51
|
+
@version = nil
|
52
|
+
@policy_id = nil
|
53
|
+
@overall_action = nil
|
54
|
+
@command_rules = {}
|
55
|
+
@compound_statement_rule = nil
|
56
|
+
@collect_full_commandline = false
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.from_json(policy_json)
|
60
|
+
return nil unless policy_json
|
61
|
+
policy_json = policy_json.deep_dup
|
62
|
+
|
63
|
+
policy_id = policy_json["policy_id"]
|
64
|
+
|
65
|
+
raise "Policy ID missing" unless policy_id
|
66
|
+
|
67
|
+
command_injection_policy = CommandInjectionPolicy.new
|
68
|
+
command_injection_policy.policy_id = policy_id
|
69
|
+
command_injection_policy.version = policy_json["version"]
|
70
|
+
|
71
|
+
if 1 != command_injection_policy.version
|
72
|
+
TCellAgent.logger.error("Command Injection not supported: #{command_injection_policy.version}")
|
73
|
+
return command_injection_policy
|
74
|
+
end
|
75
|
+
|
76
|
+
policy_data = policy_json["data"]
|
77
|
+
command_rules = {}
|
78
|
+
overall_action = nil
|
79
|
+
compound_statement_rule = nil
|
80
|
+
if policy_data
|
81
|
+
command_injection_policy.collect_full_commandline = !!policy_data["collect_full_commandline"]
|
82
|
+
|
83
|
+
(policy_data["command_rules"] or []).each do |command_rule_policy|
|
84
|
+
command_rule = CommandRule.new(command_rule_policy)
|
85
|
+
if command_rule.valid?
|
86
|
+
command = command_rule.command
|
87
|
+
if command
|
88
|
+
if command_rules.has_key?(command)
|
89
|
+
TCellAgent.logger.warn(
|
90
|
+
"CommandInjectionPolicy multiple rules for one " +
|
91
|
+
"command (dropping rule): #{command} #{command_rule.action}"
|
92
|
+
)
|
93
|
+
else
|
94
|
+
command_rules[command] = command_rule
|
95
|
+
end
|
96
|
+
elsif !command_rule.ignore?
|
97
|
+
overall_action = command_rule
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
compound_statement_rules = policy_data["compound_statement_rules"]
|
103
|
+
if compound_statement_rules && compound_statement_rules.size > 0
|
104
|
+
compound_statement_rule = CommandRule.new(compound_statement_rules[0])
|
105
|
+
if !compound_statement_rule.valid? || compound_statement_rule.ignore?
|
106
|
+
compound_statement_rule = nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
command_injection_policy.command_rules = command_rules
|
111
|
+
command_injection_policy.overall_action = overall_action
|
112
|
+
command_injection_policy.compound_statement_rule = compound_statement_rule
|
113
|
+
command_injection_policy.enabled = !overall_action.nil? || !compound_statement_rule.nil? || command_rules.size > 0
|
114
|
+
end
|
115
|
+
|
116
|
+
command_injection_policy
|
117
|
+
end
|
118
|
+
|
119
|
+
def block?(cmd, tcell_context)
|
120
|
+
return false unless @enabled
|
121
|
+
|
122
|
+
commands = parse_cmd(cmd).fetch('commands', [])
|
123
|
+
|
124
|
+
command_injection_match_events = []
|
125
|
+
block_command = false
|
126
|
+
|
127
|
+
if commands.size > 1 && !!@compound_statement_rule
|
128
|
+
if !@compound_statement_rule.ignore?
|
129
|
+
command_injection_match_events.push(
|
130
|
+
TCellAgent::SensorEvents::CommandInjectionMatchEvent.new(
|
131
|
+
@compound_statement_rule.rule_id, @compound_statement_rule.command
|
132
|
+
)
|
133
|
+
)
|
134
|
+
block_command = block_command || @compound_statement_rule.block?
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
commands.each do |command_info|
|
139
|
+
command = command_info["command"]
|
140
|
+
command_rule = command_rules[command] || @overall_action
|
141
|
+
if command_rule && !command_rule.ignore?
|
142
|
+
command_injection_match_events.push(
|
143
|
+
TCellAgent::SensorEvents::CommandInjectionMatchEvent.new(
|
144
|
+
command_rule.rule_id,
|
145
|
+
command
|
146
|
+
)
|
147
|
+
)
|
148
|
+
block_command = block_command || command_rule.block?
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
if command_injection_match_events.size > 0
|
153
|
+
method, remote_address, route_id, session_id, user_id, full_commandline = nil
|
154
|
+
if tcell_context
|
155
|
+
method = tcell_context.request_method
|
156
|
+
remote_address = tcell_context.ip_address
|
157
|
+
route_id = tcell_context.route_id
|
158
|
+
session_id = tcell_context.hmac_session_id
|
159
|
+
user_id = tcell_context.user_id
|
160
|
+
end
|
161
|
+
|
162
|
+
if @collect_full_commandline
|
163
|
+
full_commandline = cmd
|
164
|
+
end
|
165
|
+
|
166
|
+
TCellAgent.send_event(
|
167
|
+
TCellAgent::SensorEvents::CommandInjectionEvent.new(
|
168
|
+
commands,
|
169
|
+
block_command,
|
170
|
+
command_injection_match_events,
|
171
|
+
method=method,
|
172
|
+
remote_address=remote_address,
|
173
|
+
route_id=route_id,
|
174
|
+
session_id=session_id,
|
175
|
+
user_id=user_id,
|
176
|
+
full_commandline=full_commandline
|
177
|
+
)
|
178
|
+
)
|
179
|
+
end
|
180
|
+
|
181
|
+
block_command
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
def parse_cmd(cmd)
|
186
|
+
TCellAgent::Instrumentation.safe_block("Call Rust Parse Command") do
|
187
|
+
require "tcell_agent/rust/whisperer"
|
188
|
+
|
189
|
+
return TCellAgent::Rust::Whisperer.parse_cmd(cmd)
|
190
|
+
end
|
191
|
+
|
192
|
+
return {}
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -2,13 +2,14 @@
|
|
2
2
|
# See the file "LICENSE" for the full license governing this code.
|
3
3
|
|
4
4
|
require 'uri'
|
5
|
-
require 'tcell_agent/sensor_events/util/sanitizer_utilities'
|
6
5
|
require 'tcell_agent/configuration'
|
6
|
+
require 'tcell_agent/policies/policy'
|
7
|
+
require 'tcell_agent/sensor_events/util/sanitizer_utilities'
|
7
8
|
|
8
9
|
module TCellAgent
|
9
10
|
module Policies
|
10
11
|
|
11
|
-
class ContentSecurityPolicy
|
12
|
+
class ContentSecurityPolicy < Policy
|
12
13
|
class ContentSecurityPolicyHeader
|
13
14
|
@@approved_headers = [
|
14
15
|
"csp",
|
@@ -10,10 +10,12 @@
|
|
10
10
|
#+"}";
|
11
11
|
require 'pbkdf2'
|
12
12
|
require 'openssl'
|
13
|
+
require 'tcell_agent/policies/policy'
|
14
|
+
|
13
15
|
|
14
16
|
module TCellAgent
|
15
17
|
module Policies
|
16
|
-
class HoneytokensPolicy
|
18
|
+
class HoneytokensPolicy < Policy
|
17
19
|
attr_accessor :policy_id
|
18
20
|
attr_accessor :token_salt
|
19
21
|
attr_accessor :cred_tokens
|
@@ -1,58 +1,59 @@
|
|
1
1
|
# See the file "LICENSE" for the full license governing this code.
|
2
2
|
require 'uri'
|
3
|
-
require 'tcell_agent/logger'
|
4
|
-
require 'tcell_agent/sensor_events/util/redirect_utils'
|
5
|
-
# See the file "LICENSE" for the full license governing this code.
|
6
3
|
|
7
|
-
|
8
|
-
|
9
|
-
# "types": {
|
10
|
-
# "firehose": { enabled: true },
|
11
|
-
#{}"auth_framework_only": {enabled: true},
|
12
|
-
#{}"{}structure": {enabled: true },
|
13
|
-
#{}"fingerprint": {enabled: true }
|
14
|
-
#}
|
15
|
-
#},
|
4
|
+
require 'tcell_agent/policies/policy'
|
5
|
+
require 'tcell_agent/logger'
|
16
6
|
|
17
7
|
module TCellAgent
|
18
8
|
module Policies
|
19
|
-
|
20
|
-
|
21
|
-
attr_accessor :enabled
|
22
|
-
|
23
|
-
attr_accessor :block
|
9
|
+
|
10
|
+
class HttpRedirectPolicy < Policy
|
11
|
+
attr_accessor :policy_id, :enabled, :whitelist, :block, :data_scheme_allowed
|
12
|
+
|
24
13
|
def initialize
|
25
14
|
@policy_id = nil
|
26
15
|
@enabled = false
|
27
16
|
@whitelist = []
|
28
17
|
@block = false
|
18
|
+
@data_scheme_allowed = false
|
29
19
|
end
|
30
|
-
|
20
|
+
|
21
|
+
def suspicious_redirect?(host, current_host)
|
31
22
|
if (!(host) || host == "" || host == current_host)
|
32
23
|
# local redirect
|
33
24
|
return false
|
34
25
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
26
|
+
|
27
|
+
whitelist.each do |whitelist_regex|
|
28
|
+
if (host =~ whitelist_regex) || ("www.#{host}" =~ whitelist_regex)
|
29
|
+
return false
|
40
30
|
end
|
41
31
|
end
|
42
|
-
|
32
|
+
|
33
|
+
true
|
43
34
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
35
|
+
|
36
|
+
def enforce(target_uri, request_uri, current_path, method, route_id, status_code, remote_addr, hmac_session_id=nil)
|
37
|
+
return nil unless @enabled
|
38
|
+
|
39
|
+
current_host = URI.parse(request_uri).host
|
40
|
+
if target_uri.downcase.start_with?("data:")
|
41
|
+
if @data_scheme_allowed
|
42
|
+
return nil
|
43
|
+
end
|
44
|
+
|
45
|
+
target_host = target_uri.split(",")[0]
|
46
|
+
|
47
|
+
else
|
48
|
+
target_host = URI.parse(target_uri).host
|
49
|
+
if !self.suspicious_redirect?(target_host, current_host)
|
50
|
+
return nil
|
51
|
+
end
|
52
52
|
end
|
53
|
+
|
53
54
|
begin
|
54
55
|
event = TCellAgent::SensorEvents::TCellRedirectSensorEvent.new(
|
55
|
-
|
56
|
+
target_host,
|
56
57
|
current_host,
|
57
58
|
current_path,
|
58
59
|
method,
|
@@ -66,29 +67,42 @@ module TCellAgent
|
|
66
67
|
rescue Exception => ie
|
67
68
|
TCellAgent.logger.error("uncaught exception while creating redirect event: #{ie.message}")
|
68
69
|
end
|
69
|
-
|
70
|
+
|
71
|
+
if @block
|
70
72
|
return "/"
|
73
|
+
else
|
74
|
+
return nil
|
71
75
|
end
|
72
|
-
return nil
|
73
76
|
end
|
77
|
+
|
74
78
|
def self.from_json(policy_json)
|
75
|
-
if (!policy_json)
|
79
|
+
if (!policy_json)
|
76
80
|
return nil
|
77
81
|
end
|
82
|
+
|
78
83
|
http_redirect_policy = HttpRedirectPolicy.new
|
79
84
|
if policy_json.has_key?("policy_id")
|
80
85
|
http_redirect_policy.policy_id = policy_json["policy_id"]
|
81
86
|
else
|
82
87
|
raise "Policy ID missing"
|
83
88
|
end
|
89
|
+
|
84
90
|
if policy_json.has_key?("data")
|
85
91
|
policy_data_json = policy_json["data"]
|
86
92
|
http_redirect_policy.enabled = policy_data_json.fetch("enabled", false)
|
87
|
-
http_redirect_policy.whitelist = policy_data_json.fetch("whitelist", [])
|
88
93
|
http_redirect_policy.block = policy_data_json.fetch("block", false)
|
94
|
+
http_redirect_policy.data_scheme_allowed = policy_data_json.fetch("dataSchemeAllowed", false)
|
95
|
+
|
96
|
+
http_redirect_policy.whitelist = []
|
97
|
+
policy_data_json.fetch("whitelist", []).each do |regex_pattern|
|
98
|
+
escaped = Regexp.escape(regex_pattern).gsub('\*','.*?')
|
99
|
+
http_redirect_policy.whitelist.push(Regexp.new("^#{escaped}$", Regexp::IGNORECASE))
|
100
|
+
end
|
89
101
|
end
|
102
|
+
|
90
103
|
return http_redirect_policy
|
91
104
|
end
|
92
105
|
end
|
106
|
+
|
93
107
|
end
|
94
108
|
end
|
@@ -8,9 +8,12 @@
|
|
8
8
|
#}
|
9
9
|
#},
|
10
10
|
|
11
|
+
require 'tcell_agent/policies/policy'
|
12
|
+
|
13
|
+
|
11
14
|
module TCellAgent
|
12
15
|
module Policies
|
13
|
-
class HttpTxPolicy
|
16
|
+
class HttpTxPolicy < Policy
|
14
17
|
attr_accessor :policy_id
|
15
18
|
attr_accessor :firehose
|
16
19
|
attr_accessor :auth_framework
|
@@ -23,6 +26,7 @@ module TCellAgent
|
|
23
26
|
@profile = {"enabled"=>false }
|
24
27
|
@fingerprint = {"enabled"=>false, "hmacUserAgent"=>false, "hmacUserId"=>false, "sampling"=>nil }
|
25
28
|
end
|
29
|
+
|
26
30
|
def self.from_json(policy_json)
|
27
31
|
if (!policy_json)
|
28
32
|
return nil
|