immunio 1.0.9 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 707599380d8fefd64b7025d8529745af7ed07df2
4
- data.tar.gz: 294b3c9d179e6943f88f3d7b8a0db6d72c3fd1bc
3
+ metadata.gz: fe54e75e874948ac23bb4981980420811c7c97a3
4
+ data.tar.gz: e43529302f807d4035281978c1a4b90bfa2c326c
5
5
  SHA512:
6
- metadata.gz: 0c8b6e5455a9806041a0049414561ee8e70161cd85f64ab7c0041cdd82cf70350a85ec83ab0a62a3d58c038dd530ebd36ca446afc09d290f64609d4d14d080f2
7
- data.tar.gz: cff8a8c2d49cff6bdf635918fa94dca3fe4db3ed70d02fc937c914f1420050dfebe58bc12b515fe5dcd449eb8a87b098c482d914c9e2048e1d6a327aaa1d694e
6
+ metadata.gz: 3ee656e08aaf902244d38a03653ae3db83d68a23528b981040f2ac6c888b264bc8435db61ded6ffd463b6507199ec99fce765f2e5ec0f883ad68082163e67649
7
+ data.tar.gz: 6ec875e6850070c952880d48ef282f4a0961fdd91ccba4929cc19fa9d1a4379d9fe714f3a57e3a6036c248fa714dfd5c330168077619263252d3249be4dba4fa
@@ -2,6 +2,7 @@ module Immunio
2
2
  DIR = File.expand_path(File.dirname(__FILE__))
3
3
 
4
4
  def self.activate!
5
+ require_relative "immunio/utils"
5
6
  require_relative "immunio/agent"
6
7
  require_relative "immunio/authentication"
7
8
 
@@ -11,7 +11,7 @@ module Immunio
11
11
 
12
12
  # Plugins that are enabled by default. Override using the `plugins_enabled`
13
13
  # and `plugins_disabled` configuration settings.
14
- DEFAULT_PLUGINS = ["xss", "file_io", "redirect", "sqli", "eval", "shell_command"]
14
+ DEFAULT_PLUGINS = ["xss", "file_io", "redirect", "sqli", "shell_command"]
15
15
 
16
16
  CONFIG_FILENAME = "immunio.yml"
17
17
 
@@ -20,21 +20,20 @@ module Immunio
20
20
  # of a String, may be provided to mix into the strict context hash.
21
21
  def self.context(additional_data=nil)
22
22
  # We can filter out at least the top two frames
23
- cache_key = Digest::SHA1.hexdigest(caller(2).join())
23
+ stack = caller(2).join "\n"
24
+
25
+ cache_key = Digest::SHA1.hexdigest stack
26
+
24
27
  if @@hash_cache.has_key?(cache_key) then
25
28
  loose_context = @@hash_cache[cache_key]["loose_context"]
26
29
  strict_context = @@hash_cache[cache_key]["strict_context"]
27
- stack = @@hash_cache[cache_key]["stack"]
28
- loose_stack = @@hash_cache[cache_key]["stack"]
29
30
 
30
31
  if Immunio.agent.config.log_context_data
31
32
  Immunio.logger.info {"Stack contexts from cache"}
32
33
  end
33
34
  else
34
35
  # Use ropes as they're faster than string concatenation
35
- loose_stack_rope = []
36
36
  loose_context_rope = []
37
- stack_rope = []
38
37
  strict_context_rope = []
39
38
 
40
39
  # drop the top frame as it's us, but retain the rest. Immunio frames
@@ -64,13 +63,6 @@ module Immunio
64
63
  strict_path = File.basename(frame[:path])
65
64
  end
66
65
 
67
- stack_rope << "\n" unless stack_rope.empty?
68
- stack_rope << frame[:path]
69
- stack_rope << ":"
70
- stack_rope << frame[:line]
71
- stack_rope << ":"
72
- stack_rope << frame[:label]
73
-
74
66
  strict_context_rope << "\n" unless strict_context_rope.empty?
