immunio 1.0.9 → 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
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