tcell_agent 1.1.12 → 2.2.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.
Files changed (169) hide show
  1. checksums.yaml +5 -5
  2. data/bin/tcell_agent +45 -137
  3. data/lib/tcell_agent.rb +12 -14
  4. data/lib/tcell_agent/agent.rb +108 -97
  5. data/lib/tcell_agent/agent/route_manager.rb +0 -16
  6. data/lib/tcell_agent/agent/static_agent.rb +9 -30
  7. data/lib/tcell_agent/config_initializer.rb +66 -0
  8. data/lib/tcell_agent/configuration.rb +69 -345
  9. data/lib/tcell_agent/hooks/login_fraud.rb +30 -33
  10. data/lib/tcell_agent/instrument_servers.rb +23 -0
  11. data/lib/tcell_agent/instrumentation.rb +12 -10
  12. data/lib/tcell_agent/instrumentation/cmdi.rb +29 -25
  13. data/lib/tcell_agent/instrumentation/lfi.rb +84 -0
  14. data/lib/tcell_agent/instrumentation/monkey_patches/file.rb +25 -0
  15. data/lib/tcell_agent/instrumentation/monkey_patches/io.rb +131 -0
  16. data/lib/tcell_agent/instrumentation/monkey_patches/kernel.rb +102 -0
  17. data/lib/tcell_agent/logger.rb +49 -114
  18. data/lib/tcell_agent/patches.rb +6 -7
  19. data/lib/tcell_agent/policies/appfirewall_policy.rb +26 -0
  20. data/lib/tcell_agent/policies/command_injection_policy.rb +28 -0
  21. data/lib/tcell_agent/policies/dataloss_policy.rb +44 -44
  22. data/lib/tcell_agent/policies/headers_policy.rb +25 -0
  23. data/lib/tcell_agent/policies/http_redirect_policy.rb +13 -79
  24. data/lib/tcell_agent/policies/js_agent_policy.rb +27 -0
  25. data/lib/tcell_agent/policies/local_file_access.rb +28 -0
  26. data/lib/tcell_agent/policies/login_policy.rb +43 -0
  27. data/lib/tcell_agent/policies/patches_policy.rb +27 -0
  28. data/lib/tcell_agent/policies/policies_manager.rb +68 -0
  29. data/lib/tcell_agent/policies/policy_polling.rb +58 -0
  30. data/lib/tcell_agent/policies/policy_types.rb +14 -0
  31. data/lib/tcell_agent/policies/system_enablements.rb +27 -0
  32. data/lib/tcell_agent/rails/auth/authlogic.rb +46 -75
  33. data/lib/tcell_agent/rails/auth/authlogic_helper.rb +20 -0
  34. data/lib/tcell_agent/rails/auth/devise.rb +100 -105
  35. data/lib/tcell_agent/rails/auth/devise_helper.rb +29 -0
  36. data/lib/tcell_agent/rails/auth/doorkeeper.rb +62 -76
  37. data/lib/tcell_agent/{userinfo.rb → rails/auth/userinfo.rb} +0 -0
  38. data/lib/tcell_agent/rails/csrf_exception.rb +2 -10
  39. data/lib/tcell_agent/rails/dlp.rb +35 -23
  40. data/lib/tcell_agent/rails/dlp_handler.rb +1 -2
  41. data/lib/tcell_agent/rails/js_agent_insert.rb +12 -13
  42. data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +4 -25
  43. data/lib/tcell_agent/rails/middleware/context_middleware.rb +2 -12
  44. data/lib/tcell_agent/rails/middleware/global_middleware.rb +1 -2
  45. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +14 -34
  46. data/lib/tcell_agent/{rails.rb → rails/railties/tcell_agent_railties.rb} +11 -16
  47. data/lib/tcell_agent/rails/railties/tcell_agent_unicorn_railties.rb +8 -0
  48. data/lib/tcell_agent/rails/routes.rb +10 -12
  49. data/lib/tcell_agent/rails/routes/grape.rb +4 -14
  50. data/lib/tcell_agent/rails/routes/route_id.rb +3 -1
  51. data/lib/tcell_agent/rails/settings_reporter.rb +23 -36
  52. data/lib/tcell_agent/rails/tcell_body_proxy.rb +5 -4
  53. data/lib/tcell_agent/rust/agent_config.rb +60 -0
  54. data/lib/tcell_agent/rust/{libtcellagent-alpine-1.3.2.so → libtcellagent-5.0.2.dylib} +0 -0
  55. data/lib/tcell_agent/rust/{libtcellagent-1.3.2.so → libtcellagent-5.0.2.so} +0 -0
  56. data/lib/tcell_agent/rust/libtcellagent-alpine-5.0.2.so +0 -0
  57. data/lib/tcell_agent/rust/models.rb +6 -52
  58. data/lib/tcell_agent/rust/native_agent.rb +549 -0
  59. data/lib/tcell_agent/rust/native_agent_response.rb +42 -0
  60. data/lib/tcell_agent/rust/native_library.rb +69 -0
  61. data/lib/tcell_agent/rust/tcellagent-5.0.2.dll +0 -0
  62. data/lib/tcell_agent/sensor_events/agent_setting_event.rb +12 -0
  63. data/lib/tcell_agent/sensor_events/{app_config.rb → app_config_setting_event.rb} +0 -6
  64. data/lib/tcell_agent/sensor_events/dlp.rb +2 -6
  65. data/lib/tcell_agent/sensor_events/sensor.rb +0 -62
  66. data/lib/tcell_agent/sensor_events/server_agent.rb +13 -18
  67. data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +0 -108
  68. data/lib/tcell_agent/sensor_events/util/utils.rb +0 -2
  69. data/lib/tcell_agent/servers/passenger.rb +1 -28
  70. data/lib/tcell_agent/servers/puma.rb +3 -21
  71. data/lib/tcell_agent/servers/rails_server.rb +1 -2
  72. data/lib/tcell_agent/servers/thin.rb +2 -2
  73. data/lib/tcell_agent/servers/unicorn.rb +19 -80
  74. data/lib/tcell_agent/servers/webrick.rb +1 -2
  75. data/lib/tcell_agent/settings_reporter.rb +11 -90
  76. data/lib/tcell_agent/sinatra.rb +14 -16
  77. data/lib/tcell_agent/tcell_context.rb +40 -14
  78. data/lib/tcell_agent/utils/headers.rb +14 -0
  79. data/lib/tcell_agent/version.rb +1 -1
  80. data/spec/lib/tcell_agent/configuration_spec.rb +55 -346
  81. data/spec/lib/tcell_agent/hooks/login_fraud_spec.rb +46 -173
  82. data/spec/lib/tcell_agent/instrumentation/cmdi/io_cmdi_spec.rb +504 -0
  83. data/spec/lib/tcell_agent/instrumentation/cmdi/kernel_cmdi_spec.rb +435 -0
  84. data/spec/lib/tcell_agent/instrumentation/cmdi_spec.rb +201 -0
  85. data/spec/lib/tcell_agent/instrumentation/lfi/file_lfi_spec.rb +326 -0
  86. data/spec/lib/tcell_agent/instrumentation/lfi/io_lfi_spec.rb +562 -0
  87. data/spec/lib/tcell_agent/instrumentation/lfi/kernel_lfi_spec.rb +264 -0
  88. data/spec/lib/tcell_agent/instrumentation/lfi_spec.rb +150 -0
  89. data/spec/lib/tcell_agent/patches_spec.rb +25 -43
  90. data/spec/lib/tcell_agent/policies/appfirewall_policy_spec.rb +183 -0
  91. data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +57 -0
  92. data/spec/lib/tcell_agent/policies/command_injection_policy_spec.rb +84 -773
  93. data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +161 -0
  94. data/spec/lib/tcell_agent/policies/dataloss_policy_spec.rb +9 -9
  95. data/spec/lib/tcell_agent/policies/http_redirect_policy_spec.rb +243 -198
  96. data/spec/lib/tcell_agent/policies/js_agent_policy_spec.rb +75 -0
  97. data/spec/lib/tcell_agent/policies/login_policy_spec.rb +165 -33
  98. data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +84 -277
  99. data/spec/lib/tcell_agent/policies/policies_manager_spec.rb +104 -0
  100. data/spec/lib/tcell_agent/policies/policy_polling_spec.rb +6 -0
  101. data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +56 -0
  102. data/spec/lib/tcell_agent/rails/csrf_exception_spec.rb +9 -18
  103. data/spec/lib/tcell_agent/rails/js_agent_insert_spec.rb +13 -30
  104. data/spec/lib/tcell_agent/rails/logger_spec.rb +27 -7
  105. data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +17 -12
  106. data/spec/lib/tcell_agent/rails/routes/routes_spec.rb +14 -14
  107. data/spec/lib/tcell_agent/rust/agent_config_spec.rb +27 -0
  108. data/spec/lib/tcell_agent/sensor_events/util/sanitizer_utilities_spec.rb +0 -35
  109. data/spec/lib/tcell_agent/settings_reporter_spec.rb +56 -155
  110. data/spec/spec_helper.rb +1 -1
  111. data/spec/support/builders.rb +103 -0
  112. data/spec/support/force_logger_mocking.rb +38 -0
  113. data/spec/support/resources/lfi_sample_file.txt +2 -0
  114. data/spec/support/static_agent_overrides.rb +0 -15
  115. metadata +72 -83
  116. data/lib/tcell_agent/agent/event_processor.rb +0 -326
  117. data/lib/tcell_agent/agent/fork_pipe_manager.rb +0 -113
  118. data/lib/tcell_agent/agent/policy_manager.rb +0 -219
  119. data/lib/tcell_agent/agent/policy_types.rb +0 -30
  120. data/lib/tcell_agent/api.rb +0 -91
  121. data/lib/tcell_agent/appsensor/injections_reporter.rb +0 -24
  122. data/lib/tcell_agent/authlogic.rb +0 -26
  123. data/lib/tcell_agent/config/child_process_events.rb +0 -8
  124. data/lib/tcell_agent/config/unknown_options.rb +0 -123
  125. data/lib/tcell_agent/devise.rb +0 -35
  126. data/lib/tcell_agent/instrumentation/cmdi/backtick.rb +0 -10
  127. data/lib/tcell_agent/instrumentation/cmdi/exec.rb +0 -14
  128. data/lib/tcell_agent/instrumentation/cmdi/popen.rb +0 -28
  129. data/lib/tcell_agent/instrumentation/cmdi/spawn.rb +0 -11
  130. data/lib/tcell_agent/instrumentation/cmdi/system.rb +0 -11
  131. data/lib/tcell_agent/policies/http_tx_policy.rb +0 -60
  132. data/lib/tcell_agent/policies/login_fraud_policy.rb +0 -45
  133. data/lib/tcell_agent/policies/rust_policies.rb +0 -110
  134. data/lib/tcell_agent/rails/on_start.rb +0 -41
  135. data/lib/tcell_agent/rust/libtcellagent-1.3.2.dylib +0 -0
  136. data/lib/tcell_agent/rust/tcellagent-1.3.2.dll +0 -0
  137. data/lib/tcell_agent/rust/whisperer.rb +0 -308
  138. data/lib/tcell_agent/sensor_events/appsensor_event.rb +0 -52
  139. data/lib/tcell_agent/sensor_events/appsensor_meta_event.rb +0 -45
  140. data/lib/tcell_agent/sensor_events/command_injection.rb +0 -75
  141. data/lib/tcell_agent/sensor_events/honeytokens.rb +0 -16
  142. data/lib/tcell_agent/sensor_events/login_fraud.rb +0 -60
  143. data/lib/tcell_agent/sensor_events/metrics.rb +0 -123
  144. data/lib/tcell_agent/sensor_events/patches.rb +0 -21
  145. data/lib/tcell_agent/start_background_thread.rb +0 -55
  146. data/lib/tcell_agent/system_info.rb +0 -11
  147. data/lib/tcell_agent/utils/io.rb +0 -38
  148. data/lib/tcell_agent/utils/passwords.rb +0 -28
  149. data/lib/tcell_agent/utils/queue_with_timeout.rb +0 -142
  150. data/spec/lib/tcell_agent/agent/fork_pipe_manager_spec.rb +0 -100
  151. data/spec/lib/tcell_agent/agent/policy_manager_spec.rb +0 -535
  152. data/spec/lib/tcell_agent/agent/static_agent_spec.rb +0 -133
  153. data/spec/lib/tcell_agent/api/api_spec.rb +0 -39
  154. data/spec/lib/tcell_agent/appsensor/injections_reporter_spec.rb +0 -187
  155. data/spec/lib/tcell_agent/cmdi_spec.rb +0 -736
  156. data/spec/lib/tcell_agent/config/unknown_options_spec.rb +0 -213
  157. data/spec/lib/tcell_agent/instrumentation_spec.rb +0 -225
  158. data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +0 -517
  159. data/spec/lib/tcell_agent/policies/http_tx_policy_spec.rb +0 -22
  160. data/spec/lib/tcell_agent/rails/middleware/appsensor_middleware_spec.rb +0 -293
  161. data/spec/lib/tcell_agent/rails/middleware/dlp_middleware_spec.rb +0 -198
  162. data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +0 -180
  163. data/spec/lib/tcell_agent/rails/middleware/redirect_middleware_spec.rb +0 -116
  164. data/spec/lib/tcell_agent/rust/models_spec.rb +0 -120
  165. data/spec/lib/tcell_agent/rust/whisperer_spec.rb +0 -704
  166. data/spec/lib/tcell_agent/sensor_events/appsensor_meta_event_spec.rb +0 -45
  167. data/spec/lib/tcell_agent/sensor_events/sessions_metric_spec.rb +0 -272
  168. data/spec/lib/tcell_agent/utils/bounded_queue_spec.rb +0 -52
  169. data/spec/lib/tcell_agent/utils/passwords_spec.rb +0 -143