75
67
  strict_context_rope << strict_path
76
68
  strict_context_rope << ":"
@@ -89,19 +81,9 @@ module Immunio
89
81
  loose_context_rope << File.basename(frame[:path])
90
82
  loose_context_rope << ":"
91
83
  loose_context_rope << frame[:label]
92
-
93
- # build a second seperate rope for the stack that determines ou loose context key
94
- # This includes filenames for usability -- just method names not being very good
95
- # for display purposes...
96
- loose_stack_rope << "\n" unless loose_stack_rope.empty?
97
- loose_stack_rope << frame[:path]
98
- loose_stack_rope << ":"
99
- loose_stack_rope << frame[:label]
100
-
101
84
  end
102
- stack = stack_rope.join()
103
85
  strict_stack = strict_context_rope.join()
104
- loose_stack = loose_stack_rope.join()
86
+ loose_stack = loose_context_rope.join()
105
87
 
106
88
  if Immunio.agent.config.log_context_data
107
89
  Immunio.logger.info {"Strict context stack:\n#{strict_stack}"}
@@ -109,12 +91,10 @@ module Immunio
109
91
  end
110
92
 
111
93
  strict_context = Digest::SHA1.hexdigest(strict_stack)
112
- loose_context = Digest::SHA1.hexdigest(loose_context_rope.join())
94
+ loose_context = Digest::SHA1.hexdigest(loose_stack)
113
95
  @@hash_cache[cache_key] = {
114
96
  "strict_context" => strict_context,
115
97
  "loose_context" => loose_context,
116
- "stack" => stack,
117
- "loose_stack" => loose_stack
118
98
  }
119
99
  end
120
100
 
@@ -126,7 +106,7 @@ module Immunio
126
106
  strict_context = Digest::SHA1.hexdigest(strict_context + additional_data)
127
107
  end
128
108
 
129
- return strict_context, loose_context, stack, loose_stack
109
+ return strict_context, loose_context, stack
130
110
  end
131
111
  end
132
112
  end
@@ -49,15 +49,35 @@ module Immunio
49
49
 
50
50
  # @template is a virtual template that doesn't contain the source. We need
51
51
  # to try to load the source. But, the virtual template doesn't know the
52
- # original format of the source template file. Grab the original format
53
- # from the view context and override the default of just :html when
54
- # when looking up the template.
55
- old_formats = context.lookup_context.formats
52
+ # original format of the source template file.
53
+ #
54
+ # First, try to load it using the Rails defaults (usually "html" and
55
+ # "txt"). If that doesn't work, try to use the original format from the
56
+ # virtual template.
57
+ #
58
+ # Though one might think the format from the virtual template would always
59
+ # work, unfortunately the format from the template refers to the "type" of
60
+ # the template, which may or may not be the same as the format of the
61
+ # lookup context, which specifies the file extension of the template. Ugh,
62
+ # naming... For example, the lookup context format may be "txt" while the
63
+ # template format is "text".
64
+ #
65
+ # Astute readers may note that there's the possibility the template
66
+ # extension is not in the Rails default list of lookup formats, and also
67
+ # does not match the template type. We are just going to leave that for
68
+ # another day, and hope that day never comes...
56
69
  begin
57
- context.lookup_context.formats = @template.formats
58
70
  refreshed = Immunio::IOHooks.paused { @template.refresh(context) }
59
- ensure
60
- context.lookup_context.formats = old_formats
71
+ rescue
72
+ begin
73
+ old_formats = context.lookup_context.formats
74
+ context.lookup_context.formats = @template.formats
75
+ refreshed = Immunio::IOHooks.paused { @template.refresh(context) }
76
+ rescue
77
+ Immunio.logger.warn { "Failed to refresh template source from #{@template} using contexts #{old_formats} and #{@template.formats}" }
78
+ ensure
79
+ context.lookup_context.formats = old_formats
80
+ end
61
81
  end
62
82
 
