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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/Readme.txt +7 -0
  3. data/bin/tcell_agent +9 -0
  4. data/lib/tcell_agent/agent/policy_manager.rb +3 -0
  5. data/lib/tcell_agent/agent/policy_types.rb +4 -1
  6. data/lib/tcell_agent/appsensor/injections_matcher.rb +20 -0
  7. data/lib/tcell_agent/appsensor/injections_reporter.rb +15 -56
  8. data/lib/tcell_agent/appsensor/meta_data.rb +56 -2
  9. data/lib/tcell_agent/appsensor/rules/baserules.json +371 -138
  10. data/lib/tcell_agent/cmdi.rb +113 -0
  11. data/lib/tcell_agent/config/unknown_options.rb +2 -0
  12. data/lib/tcell_agent/configuration.rb +30 -16
  13. data/lib/tcell_agent/hooks/login_fraud.rb +79 -0
  14. data/lib/tcell_agent/instrumentation.rb +6 -11
  15. data/lib/tcell_agent/patches/meta_data.rb +14 -11
  16. data/lib/tcell_agent/policies/appsensor/injection_sensor.rb +5 -9
  17. data/lib/tcell_agent/policies/appsensor_policy.rb +22 -206
  18. data/lib/tcell_agent/policies/clickjacking_policy.rb +4 -2
  19. data/lib/tcell_agent/policies/command_injection_policy.rb +196 -0
  20. data/lib/tcell_agent/policies/content_security_policy.rb +3 -2
  21. data/lib/tcell_agent/policies/dataloss_policy.rb +3 -1
  22. data/lib/tcell_agent/policies/honeytokens_policy.rb +3 -1
  23. data/lib/tcell_agent/policies/http_redirect_policy.rb +51 -37
  24. data/lib/tcell_agent/policies/http_tx_policy.rb +5 -1
  25. data/lib/tcell_agent/policies/login_fraud_policy.rb +6 -1
  26. data/lib/tcell_agent/policies/patches_policy.rb +3 -1
  27. data/lib/tcell_agent/policies/policy.rb +10 -0
  28. data/lib/tcell_agent/policies/secure_headers_policy.rb +5 -2
  29. data/lib/tcell_agent/rails/auth/devise.rb +12 -23
  30. data/lib/tcell_agent/rails/csrf_exception.rb +1 -1
  31. data/lib/tcell_agent/rails/dlp.rb +50 -54
  32. data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +0 -1
  33. data/lib/tcell_agent/rails/middleware/context_middleware.rb +0 -1
  34. data/lib/tcell_agent/rails/middleware/global_middleware.rb +0 -1
  35. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +7 -10
  36. data/lib/tcell_agent/rails/on_start.rb +0 -1
  37. data/lib/tcell_agent/rails/tcell_body_proxy.rb +4 -4
  38. data/lib/tcell_agent/rails.rb +0 -2
  39. data/lib/tcell_agent/rust/libtcellagent-0.6.1.dylib +0 -0
  40. data/lib/tcell_agent/rust/libtcellagent-0.6.1.so +0 -0
  41. data/lib/tcell_agent/rust/models.rb +61 -0
  42. data/lib/tcell_agent/rust/tcellagent-0.6.1.dll +0 -0
  43. data/lib/tcell_agent/rust/whisperer.rb +112 -0
  44. data/lib/tcell_agent/sensor_events/appsensor_event.rb +25 -21
  45. data/lib/tcell_agent/sensor_events/appsensor_meta_event.rb +31 -24
  46. data/lib/tcell_agent/sensor_events/command_injection.rb +58 -0
  47. data/lib/tcell_agent/sensor_events/discovery.rb +1 -1
  48. data/lib/tcell_agent/sensor_events/login_fraud.rb +3 -13
  49. data/lib/tcell_agent/sensor_events/sensor.rb +81 -77
  50. data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +8 -0
  51. data/lib/tcell_agent/start_background_thread.rb +12 -3
  52. data/lib/tcell_agent/utils/io.rb +4 -1
  53. data/lib/tcell_agent/utils/params.rb +1 -0
  54. data/lib/tcell_agent/version.rb +1 -1
  55. data/lib/tcell_agent.rb +0 -1
  56. data/spec/lib/tcell_agent/appsensor/injections_matcher_spec.rb +27 -9
  57. data/spec/lib/tcell_agent/appsensor/injections_reporter_spec.rb +143 -193
  58. data/spec/lib/tcell_agent/appsensor/meta_data_spec.rb +67 -0
  59. data/spec/lib/tcell_agent/appsensor/rules/appsensor_rule_manager_spec.rb +0 -10
  60. data/spec/lib/tcell_agent/cmdi_spec.rb +748 -0
  61. data/spec/lib/tcell_agent/config/unknown_options_spec.rb +8 -0
  62. data/spec/lib/tcell_agent/configuration_spec.rb +138 -6
  63. data/spec/lib/tcell_agent/hooks/login_fraud_spec.rb +357 -0
  64. data/spec/lib/tcell_agent/patches/block_rule_spec.rb +70 -87
  65. data/spec/lib/tcell_agent/patches_spec.rb +9 -4
  66. data/spec/lib/tcell_agent/policies/appsensor/xss_sensor_spec.rb +186 -9
  67. data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +309 -484
  68. data/spec/lib/tcell_agent/policies/command_injection_policy_spec.rb +736 -0
  69. data/spec/lib/tcell_agent/policies/http_redirect_policy_spec.rb +222 -41
  70. data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +56 -32
  71. data/spec/lib/tcell_agent/rails/middleware/appsensor_middleware_spec.rb +161 -85
  72. data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +40 -72
  73. data/spec/lib/tcell_agent/rust/whisperer_spec.rb +267 -0
  74. data/spec/lib/tcell_agent/sensor_events/appsensor_meta_event_spec.rb +20 -15
  75. data/spec/spec_helper.rb +0 -9
  76. data/tcell_agent.gemspec +8 -3
  77. metadata +40 -39
  78. data/lib/tcell_agent/appsensor/sensor.rb +0 -52
  79. data/lib/tcell_agent/policies/appsensor/database_sensor.rb +0 -56
  80. data/lib/tcell_agent/policies/appsensor/misc_sensor.rb +0 -59
  81. data/lib/tcell_agent/policies/appsensor/payloads_policy.rb +0 -150
  82. data/lib/tcell_agent/policies/appsensor/request_size_sensor.rb +0 -25
  83. data/lib/tcell_agent/policies/appsensor/response_codes_sensor.rb +0 -73
  84. data/lib/tcell_agent/policies/appsensor/response_size_sensor.rb +0 -25
  85. data/lib/tcell_agent/policies/appsensor/size_sensor.rb +0 -71
  86. data/lib/tcell_agent/policies/appsensor/user_agent_sensor.rb +0 -47
  87. data/lib/tcell_agent/rails/auth/hooks.rb +0 -79
  88. data/lib/tcell_agent/sensor_events/util/redirect_utils.rb +0 -22
  89. data/spec/lib/tcell_agent/policies/appsensor/database_sensor_spec.rb +0 -165
  90. data/spec/lib/tcell_agent/policies/appsensor/misc_sensor_spec.rb +0 -429
  91. data/spec/lib/tcell_agent/policies/appsensor/payloads_policy_apply_spec.rb +0 -466
  92. data/spec/lib/tcell_agent/policies/appsensor/payloads_policy_from_json_spec.rb +0 -890
  93. data/spec/lib/tcell_agent/policies/appsensor/payloads_policy_log_spec.rb +0 -417
  94. data/spec/lib/tcell_agent/policies/appsensor/request_size_sensor_spec.rb +0 -236
  95. data/spec/lib/tcell_agent/policies/appsensor/response_codes_sensor_spec.rb +0 -297
  96. data/spec/lib/tcell_agent/policies/appsensor/response_size_sensor_spec.rb +0 -241
  97. data/spec/lib/tcell_agent/policies/appsensor/user_agent_sensor_spec.rb +0 -172
  98. data/spec/lib/tcell_agent/rails/auth/hooks_spec.rb +0 -246
  99. data/spec/lib/tcell_agent/sensor_events/util/redirect_utils_spec.rb +0 -25
  100. data/spec/support/resources/baserules.json +0 -155