@@ -1,47 +1,44 @@
1
1
  require 'tcell_agent/agent'
2
- require 'tcell_agent/sensor_events/login_fraud'
3
2
 
4
3
  module TCellAgent
5
4
  module Hooks
6
5
  module LoginFraud
6
+ # Note: mock out in tests
7
+ def self.get_logger
8
+ unless defined?(@login_fraud_logger)
9
+ @login_fraud_logger = TCellAgent::ModuleLogger.new(TCellAgent.logger, name)
10
+ end
11
+
12
+ @login_fraud_logger
13
+ end
14
+
7
15
  def self.report_login_event(status,
8
16
  env_or_header_keys,
9
17
  tcell_data,
10
18
  user_id,
11
19
  password,
12
20
  user_valid)
13
- if TCellAgent.configuration.enabled &&
14
- TCellAgent.configuration.should_intercept_requests?
15
- login_fraud_policy = TCellAgent.policy(TCellAgent::PolicyTypes::LOGINFRAUD)
16
-
17
- if login_fraud_policy && login_fraud_policy.enabled
18
- if tcell_data
19
- if ![TCellAgent::Hooks::V1::Login::LOGIN_FAILURE,
20
- TCellAgent::Hooks::V1::Login::LOGIN_SUCCESS].include?(status)
21
- TCellAgent.logger.error("Unkown login status: #{status}")
21
+ return unless TCellAgent.configuration.should_intercept_requests? && tcell_data
22
22
 