63
83
  return if refreshed.nil?
@@ -337,7 +357,7 @@ module Immunio
337
357
  extend ActiveSupport::Concern
338
358
 
339
359
  included do
340
- alias_method_chain :add_expr, :immunio
360
+ Immunio::Utils.alias_method_chain self, :add_expr, :immunio
341
361
  end
342
362
 
343
363
  def add_expr_with_immunio(src, code, indicator)
@@ -362,7 +382,7 @@ module Immunio
362
382
  extend ActiveSupport::Concern
363
383
 
364
384
  included do
365
- alias_method_chain :push_script, :immunio
385
+ Immunio::Utils.alias_method_chain self, :push_script, :immunio
366
386
  end
367
387
 
368
388
  def push_script_with_immunio(code, opts = {}, &block)
@@ -385,7 +405,7 @@ module Immunio
385
405
  extend ActiveSupport::Concern
386
406
 
387
407
  included do
388
- alias_method_chain :render_template, :immunio
408
+ Immunio::Utils.alias_method_chain self, :render_template, :immunio
389
409
  end
390
410
 
391
411
  def render_template_with_immunio(template, *args)
@@ -407,7 +427,7 @@ module Immunio
407
427
  extend ActiveSupport::Concern
408
428
 
409
429
  included do
410
- alias_method_chain :render, :immunio
430
+ Immunio::Utils.alias_method_chain self, :render, :immunio
411
431
  end
412
432
 
413
433
  def render_with_immunio(context, *args, &block)
@@ -428,7 +448,7 @@ module Immunio
428
448
  extend ActiveSupport::Concern
429
449
 
430
450
  included do
431
- alias_method_chain :write_fragment, :immunio
451
+ Immunio::Utils.alias_method_chain self, :write_fragment, :immunio
432
452
  end
433
453
 
434
454
  def write_fragment_with_immunio(key, content, options = nil)
@@ -10,7 +10,7 @@ module Immunio
10
10
  extend ActiveSupport::Concern
11
11
 
12
12
  included do
13
- alias_method_chain :quote, :immunio if method_defined? :quote
13
+ Immunio::Utils.alias_method_chain self, :quote, :immunio if method_defined? :quote
14
14
  end
15
15
 
16
16
  IGNORED_TYPES = [TrueClass, FalseClass, NilClass, Fixnum, Bignum, Float].freeze
@@ -69,7 +69,7 @@ module Immunio
69
69
  end
70
70
  end
71
71
  end
72
- alias_method_chain :sanitize_sql_array, :immunio
72
+ Immunio::Utils.alias_method_chain self, :sanitize_sql_array, :immunio
73
73
  end
74
74
  end
75
75
  end
@@ -78,7 +78,7 @@ module Immunio
78
78
  extend ActiveSupport::Concern
79
79
 
80
80
  included do
81
- alias_method_chain :accept, :immunio if method_defined? :accept
81
+ Immunio::Utils.alias_method_chain self, :accept, :immunio if method_defined? :accept
82
82
  end
83
83
 
84
84
  def accept_with_immunio(object, *args)
@@ -666,7 +666,7 @@ module Immunio
666
666
  extend ActiveSupport::Concern
667
667
 
668
668
  included do
669
- alias_method_chain :log, :immunio if method_defined? :log
669
+ Immunio::Utils.alias_method_chain self, :log, :immunio if method_defined? :log
670
670
  end
671
671
 
672
672
  def log_with_immunio(sql, name = "SQL", binds = [], *args)
@@ -3,7 +3,9 @@ module Immunio
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- alias_method_chain :verify_authenticity_token, :immunio if method_defined? :verify_authenticity_token
6
+ if method_defined? :verify_authenticity_token
7
+ Immunio::Utils.alias_method_chain self, :verify_authenticity_token, :immunio
8
+ end
7
9
  end
8
10
 
9
11
  protected
@@ -13,7 +13,7 @@ if defined? Devise
13
13
  extend ActiveSupport::Concern