@@ -0,0 +1,736 @@
1
+ require 'spec_helper'
2
+
3
+ module TCellAgent
4
+ module Policies
5
+
6
+ describe CommandInjectionPolicy do
7
+ describe "#from_json" do
8
+ context "with a nil policy" do
9
+ it "should return nil" do
10
+ expect(CommandInjectionPolicy.from_json(nil)).to be_nil
11
+ end
12
+ end
13
+
14
+ context "with an empty policy" do
15
+ it "should raise a policy missing error" do
16
+ expect {
17
+ CommandInjectionPolicy.from_json({})
18
+ }.to raise_error(RuntimeError)
19
+ end
20
+ end
21
+
22
+ context "with an empty version" do
23
+ it "should have empty version" do
24
+ cmdi = CommandInjectionPolicy.from_json({ "policy_id" => "policy_id" })
25
+ expect(cmdi.policy_id).to eq("policy_id")
26
+ expect(cmdi.version).to be_nil
27
+ expect(cmdi.enabled).to eq(false)
28
+ expect(cmdi.overall_action).to be_nil
29
+ expect(cmdi.compound_statement_rule).to be_nil
30
+ expect(cmdi.command_rules).to eq({})
31
+ expect(cmdi.collect_full_commandline).to eq(false)
32
+ end
33
+ end
34
+
35
+ context "with no data" do
36
+ it "should have disabled ip blocking" do
37
+ cmdi = CommandInjectionPolicy.from_json({
38
+ "policy_id" => "policy_id",
39
+ "version" => 1
40
+ })
41
+ expect(cmdi.policy_id).to eq("policy_id")
42
+ expect(cmdi.version).to eq(1)
43
+ expect(cmdi.enabled).to eq(false)
44
+ expect(cmdi.overall_action).to be_nil
45
+ expect(cmdi.compound_statement_rule).to be_nil
46
+ expect(cmdi.command_rules).to eq({})
47
+ expect(cmdi.collect_full_commandline).to eq(false)
48
+ end
49
+ end
50
+
51
+ context "with empty data" do
52
+ it "should have default values" do
53
+ cmdi = CommandInjectionPolicy.from_json({
54
+ "policy_id" => "policy_id",
55
+ "version" => 1,
56
+ "data" => {}
57
+ })
58
+ expect(cmdi.policy_id).to eq("policy_id")
59
+ expect(cmdi.version).to eq(1)
60
+ expect(cmdi.enabled).to eq(false)
61
+ expect(cmdi.overall_action).to be_nil
62
+ expect(cmdi.compound_statement_rule).to be_nil
63
+ expect(cmdi.command_rules).to eq({})
64
+ expect(cmdi.collect_full_commandline).to eq(false)
65
+ end
66
+ end
67
+
68
+ context "with empty command rules" do
69
+ it "should have default values" do
70
+ cmdi = CommandInjectionPolicy.from_json({
71
+ "policy_id" => "policy_id",
72
+ "version" => 1,
73
+ "data" => {
74
+ "command_rules" => []
75
+ }
76
+ })
77
+ expect(cmdi.policy_id).to eq("policy_id")
78
+ expect(cmdi.version).to eq(1)
79
+ expect(cmdi.enabled).to eq(false)
80
+ expect(cmdi.overall_action).to be_nil
81
+ expect(cmdi.compound_statement_rule).to be_nil
82
+ expect(cmdi.command_rules).to eq({})
83
+ expect(cmdi.collect_full_commandline).to eq(false)
84
+ end
85
+ end
86
+
87
+ context "with empty compount statement rules" do
88
+ it "should have default values" do
89
+ cmdi = CommandInjectionPolicy.from_json({
90
+ "policy_id" => "policy_id",
91
+ "version" => 1,
92
+ "data" => {
93
+ "compound_statement_rules" => []
94
+ }
95
+ })
96
+ expect(cmdi.policy_id).to eq("policy_id")
97
+ expect(cmdi.version).to eq(1)
98
+ expect(cmdi.enabled).to eq(false)
99
+ expect(cmdi.overall_action).to be_nil
100
+ expect(cmdi.compound_statement_rule).to be_nil
101
+ expect(cmdi.command_rules).to eq({})
102
+ expect(cmdi.collect_full_commandline).to eq(false)
103
+ end
104
+ end
105
+
106
+ context "with populated command rules" do
107
+ it "should have default values" do
108
+ cmdi = CommandInjectionPolicy.from_json({
109
+ "policy_id" => "policy_id",
110
+ "version" => 1,
111
+ "data" => {
112
+ "command_rules" => [
113
+ {"rule_id" => "1", "action" => "block"},
114
+ {"rule_id" => "2", "command" => "nc", "action" => "ignore"}
115
+ ]
116
+ }
117
+ })
118
+
119
+ expect(cmdi.policy_id).to eq("policy_id")
120
+ expect(cmdi.version).to eq(1)
121
+ expect(cmdi.enabled).to eq(true)
122
+ expect(cmdi.overall_action).to_not be_nil
123
+ expect(cmdi.overall_action.rule_id).to eq("1")
124
+ expect(cmdi.overall_action.action).to eq(CommandRule::BLOCK)
125
+ expect(cmdi.overall_action.command).to be_nil
126
+ expect(cmdi.command_rules.size).to eq(1)
127
+ expect(cmdi.command_rules["nc"]).to_not be_nil
128
+ expect(cmdi.command_rules["nc"].rule_id).to eq("2")
129
+ expect(cmdi.command_rules["nc"].action).to eq(CommandRule::IGNORE)
130
+ expect(cmdi.command_rules["nc"].command).to eq("nc")
131
+ expect(cmdi.compound_statement_rule).to be_nil
132
+ expect(cmdi.collect_full_commandline).to eq(false)
133
+ end
134
+ end
135
+
136
+ context "with populated compound statement rules" do
137
+ it "should have default values" do
138
+ cmdi = CommandInjectionPolicy.from_json({
139
+ "policy_id" => "policy_id",
140
+ "version" => 1,
141
+ "data" => {
142
+ "compound_statement_rules" => [
143
+ {"rule_id" => "3", "action" => "block"}
144
+ ]
145
+ }
146
+ })
147
+
148
+ expect(cmdi.policy_id).to eq("policy_id")
149
+ expect(cmdi.version).to eq(1)
150
+ expect(cmdi.enabled).to eq(true)
151
+ expect(cmdi.overall_action).to be_nil
152
+ expect(cmdi.command_rules).to eq({})
153
+ expect(cmdi.compound_statement_rule).to_not be_nil
154
+ expect(cmdi.compound_statement_rule.rule_id).to eq("3")
155
+ expect(cmdi.compound_statement_rule.action).to eq(CommandRule::BLOCK)
156
+ expect(cmdi.compound_statement_rule.command).to be_nil
157
+ expect(cmdi.collect_full_commandline).to eq(false)
158
+ end
159
+ end
160
+
161
+ context "with populated collect_full_commandline" do
162
+ context "as nil" do
163
+ it "should have collect_full_commandline disabled" do
164
+ cmdi = CommandInjectionPolicy.from_json({
165
+ "policy_id" => "policy_id",
166
+ "version" => 1,
167
+ "data" => {
168
+ "collect_full_commandline" => nil,
169
+ "compound_statement_rules" => [
170
+ {"rule_id" => "3", "action" => "block"}
171
+ ]
172
+ }
173
+ })
174
+
175
+ expect(cmdi.policy_id).to eq("policy_id")
176
+ expect(cmdi.version).to eq(1)
177
+ expect(cmdi.enabled).to eq(true)
178
+ expect(cmdi.overall_action).to be_nil
179
+ expect(cmdi.command_rules).to eq({})
180
+ expect(cmdi.compound_statement_rule).to_not be_nil
181
+ expect(cmdi.compound_statement_rule.rule_id).to eq("3")
182
+ expect(cmdi.compound_statement_rule.action).to eq(CommandRule::BLOCK)
183
+ expect(cmdi.compound_statement_rule.command).to be_nil
184
+ expect(cmdi.collect_full_commandline).to eq(false)
185
+ end
186
+ end
187
+
188
+ context "as false" do
189
+ it "should have collect_full_commandline disabled" do
190
+ cmdi = CommandInjectionPolicy.from_json({
191
+ "policy_id" => "policy_id",
192
+ "version" => 1,
193
+ "data" => {
194
+ "collect_full_commandline" => false,
195
+ "compound_statement_rules" => [
196
+ {"rule_id" => "3", "action" => "block"}
197
+ ]
198
+ }
199
+ })
200
+
201
+ expect(cmdi.policy_id).to eq("policy_id")
202
+ expect(cmdi.version).to eq(1)
203
+ expect(cmdi.enabled).to eq(true)
204
+ expect(cmdi.overall_action).to be_nil
205
+ expect(cmdi.command_rules).to eq({})
206
+ expect(cmdi.compound_statement_rule).to_not be_nil
207
+ expect(cmdi.compound_statement_rule.rule_id).to eq("3")
208
+ expect(cmdi.compound_statement_rule.action).to eq(CommandRule::BLOCK)
209
+ expect(cmdi.compound_statement_rule.command).to be_nil
210
+ expect(cmdi.collect_full_commandline).to eq(false)
211
+ end
212
+ end
213
+
214
+ context "as true" do
215
+ it "should have collect_full_commandline enabled" do
216
+ cmdi = CommandInjectionPolicy.from_json({
217
+ "policy_id" => "policy_id",
218
+ "version" => 1,
219
+ "data" => {
220
+ "collect_full_commandline" => true,
221
+ "compound_statement_rules" => [
222
+ {"rule_id" => "3", "action" => "block"}
223
+ ]
224
+ }
225
+ })
226
+
227
+ expect(cmdi.policy_id).to eq("policy_id")
228
+ expect(cmdi.version).to eq(1)
229
+ expect(cmdi.enabled).to eq(true)
230
+ expect(cmdi.overall_action).to be_nil
231
+ expect(cmdi.command_rules).to eq({})
232
+ expect(cmdi.compound_statement_rule).to_not be_nil
233
+ expect(cmdi.compound_statement_rule.rule_id).to eq("3")
234
+ expect(cmdi.compound_statement_rule.action).to eq(CommandRule::BLOCK)
235
+ expect(cmdi.compound_statement_rule.command).to be_nil
236
+ expect(cmdi.collect_full_commandline).to eq(true)
237
+ end
238
+ end
239
+ end
240
+
241
+ end
242
+
243
+ describe "#block?" do
244
+ context "with command rules" do
245
+ context "that are blank" do
246
+ it "should not block" do
247
+ cmdi = CommandInjectionPolicy.from_json({
248
+ "policy_id" => "policy_id",
249
+ "version" => 1,
250
+ "data" => {
251
+ "collect_full_commandline" => true,
252
+ "command_rules" => []
253
+ }
254
+ })
255
+
256
+ expect(TCellAgent).to_not receive(:send_event)
257
+
258
+ expect(
259
+ cmdi.block?("cat /etc/passwd | grep root", nil)
260
+ ).to eq(false)
261
+ end
262
+ end
263
+
264
+ context "that ignore all" do
265
+ it "should not block" do
266
+ cmdi = CommandInjectionPolicy.from_json({
267
+ "policy_id" => "policy_id",
268
+ "version" => 1,
269
+ "data" => {
270
+ "collect_full_commandline" => true,
271
+ "command_rules" => [{"rule_id" => "1", "action" => "ignore"}]
272
+ }
273
+ })
274
+
275
+ expect(TCellAgent).to_not receive(:send_event)
276
+
277
+ expect(
278
+ cmdi.block?("cat /etc/passwd | grep root", nil)
279
+ ).to eq(false)
280
+ end
281
+
282
+ context "and ignore cat" do
283
+ it "should not send an event" do
284
+ cmdi = CommandInjectionPolicy.from_json({
285
+ "policy_id" => "policy_id",
286
+ "version" => 1,
287
+ "data" => {
288
+ "collect_full_commandline" => true,
289
+ "command_rules" => [
290
+ {"rule_id" => "1", "action" => "ignore"},
291
+ {"rule_id" => "2", "action" => "ignore", "command" => "cat"}
292
+ ]
293
+ }
294
+ })
295
+
296
+ expect(TCellAgent).to_not receive(:send_event)
297
+
298
+ expect(
299
+ cmdi.block?("cat /etc/passwd | grep root", nil)
300
+ ).to eq(false)
301
+ end
302
+ end
303
+
304
+ context "and report cat" do
305
+ it "should send an event" do
306
+ cmdi = CommandInjectionPolicy.from_json({
307
+ "policy_id" => "policy_id",
308
+ "version" => 1,
309
+ "data" => {
310
+ "collect_full_commandline" => true,
311
+ "command_rules" => [
312
+ {"rule_id" => "1", "action" => "ignore"},
313
+ {"rule_id" => "2", "action" => "report", "command" => "cat"}
314
+ ]
315
+ }
316
+ })
317
+
318
+ expect(TCellAgent).to receive(:send_event).with({
319
+ "event_type" => "cmdi",
320
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
321
+ "blocked" => false,
322
+ "matches" => [{"rule_id" => "2", "command" => "cat"}],
323
+ "full_commandline" => "cat /etc/passwd | grep root"
324
+ })
325
+
326
+ expect(
327
+ cmdi.block?("cat /etc/passwd | grep root", nil)
328
+ ).to eq(false)
329
+ end
330
+ end
331
+
332
+ context "and block cat" do
333
+ it "should send an event and block" do
334
+ cmdi = CommandInjectionPolicy.from_json({
335
+ "policy_id" => "policy_id",
336
+ "version" => 1,
337
+ "data" => {
338
+ "collect_full_commandline" => true,
339
+ "command_rules" => [
340
+ {"rule_id" => "1", "action" => "ignore"},
341
+ {"rule_id" => "2", "action" => "block", "command" => "cat"}
342
+ ]
343
+ }
344
+ })
345
+
346
+ expect(TCellAgent).to receive(:send_event).with({
347
+ "event_type" => "cmdi",
348
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
349
+ "blocked" => true,
350
+ "matches" => [{"rule_id" => "2", "command" => "cat"}],
351
+ "full_commandline"=>"cat /etc/passwd | grep root"
352
+ })
353
+
354
+ expect(
355
+ cmdi.block?("cat /etc/passwd | grep root", nil)
356
+ ).to eq(true)
357
+ end
358
+ end
359
+ end
360
+
361
+ context "that report all" do
362
+ it "should send an event" do
363
+ cmdi = CommandInjectionPolicy.from_json({
364
+ "policy_id" => "policy_id",
365
+ "version" => 1,
366
+ "data" => {
367
+ "command_rules" => [{"rule_id" => "1", "action" => "report"}]
368
+ }
369
+ })
370
+
371
+ expect(TCellAgent).to receive(:send_event).with({
372
+ "event_type" => "cmdi",
373
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
374
+ "blocked" => false,
375
+ "matches" => [{"rule_id" => "1", "command" => "cat"}, {"rule_id" => "1", "command" => "grep"}]
376
+ })
377
+
378
+ expect(
379
+ cmdi.block?("cat /etc/passwd | grep root", nil)
380
+ ).to eq(false)
381
+ end
382
+
383
+ context "and ignore cat" do
384
+ it "should send an event for grep not cat" do
385
+ cmdi = CommandInjectionPolicy.from_json({
386
+ "policy_id" => "policy_id",
387
+ "version" => 1,
388
+ "data" => {
389
+ "command_rules" => [
390
+ {"rule_id" => "1", "action" => "report"},
391
+ {"rule_id" => "2", "action" => "ignore", "command" => "cat"}
392
+ ]
393
+ }
394
+ })
395
+
396
+ expect(TCellAgent).to receive(:send_event).with({
397
+ "event_type" => "cmdi",
398
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
399
+ "blocked" => false,
400
+ "matches" => [{"rule_id" => "1", "command" => "grep"}]
401
+ })
402
+
403
+ expect(
404
+ cmdi.block?("cat /etc/passwd | grep root", nil)
405
+ ).to eq(false)
406
+ end
407
+ end
408
+
409
+ context "and report cat" do
410
+ it "should send an event for grep and cat" do
411
+ cmdi = CommandInjectionPolicy.from_json({
412
+ "policy_id" => "policy_id",
413
+ "version" => 1,
414
+ "data" => {
415
+ "command_rules" => [
416
+ {"rule_id" => "1", "action" => "report"},
417
+ {"rule_id" => "2", "action" => "report", "command" => "cat"}
418
+ ]
419
+ }
420
+ })
421
+
422
+ expect(TCellAgent).to receive(:send_event).with({
423
+ "event_type" => "cmdi",
424
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
425
+ "blocked" => false,
426
+ "matches" => [{"rule_id" => "2", "command" => "cat"}, {"rule_id" => "1", "command" => "grep"}]
427
+ })
428
+
429
+ expect(
430
+ cmdi.block?("cat /etc/passwd | grep root", nil)
431
+ ).to eq(false)
432
+ end
433
+ end
434
+
435
+ context "and block cat" do
436
+ it "should send an event for grep and cat and block" do
437
+ cmdi = CommandInjectionPolicy.from_json({
438
+ "policy_id" => "policy_id",
439
+ "version" => 1,
440
+ "data" => {
441
+ "command_rules" => [
442
+ {"rule_id" => "1", "action" => "report"},
443
+ {"rule_id" => "2", "action" => "block", "command" => "cat"}
444
+ ]
445
+ }
446
+ })
447
+
448
+ expect(TCellAgent).to receive(:send_event).with({
449
+ "event_type" => "cmdi",
450
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
451
+ "blocked" => true,
452
+ "matches" => [{"rule_id" => "2", "command" => "cat"}, {"rule_id" => "1", "command" => "grep"}]
453
+ })
454
+
455
+ expect(
456
+ cmdi.block?("cat /etc/passwd | grep root", nil)
457
+ ).to eq(true)
458
+ end
459
+ end
460
+ end
461
+
462
+ context "that block all" do
463
+ it "should send an event and block" do
464
+ cmdi = CommandInjectionPolicy.from_json({
465
+ "policy_id" => "policy_id",
466
+ "version" => 1,
467
+ "data" => {
468
+ "command_rules" => [{"rule_id" => "1", "action" => "block"}]
469
+ }
470
+ })
471
+
472
+ expect(TCellAgent).to receive(:send_event).with({
473
+ "event_type" => "cmdi",
474
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
475
+ "blocked" => true,
476
+ "matches" => [{"rule_id" => "1", "command" => "cat"}, {"rule_id" => "1", "command" => "grep"}]
477
+ })
478
+
479
+ expect(
480
+ cmdi.block?("cat /etc/passwd | grep root", nil)
481
+ ).to eq(true)
482
+ end
483
+
484
+ context "and ignore cat" do
485
+ it "should send an event for grep not cat and block" do
486
+ cmdi = CommandInjectionPolicy.from_json({
487
+ "policy_id" => "policy_id",
488
+ "version" => 1,
489
+ "data" => {
490
+ "command_rules" => [
491
+ {"rule_id" => "1", "action" => "block"},
492
+ {"rule_id" => "2", "action" => "ignore", "command" => "cat"}
493
+ ]
494
+ }
495
+ })
496
+
497
+ expect(TCellAgent).to receive(:send_event).with({
498
+ "event_type" => "cmdi",
499
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
500
+ "blocked" => true,
501
+ "matches" => [{"rule_id" => "1", "command" => "grep"}]
502
+ })
503
+
504
+ expect(
505
+ cmdi.block?("cat /etc/passwd | grep root", nil)
506
+ ).to eq(true)
507
+ end
508
+ end
509
+
510
+ context "and report cat" do
511
+ it "should send an event for grep and cat and block" do
512
+ cmdi = CommandInjectionPolicy.from_json({
513
+ "policy_id" => "policy_id",
514
+ "version" => 1,
515
+ "data" => {
516
+ "command_rules" => [
517
+ {"rule_id" => "1", "action" => "block"},
518
+ {"rule_id" => "2", "action" => "report", "command" => "cat"}
519
+ ]
520
+ }
521
+ })
522
+
523
+ expect(TCellAgent).to receive(:send_event).with({
524
+ "event_type" => "cmdi",
525
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
526
+ "blocked" => true,
527
+ "matches" => [{"rule_id" => "2", "command" => "cat"}, {"rule_id" => "1", "command" => "grep"}]
528
+ })
529
+
530
+ expect(
531
+ cmdi.block?("cat /etc/passwd | grep root", nil)
532
+ ).to eq(true)
533
+ end
534
+ end
535
+
536
+ context "and block cat" do
537
+ it "should send an event for grep and cat and block" do
538
+ cmdi = CommandInjectionPolicy.from_json({
539
+ "policy_id" => "policy_id",
540
+ "version" => 1,
541
+ "data" => {
542
+ "command_rules" => [
543
+ {"rule_id" => "1", "action" => "block"},
544
+ {"rule_id" => "2", "action" => "block", "command" => "cat"}
545
+ ]
546
+ }
547
+ })
548
+
549
+ expect(TCellAgent).to receive(:send_event).with({
550
+ "event_type" => "cmdi",
551
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
552
+ "blocked" => true,
553
+ "matches" => [{"rule_id" => "2", "command" => "cat"}, {"rule_id" => "1", "command" => "grep"}]
554
+ })
555
+
556
+ expect(
557
+ cmdi.block?("cat /etc/passwd | grep root", nil)
558
+ ).to eq(true)
559
+ end
560
+ end
561
+ end
562
+ end
563
+
564
+ context "with compound statement rules" do
565
+ before(:each) do
566
+ @tcell_context = TCellAgent::Instrumentation::TCellData.new
567
+ @tcell_context.request_method = "GET"
568
+ @tcell_context.ip_address = "1.1.1.1"
569
+ @tcell_context.route_id = "12345"
570
+ @tcell_context.hmac_session_id = "sldfjk2343"
571
+ @tcell_context.user_id = "user_id"
572
+ end
573
+
574
+ context "set to ignore" do
575
+ before(:each) do
576
+ @cmdi = CommandInjectionPolicy.from_json({
577
+ "policy_id" => "policy_id",
578
+ "version" => 1,
579
+ "data" => {
580
+ "compound_statement_rules" => [
581
+ {"rule_id" => "1", "action" => "ignore"}
582
+ ]
583
+ }
584
+ })
585
+ end
586
+
587
+ context "one parsed command" do
588
+ it "should not send events or block" do
589
+ expect(TCellAgent).to_not receive(:send_event)
590
+
591
+ expect(
592
+ @cmdi.block?("cat /etc/passwd", @tcell_context)
593
+ ).to eq(false)
594
+ end
595
+ end
596
+
597
+ context "two parsed commands" do
598
+ it "should not send events or block" do
599
+ expect(TCellAgent).to_not receive(:send_event)
600
+
601
+ expect(
602
+ @cmdi.block?("cat /etc/passwd | grep root", @tcell_context)
603
+ ).to eq(false)
604
+ end
605
+ end
606
+ end
607
+
608
+ context "set to report" do
609
+ before(:each) do
610
+ @cmdi = CommandInjectionPolicy.from_json({
611
+ "policy_id" => "policy_id",
612
+ "version" => 1,
613
+ "data" => {
614
+ "compound_statement_rules" => [
615
+ {"rule_id" => "1", "action" => "report"}
616
+ ]
617
+ }
618
+ })
619
+ end
620
+
621
+ context "one parsed command" do
622
+ it "should not send events or block" do
623
+ expect(TCellAgent).to_not receive(:send_event)
624
+
625
+ expect(
626
+ @cmdi.block?("cat /etc/passwd", @tcell_context)
627
+ ).to eq(false)
628
+ end
629
+ end
630
+
631
+ context "two parsed commands" do
632
+ it "should send an event but not block" do
633
+ expect(TCellAgent).to receive(:send_event).with({
634
+ "event_type" => "cmdi",
635
+ "commands" => [
636
+ {"command" => "cat", "arg_count" => 1},
637
+ {"command" => "grep", "arg_count" => 1}
638
+ ],
639
+ "blocked" => false,
640
+ "matches" => [{"rule_id" => "1"}],
641
+ "method" => "GET",
642
+ "remote_address" => "1.1.1.1",
643
+ "route_id" => "12345",
644
+ "session_id" => "sldfjk2343",
645
+ "user_id" => "user_id"
646
+ })
647
+
648
+ expect(
649
+ @cmdi.block?("cat /etc/passwd | grep root", @tcell_context)
650
+ ).to eq(false)
651
+ end
652
+ end
653
+ end
654
+
655
+ context "set to block" do
656
+ before(:each) do
657
+ @cmdi = CommandInjectionPolicy.from_json({
658
+ "policy_id" => "policy_id",
659
+ "version" => 1,
660
+ "data" => {
661
+ "compound_statement_rules" => [
662
+ {"rule_id" => "1", "action" => "block"}
663
+ ]
664
+ }
665
+ })
666
+ end
667
+
668
+ context "one parsed command" do
669
+ it "should not send events or block" do
670
+ expect(TCellAgent).to_not receive(:send_event)
671
+
672
+ expect(
673
+ @cmdi.block?("cat /etc/passwd", @tcell_context)
674
+ ).to eq(false)
675
+ end
676
+ end
677
+
678
+ context "two parsed commands" do
679
+ it "should send an event and block" do
680
+ expect(TCellAgent).to receive(:send_event).with({
681
+ "event_type" => "cmdi",
682
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
683
+ "blocked" => true,
684
+ "matches" => [{"rule_id" => "1"}],
685
+ "method" => "GET",
686
+ "remote_address" => "1.1.1.1",
687
+ "route_id" => "12345",
688
+ "session_id" => "sldfjk2343",
689
+ "user_id" => "user_id"
690
+ })
691
+
692
+ expect(
693
+ @cmdi.block?("cat /etc/passwd | grep root", @tcell_context)
694
+ ).to eq(true)
695
+ end
696
+ end
697
+ end
698
+
699
+ context "that conflict" do
700
+ it "only take the first one and ignore the rest" do
701
+ ## multiple compound statements present only first one is taken
702
+ cmdi = CommandInjectionPolicy.from_json({
703
+ "policy_id" => "policy_id",
704
+ "version" => 1,
705
+ "data" => {
706
+ "compound_statement_rules" => [
707
+ {"rule_id" => "1", "action" => "block"},
708
+ {"rule_id" => "2", "action" => "ignore"}
709
+ ]
710
+ }
711
+ })
712
+
713
+ expect(TCellAgent).to receive(:send_event).with({
714
+ "event_type" => "cmdi",
715
+ "commands" => [{"command" => "cat", "arg_count" => 1}, {"command" => "grep", "arg_count" => 1}],
716
+ "blocked" => true,
717
+ "matches" => [{"rule_id" => "1"}],
718
+ "method" => "GET",
719
+ "remote_address" => "1.1.1.1",
720
+ "route_id" => "12345",
721
+ "session_id" => "sldfjk2343",
722
+ "user_id" => "user_id"
723
+ })
724
+
725
+ expect(
726
+ cmdi.block?("cat /etc/passwd | grep root", @tcell_context)
727
+ ).to eq(true)
728
+ end
729
+
730
+ end
731
+ end
732
+ end
733
+
734
+ end
735
+ end
736
+ end