23
- elsif (status == TCellAgent::Hooks::V1::Login::LOGIN_FAILURE) &&
24
- login_fraud_policy.login_failed_enabled
25
- TCellAgent.send_event(
26
- TCellAgent::SensorEvents::LoginFailure.new(env_or_header_keys,
27
- tcell_data,
28
- user_id,
29
- password,
30
- user_valid)
31
- )
23
+ login_policy = TCellAgent.policy(TCellAgent::PolicyTypes::LOGINFRAUD)
32
24
 
33
- elsif (status == TCellAgent::Hooks::V1::Login::LOGIN_SUCCESS) &&
34
- login_fraud_policy.login_success_enabled
35
- TCellAgent.send_event(
36
- TCellAgent::SensorEvents::LoginSuccess.new(env_or_header_keys,
37
- tcell_data,
38
- user_id,
39
- password,
40
- user_valid)
41
- )
42
- end
43
- end
44
- end
25
+ if ![TCellAgent::Hooks::V1::Login::LOGIN_FAILURE,
26
+ TCellAgent::Hooks::V1::Login::LOGIN_SUCCESS].include?(status)
27
+ get_logger.error("Unkown login status: #{status}")
28
+ elsif status == TCellAgent::Hooks::V1::Login::LOGIN_FAILURE
29
+ login_policy.report_login_failure(
30
+ user_id,
31
+ password,
32
+ env_or_header_keys,
33
+ user_valid,
34
+ tcell_data
35
+ )
36
+ elsif status == TCellAgent::Hooks::V1::Login::LOGIN_SUCCESS
37
+ login_policy.report_login_success(
38
+ user_id,
39
+ env_or_header_keys,
40
+ tcell_data
41
+ )
45
42
  end