14
14
 
15
15
  included do
16
- alias_method_chain :send_reset_password_instructions, :immunio
16
+ Immunio::Utils.alias_method_chain self, :send_reset_password_instructions, :immunio
17
17
  end
18
18
 
19
19
  def send_reset_password_instructions_with_immunio(attributes={})
@@ -7,22 +7,22 @@ module Immunio
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  def self.extended(base)
10
- base.singleton_class.alias_method_chain :eval, :immunio
10
+ Immunio::Utils.alias_method_chain base.singleton_class, :eval, :immunio
11
11
  end
12
12
 
13
13
  def self.included(base)
14
- base.alias_method_chain :eval, :immunio
14
+ Immunio::Utils.alias_method_chain base, :eval, :immunio
15
15
  end
16
16
 
17
17
  protected
18
18
  def eval_with_immunio(*args)
19
19
  Immunio.logger.debug {"Eval_with_immunio with args: #{args}"}
20
20
  Request.time "plugin", "#{Module.nesting[0]}::#{__method__}" do
21
- strict_context, loose_context, stack, loose_stack = Immunio::Context.context()
21
+ strict_context, loose_context, stack = Immunio::Context.context()
22
22
  Immunio.run_hook! "eval", "eval",
23
23
  parameters: args,
24
24
  context_key: loose_context,
25
- stack: loose_stack
25
+ stack: stack
26
26
  Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
27
27
  if args[1].nil?
28
28
  # eval call did not include a binding, so we eval it in the caller's binding
@@ -148,18 +148,13 @@ module Immunio
148
148
  end
149
149
 
150
150
  def extract_session_id(session)
151
- session_id = case
152
- when session.respond_to?(:id)
151
+ session_id = if session.respond_to?(:id)
153
152
  session.id
154
- when session[:id]
155
- session[:id]
156
- when session[:session_id]
157
- session[:session_id]
158
153
  else
159
- return nil
154
+ session[:id] || session[:session_id]
160
155
  end
161
156
 
162
- Digest::SHA1.hexdigest(session_id)
157
+ Digest::SHA1.hexdigest(session_id) if session_id
163
158
  end
164
159
  end
165
160
 
@@ -19,17 +19,17 @@ module Immunio
19
19
 
20
20
  def self.inject(mod, name, methods)
21
21
  mod.class_eval <<-EOF
22
- def self.extended(base) # def self.extended(base)
23
- #{methods.inspect}.each do |method| # ["read", "binread"].each do |method|
24
- base.singleton_class.alias_method_chain method, :immunio # base.singleton_class.alias_method_chain method, :immunio
25
- end # end
26
- end # end
22
+ def self.extended(base)
23
+ #{methods.inspect}.each do |method|
24
+ Immunio::Utils.alias_method_chain base.singleton_class, method, :immunio
25
+ end
26
+ end
27
27
 
28
- def self.included(base) # def self.included(base)
29
- #{methods.inspect}.each do |method| # ["read", "binread"].each do |method|
30
- base.alias_method_chain method, :immunio # base.alias_method_chain method, :immunio
31
- end # end
32
- end # end
28
+ def self.included(base)
29
+ #{methods.inspect}.each do |method|
30
+ Immunio::Utils.alias_method_chain base, method, :immunio
31
+ end
32
+ end
33
33
  EOF
34
34
  Immunio.logger.debug { "IO: successfully chained #{name} #{methods}" }
35
35
  methods.each do |method|
@@ -39,12 +39,12 @@ module Immunio
39
39
  #{method}_without_immunio(*args, &block)
40
40
  else
41
41
  Request.time "plugin", "IO::#{method}" do #
42
- strict_context, loose_context, stack, loose_stack = Immunio::Context.context()
42
+ strict_context, loose_context, stack = Immunio::Context.context()
43
43
 
44
44
  Immunio.run_hook! "io", "file_io", # Immunio.run_hook! "io", "open",
45
45
  method: "#{name}#{method}", # open_method: "IO.read",