46
43
  end
47
44
  end
@@ -91,9 +88,9 @@ if defined?(TCellAgent::Hooks::V1::Login)
91
88
  tcell_data = TCellAgent::Instrumentation::TCellData.new
92
89
  tcell_data.user_agent = user_agent
93
90
  tcell_data.referrer = referrer
94
- tcell_data.ip_address = remote_address
91
+ tcell_data.remote_address = remote_address
95
92
  tcell_data.path = document_uri
96
- tcell_data.hmac_session_id = TCellAgent::SensorEvents::Util.hmac(session_id)
93
+ tcell_data.session_id = session_id
97
94
 
98
95
  TCellAgent::Hooks::LoginFraud.report_login_event(status,
99
96
  header_keys,
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ tcell_server = ENV['TCELL_AGENT_SERVER']
4
+
5
+ if tcell_server && tcell_server == 'mock'
6
+ TCellAgent.thread_agent.instrument_built_ins
7
+ end
8
+
9
+ if (tcell_server && tcell_server == 'webrick') || defined?(Rails::Server)
10
+ require('tcell_agent/servers/rails_server')
11
+
12
+ elsif (tcell_server && tcell_server == 'thin') || defined?(Thin)
13
+ require('tcell_agent/servers/thin')
14
+
15
+ elsif (tcell_server && tcell_server == 'puma') || defined?(Puma)
16
+ require('tcell_agent/servers/puma')
17
+
18
+ elsif (tcell_server && tcell_server == 'unicorn') || defined?(Unicorn)
19
+ require('tcell_agent/servers/unicorn')
20
+
21
+ elsif (tcell_server && tcell_server == 'passenger') || defined?(PhusionPassenger)
22
+ require('tcell_agent/servers/passenger')
23
+ end
@@ -1,5 +1,4 @@
1
1
  # See the file "LICENSE" for the full license governing this code.
2
- require 'tcell_agent/logger'
3
2
  require 'tcell_agent/configuration'
4
3
  require 'tcell_agent/version'
5
4
  require 'date'
@@ -64,7 +63,7 @@ module TCellAgent
64
63
  class TCellData
65
64
  attr_accessor :transaction_id, :session_id, :hmac_session_id, :user_id,
66
65
  :password, :route_id, :path, :uri, :fullpath, :context_filters_by_term,
67
- :database_filters, :ip_address, :user_agent, :request_method,
66
+ :database_filters, :remote_address, :user_agent, :request_method,
68
67
  :path_parameters, :patches_blocking_triggered, :grape_mount_endpoint,
69
68
  :referrer, :csrf_exception_name, :sql_exceptions, :database_result_sizes
70
69
 
@@ -209,23 +208,26 @@ module TCellAgent
209
208
  "<#{self.class.name} transaction_id: #{transaction_id} session_id: #{session_id} " \
210
209
  "hmac_session_id: #{hmac_session_id} user_id: #{user_id} route_id: #{route_id} " \
211
210
  "uri: #{uri} context_filters_by_term: #{context_filters_by_term} " \
212
- "database_filters: #{database_filters} ip_address: #{ip_address} user_agent: #{user_agent} " \
211
+ "database_filters: #{database_filters} remote_address: #{remote_address} user_agent: #{user_agent} " \
213
212
  "request_method: #{@request_method} path_parameters: #{@path_parameters}>"
214
213
  end
215
214
  end
216
215
 
217
- def self.instrument_frameworks
218
- require 'tcell_agent/authlogic' if defined?(Authlogic)
219
- require 'tcell_agent/devise' if defined?(Devise)
220
- require 'tcell_agent/rails' if defined?(Rails)
221
- require 'tcell_agent/sinatra' if defined?(Sinatra)
216
+ # Note: mock for tests
217
+ def self.get_safe_block_logger
218
+ unless defined?(@safe_block_logger)
219
+ @safe_block_logger = TCellAgent::ModuleLogger.new(TCellAgent.logger, name)
220
+ end
221
+
222
+ @safe_block_logger
222
223
  end
223
224
 
224
225
  def self.safe_block(message, &block)
225
226
  block.call
226
227
  rescue StandardError => ex
227
- TCellAgent.logger.debug "Exception in safe_block #{message}: #{ex.class} happened, message is #{ex.message}"
228
- TCellAgent.logger.debug(ex.backtrace)
228
+ logger = get_safe_block_logger
229
+ logger.error("Error #{message} (#{ex.class}): #{ex.message}")
230
+ logger.exception(ex)
229
231
  end
230
232
 
231
233
  def self.safe_block_no_log(_message, &block)
@@ -1,4 +1,4 @@
1
- require 'tcell_agent/agent/policy_types'
1
+ require 'tcell_agent/policies/policy_types'
2
2
  require 'tcell_agent/utils/strings'
3
3
  require 'tcell_agent/configuration'
4
4
 
@@ -7,13 +7,13 @@ module TCellAgent
7
7
  def self.block_command?(cmd)
8
8
  TCellAgent::Instrumentation.safe_block('Checking Command Injection Policy') do
9
9
  if TCellAgent::Utils::Strings.present?(cmd)
10
- rust_policies = TCellAgent.policy(TCellAgent::PolicyTypes::RUST)
11
- if rust_policies && rust_policies.cmdi_enabled
10
+ command_injection_policy = TCellAgent.policy(TCellAgent::PolicyTypes::COMMANDINJECTION)
11
+ if command_injection_policy.enabled
12
12
  request_env = TCellAgent::Instrumentation::Rails::Middleware::ContextMiddleware::THREADS.fetch(
13
13
  Thread.current.object_id, {}
14
14
  )
15
15
  tcell_context = request_env[TCellAgent::Instrumentation::TCELL_ID]
16
- return rust_policies.block_command?(cmd, tcell_context)
16
+ return command_injection_policy.block_command?(cmd, tcell_context)
17
17
  end
18
18
  end
19
19
  end
@@ -25,32 +25,36 @@ module TCellAgent
25
25
  cmd = ''
26
26
 
27
27
  TCellAgent::Instrumentation.safe_block('CMDI Parsing *args') do
28
- unless args.empty?
29
- args_copy = Array.new(args)
30
- args_copy.shift if args_copy.first.is_a?(Hash)
31
- args_copy.pop if args_copy.last.is_a?(Hash)
32
-
33
- if args_copy.first.is_a?(Array)
34
- cmd_n_argv0 = args_copy.shift
35
- args_copy.unshift(cmd_n_argv0.first)
36
- end
28
+ return cmd if args.nil? || args.empty?
29
+
30
+ args_copy = Array.new(args)
31
+ args_copy.shift if args_copy.first.is_a?(Hash)
32
+ args_copy.pop if args_copy.last.is_a?(Hash)
37
33
 
38
- cmd = args_copy.join(' ')
34
+ if args_copy.first.is_a?(Array)
35
+ cmd_n_argv0 = args_copy.shift
36
+ args_copy.unshift(cmd_n_argv0.first)
39
37
  end
38
+
39
+ cmd = args_copy.join(' ')
40
40
  end
41
41
 
42
42
  cmd
43
43
  end
44
- end
45
- end
46
44
 
47
- if TCellAgent.configuration.should_instrument_cmdi_exec?
48
- require('tcell_agent/instrumentation/cmdi/exec')
49
- else
50
- TCellAgent.logger.debug('Disabling cmdi Kernel::exec instrumentation')
51
- end
45
+ def self.parse_command_from_open(*args)
46
+ cmd = ''
47
+
48
+ TCellAgent::Instrumentation.safe_block('CMDI Parsing *args') do
49
+ return cmd if args.nil? || args.empty?
50
+
51
+ args_copy = Array.new(args)
52
+ first_arg = args_copy.shift
53
+
54
+ cmd = first_arg[1..-1] if first_arg && (first_arg.is_a? String) && first_arg[0] == '|'
55
+ end
52
56
 
53
- require('tcell_agent/instrumentation/cmdi/backtick')
54
- require('tcell_agent/instrumentation/cmdi/system')
55
- require('tcell_agent/instrumentation/cmdi/spawn')
56
- require('tcell_agent/instrumentation/cmdi/popen')
57
+ cmd
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,84 @@
1
+ require 'tcell_agent/policies/policy_types'
2
+ require 'tcell_agent/utils/strings'
3
+ require 'tcell_agent/configuration'
4
+
5
+ module TCellAgent
6
+ module Instrumentation
7
+ module Lfi
8
+ def self.block_file_access?(path, mode)
9
+ TCellAgent::Instrumentation.safe_block('Checking Local Files Policy') do
10
+ if TCellAgent::Utils::Strings.present?(path)
11
+ lfi_policy = TCellAgent.policy(TCellAgent::PolicyTypes::LFI)
12
+
13
+ request_env = TCellAgent::Instrumentation::Rails::Middleware::ContextMiddleware::THREADS.fetch(
14
+ Thread.current.object_id, {}
15
+ )
16
+
17
+ tcell_context = request_env[TCellAgent::Instrumentation::TCELL_ID]
18
+ return lfi_policy.block_file_access?(path, mode, tcell_context)
19
+ end
20
+ end
21
+
22
+ false
23
+ end
24
+
25
+ def self.extract_path_mode(*args)
26
+ path = ''
27
+ mode = ''
28
+
29
+ TCellAgent::Instrumentation.safe_block('LFI Parsing *args') do
30
+ return ['', ''] if args.nil? || args.empty?
31
+
32
+ args_copy = Array.new(args)
33
+ path = args_copy.shift
34
+ mode = args_copy.shift || 'r'
35
+
36
+ if path && path.to_s[0] != '|'
37
+ path = File.expand_path(path.to_s)
38
+
39
+ mode = if mode && mode.is_a?(Hash)
40
+ convert_mode(mode[:mode])
41
+ else
42
+ convert_mode(mode)
43
+ end
44
+
45
+ [path, mode]
46
+ else
47
+ ['', '']
48
+ end
49
+ end
50
+ end
51
+
52
+ def self.extract_path_mode_argf
53
+ path = ''
54
+ mode = 'Read'
55
+
56
+ TCellAgent::Instrumentation.safe_block('LFI Parsing ARGF') do
57
+ if ARGF.eof? && !ARGV.empty?
58
+ argv_copy = Array.new(ARGV)
59
+ path = argv_copy.shift
60
+ else
61
+ path = ARGF.filename
62
+ end
63
+
64
+ if path && path.to_s[0] != '|'
65
+ [File.expand_path(path.to_s), mode]
66
+ else
67
+ ['', '']
68
+ end
69
+ end
70
+ end
71
+
72
+ def self.convert_mode(mode)
73
+ if mode.is_a? String
74
+ return 'ReadWrite' if mode.include? '+'
75
+ return 'Write' if (mode.include? 'w') || (mode.include? 'a')
76
+ elsif mode.is_a? Numeric
77
+ return 'ReadWrite' if (mode & ::File::RDWR) != 0
78
+ return 'Write' if (mode & ::File::WRONLY) != 0
79
+ end
80
+ 'Read'
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,25 @@
1
+ class File
2
+ class << self
3
+ alias_method :tcell_original_new, :new
4
+ def new(*args, &block)
5
+ path, mode = TCellAgent::Instrumentation::Lfi.extract_path_mode(*args)
6
+
7
+ if TCellAgent::Instrumentation::Lfi.block_file_access?(path, mode)
8
+ raise IOError, "tCell.io Agent: Attempted access to file #{path} with mode #{mode} denied"
9
+ end
10
+
11
+ tcell_original_new(*args, &block)
12
+ end
13
+
14
+ alias_method :tcell_original_open, :open
15
+ def open(*args, &block)
16
+ path, mode = TCellAgent::Instrumentation::Lfi.extract_path_mode(*args)
17
+
18
+ if TCellAgent::Instrumentation::Lfi.block_file_access?(path, mode)
19
+ raise IOError, "tCell.io Agent: Attempted access to file #{path} with mode #{mode} denied"
20
+ end
21
+
22
+ tcell_original_open(*args, &block)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,131 @@
1
+ class IO
2
+ class << self
3
+ alias_method :tcell_original_binread, :binread
4
+ def binread(*args, &block)
5
+ path, mode = TCellAgent::Instrumentation::Lfi.extract_path_mode(*args)
6
+
7
+ if !path.strip.empty? && TCellAgent::Instrumentation::Lfi.block_file_access?(path, mode)
8
+ raise IOError, "tCell.io Agent: Attempted access to file #{path} with mode #{mode} denied"
9
+ end
10
+
11
+ if path.empty?
12
+ cmd = TCellAgent::Cmdi.parse_command_from_open(*args)
13
+ if cmd && TCellAgent::Cmdi.block_command?(cmd)
14
+ raise "tCell.io Agent: Command not allowed by policy: #{cmd}"
15
+ end
16
+ end
17
+
18
+ tcell_original_binread(*args, &block)
19
+ end
20
+
21
+ alias_method :tcell_original_binwrite, :binwrite
22
+ def binwrite(*args, &block)
23
+ path, _mode = TCellAgent::Instrumentation::Lfi.extract_path_mode(*args)
24
+ mode = 'Write'
25
+
26
+ if TCellAgent::Instrumentation::Lfi.block_file_access?(path, mode)
27
+ raise IOError, "tCell.io Agent: Attempted access to file #{path} with mode #{mode} denied"
28
+ end
29
+
30
+ tcell_original_binwrite(*args, &block)
31
+ end
32
+
33
+ alias_method :tcell_original_foreach, :foreach
34
+ def foreach(*args, &block)
35
+ path, _mode = TCellAgent::Instrumentation::Lfi.extract_path_mode(*args)
36
+ mode = 'Read'
37
+
38
+ if TCellAgent::Instrumentation::Lfi.block_file_access?(path, mode)
39
+ raise IOError, "tCell.io Agent: Attempted access to file #{path} with mode #{mode} denied"
40
+ end
41
+
42
+ tcell_original_foreach(*args, &block)
43
+ end
44
+
45
+ alias_method :tcell_original_popen, :popen
46
+ def popen(*args, &block)
47
+ unless args.empty?
48
+ cmd = ''
49
+
50
+ TCellAgent::Instrumentation.safe_block('CMDI Parsing popen *args') do
51
+ args_copy = Array.new(args)
52
+ args_copy.shift if args_copy.first.is_a?(Hash)
53
+ args_copy.pop if args_copy.last.is_a?(Hash)
54
+
55
+ cmd = if args_copy.first.is_a?(String)
56
+ args_copy.shift
57
+ else
58
+ TCellAgent::Cmdi.parse_command(*args_copy.shift)
59
+ end
60
+ end
61
+
62
+ if TCellAgent::Cmdi.block_command?(cmd)
63
+ raise "tCell.io Agent: Command not allowed by policy: #{cmd}"
64
+ end
65
+ end
66
+
67
+ tcell_original_popen(*args, &block)
68
+ end
69
+
70
+ alias_method :tcell_original_read, :read
71
+ def read(*args, &block)
72
+ path, _mode = TCellAgent::Instrumentation::Lfi.extract_path_mode(*args)
73
+ mode = 'Read'
74
+
75
+ if !path.strip.empty? && TCellAgent::Instrumentation::Lfi.block_file_access?(path, mode)
76
+ raise IOError, "tCell.io Agent: Attempted access to file #{path} with mode #{mode} denied"
77
+ end
78
+
79
+ if path.empty?
80
+ cmd = TCellAgent::Cmdi.parse_command_from_open(*args)
81
+ if cmd && TCellAgent::Cmdi.block_command?(cmd)
82
+ raise "tCell.io Agent: Command not allowed by policy: #{cmd}"
83
+ end
84
+ end
85
+
86
+ tcell_original_read(*args, &block)
87
+ end
88
+
89
+ alias_method :tcell_original_readlines, :readlines
90
+ def readlines(*args, &block)
91
+ path, _mode = TCellAgent::Instrumentation::Lfi.extract_path_mode(*args)
92
+ mode = 'Read'
93
+
94
+ if !path.strip.empty? && TCellAgent::Instrumentation::Lfi.block_file_access?(path, mode)
95
+ raise IOError, "tCell.io Agent: Attempted access to file #{path} with mode #{mode} denied"
96
+ end
97
+
98
+ if path.empty?
99
+ cmd = TCellAgent::Cmdi.parse_command_from_open(*args)
100
+ if cmd && TCellAgent::Cmdi.block_command?(cmd)
101
+ raise "tCell.io Agent: Command not allowed by policy: #{cmd}"
102
+ end
103
+ end
104
+
105
+ tcell_original_readlines(*args, &block)
106
+ end
107
+
108
+ alias_method :tcell_original_sysopen, :sysopen
109
+ def sysopen(*args, &block)
110
+ path, mode = TCellAgent::Instrumentation::Lfi.extract_path_mode(*args)
111
+
112
+ if TCellAgent::Instrumentation::Lfi.block_file_access?(path, mode)
113
+ raise IOError, "tCell.io Agent: Attempted access to file #{path} with mode #{mode} denied"
114
+ end
115
+
116
+ tcell_original_sysopen(*args, &block)
117
+ end
118
+
119
+ alias_method :tcell_original_write, :write
120
+ def write(*args, &block)
121
+ path, _mode = TCellAgent::Instrumentation::Lfi.extract_path_mode(*args)
122
+ mode = 'Write'
123
+
124
+ if TCellAgent::Instrumentation::Lfi.block_file_access?(path, mode)
125
+ raise IOError, "tCell.io Agent: Attempted access to file #{path} with mode #{mode} denied"
126
+ end
127
+
128
+ tcell_original_write(*args, &block)
129
+ end
130
+ end
131
+ end