46
46
  parameters: args, # parameters: args
47
- stack: loose_stack, #
47
+ stack: stack, #
48
48
  context_key: loose_context, #
49
49
  cwd: Dir.pwd
50
50
  Request.pause "plugin", "IO::#{method}" do #
@@ -75,11 +75,11 @@ module Immunio
75
75
  Kernel.class_eval <<-EOF
76
76
  define_method :backtick_with_immunio do |cmd|
77
77
  Request.time "plugin", "Shell::backtick" do
78
- strict_context, loose_context, stack, loose_stack = Immunio::Context.context()
78
+ strict_context, loose_context, stack = Immunio::Context.context()
79
79
  Immunio.run_hook! "io", "file_io",
80
80
  method: "Kernel.backtick",
81
81
  parameters: [cmd],
82
- stack: loose_stack,
82
+ stack: stack,
83
83
  context_key: loose_context,
84
84
  cwd: Dir.pwd
85
85
  Request.pause "plugin", "Shell::backtick" do
@@ -5,7 +5,7 @@ module Immunio
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- alias_method_chain :redirect_to, :immunio if method_defined? :redirect_to
8
+ Immunio::Utils.alias_method_chain self, :redirect_to, :immunio if method_defined? :redirect_to
9
9
  end
10
10
 
11
11
  protected
@@ -22,11 +22,11 @@ module Immunio
22
22
  loptions = loptions.call
23
23
  end
24
24
  if loptions.is_a? String then
25
- strict_context, loose_context, stack, loose_stack = Immunio::Context.context() # rubocop:disable Lint/UselessAssignment
25
+ strict_context, loose_context, stack = Immunio::Context.context() # rubocop:disable Lint/UselessAssignment
26
26
  Immunio.run_hook! "redirect", "framework_redirect",
27
27
  destination_url: loptions,
28
28
  context_key: loose_context,
29
- stack: loose_stack
29
+ stack: stack
30
30
  end
31
31
  Request.pause "plugin", "#{Module.nesting[0]}::#{__method__}" do
32
32
  redirect_to_without_immunio( options, response_status )
@@ -110,6 +110,19 @@ module Immunio
110
110
  Request.current = nil
111
111
  end
112
112
 
113
+ def make_safe_meta(meta)
114
+ # Some versions of rails, like 4.2.0, fail to JSONify some objects properly.
115
+ safe_meta = {}
116
+ meta.each do |key, value|
117
+ if value.is_a?(Numeric) || value.is_a?(String) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
118
+ safe_meta[key] = value
119
+ else
120
+ safe_meta[key] = value.inspect
121
+ end
122
+ end
123
+ safe_meta
124
+ end
125
+
113
126
  # Run the `hook` and return a hash eg.: `{ "allow": true }`.
114
127
  def run_hook(plugin, hook, meta={})
115
128
  request = Request.current
@@ -164,29 +177,41 @@ module Immunio
164
177
  Immunio.logger.debug { "Result from #{hook} hook: (can't log result due to encoding incompatibility)" }
165
178
  end
166
179
 
167
- result || {}
168
-
180
+ result ||= {}
181
+
182
+ if result.respond_to?(:has_key?) and result.has_key?(:diagnostics)
183
+ result[:diagnostics].to_h.each_value do |diag|
184
+ Immunio.logger.debug { "Sending Diagnostic Report: #{diag['message']}" }
185
+ msg = {
186
+ type: "engine.diagnostic",
187
+ diagnostic_type: diag['report_type'],
188
+ diagnostic_message: diag['message'],
189
+ diagnostic_meta: diag['meta'],
190
+ diagnostic_version: "0.0.2",
191
+ agent_version: Immunio::VERSION,
192
+ request_id: request.id,
193
+ timestamp: timestamp,
194
+ plugin: plugin,
195
+ hook: hook,
196
+ meta: make_safe_meta(meta),
197
+ vmcode_version: request.vm.code_version,
198
+ vmdata_version: request.vm.data_version
199
+ }
200
+ @channel.send_message msg
201
+ end
202
+ end
203
+ result
169
204
  # Previosuly this only caught VMErrors, however other exceptions can cause 500s
170
205
  # so to be on the safe side make sure we catch anything raised within the VM call --ol
171
206
  rescue StandardError => e
172
207
  # Log and discard VM errors
173
208
 
174
- # Some versions of rails, like 4.2.0, fail to JSONify some objects properly.
175
- safe_meta = {}
176
- meta.each do |key, value|
177
- if value.is_a?(Numeric) || value.is_a?(String) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
178
- safe_meta[key] = value
179
- else
180
- safe_meta[key] = value.inspect
181
- end
182
- end
183
-
184
209
  log_and_send_error e, "Error running hook #{hook}",
185
210
  request_id: request.id,
186
211
  timestamp: timestamp,
187
212
  plugin: plugin,
188
213
  hook: hook,
189
- meta: safe_meta,
214
+ meta: make_safe_meta(meta),
190
215
  vmcode_version: request.vm.code_version,
191
216
  vmdata_version: request.vm.data_version
192
217
 
@@ -152,6 +152,6 @@ module Rufus::Lua
152
152
  raise
153
153
  end
154
154
  end
155
- alias_method_chain :call, :stack_reset
155
+ Immunio::Utils.alias_method_chain self, :call, :stack_reset
156
156
  end
157
157
  end
@@ -0,0 +1,29 @@
1
+ module Immunio
2
+ module Utils
3
+ # Taken by ActiveSupport to maintain privacy of aliased methods but reduce
4
+ # our dependency on Rails
5
+ def self.alias_method_chain(klass, target, feature)
6
+ # Strip out punctuation on predicates, bang or writer methods since
7
+ # e.g. target?_without_feature is not a valid method name.
8
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
9
+ yield(aliased_target, punctuation) if block_given?
10
+
11
+ with_method = "#{aliased_target}_with_#{feature}#{punctuation}"
12
+ without_method = "#{aliased_target}_without_#{feature}#{punctuation}"
13
+
14
+ klass.class_eval do
15
+ alias_method without_method, target
16
+ alias_method target, with_method
17
+
18
+ case
19
+ when public_method_defined?(without_method)
20
+ public target
21
+ when protected_method_defined?(without_method)
22
+ protected target
23
+ when private_method_defined?(without_method)
24
+ private target
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,5 +1,5 @@
1
1
  module Immunio
2
2
  AGENT_TYPE = "agent-ruby"
3
- VERSION = "1.0.9"
3
+ VERSION = "1.0.10"
4
4
  VM_VERSION = "2.2.0"
5
5
  end
@@ -19,6 +19,7 @@ LUA_SRC = \
19
19
  lib/DataDumper.lua \
20
20
  lib/date.lua \
21
21
  lib/defence.lua \
22
+ lib/diag.lua \
22
23
  lib/escape.lua \
23
24
  lib/extensions.lua \
24
25
  lib/hooks.lua \
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: immunio
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.9
4
+ version: 1.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Immunio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-11 00:00:00.000000000 Z
11
+ date: 2016-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -161,6 +161,7 @@ files:
161
161
  - lib/immunio/rufus_lua_ext/state.rb
162
162
  - lib/immunio/rufus_lua_ext/table.rb
163
163
  - lib/immunio/rufus_lua_ext/utils.rb
164
+ - lib/immunio/utils.rb
164
165
  - lib/immunio/version.rb
165
166
  - lib/immunio/vm.rb
166
167
  - lua-hooks/Makefile
@@ -438,7 +439,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
438
439
  version: '0'
439
440
  requirements: []
440
441
  rubyforge_project:
441
- rubygems_version: 2.5.1
442
+ rubygems_version: 2.4.5
442
443
  signing_key:
443
444
  specification_version: 4
444
445
  summary: Immunio Ruby agent