immunio 1.0.4 → 1.0.5

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.
@@ -20,7 +20,7 @@ module Immunio
20
20
  @paused_times = {}
21
21
  @start_time = Time.now
22
22
 
23
- Immunio.logger.debug "Created new Request #{id} with data #{@data}"
23
+ Immunio.logger.debug { "Created new Request #{id} with data #{@data}" }
24
24
  end
25
25
 
26
26
  def id
@@ -78,7 +78,7 @@ module Immunio
78
78
  result = Immunio.run_hook "request", "should_report"
79
79
  # If the hook doesn't exist, turn a nil report value into a false value
80
80
  report = !!result["report"]
81
- Immunio.logger.debug "Report request: #{report}"
81
+ Immunio.logger.debug { "Report request: #{report}" }
82
82
  report
83
83
  end
84
84
 
@@ -98,7 +98,7 @@ module Immunio
98
98
 
99
99
  def self.current=(request)
100
100
  Thread.current["immunio.request"] = request
101
- Immunio.logger.debug "Setting current request for thread #{Thread.current.object_id} to #{request && request.id || nil}"
101
+ Immunio.logger.debug { "Setting current request for thread #{Thread.current.object_id} to #{request && request.id || nil}" }
102
102
  end
103
103
 
104
104
  # This shim exists to preserve the stack depth into hooks when self.time and self.pause are
@@ -1,5 +1,5 @@
1
1
  module Immunio
2
2
  AGENT_TYPE = "agent-ruby"
3
- VERSION = "1.0.4"
3
+ VERSION = "1.0.5"
4
4
  VM_VERSION = "2.2.0"
5
5
  end
@@ -54,7 +54,7 @@ module Immunio
54
54
  @functions = functions
55
55
  @utils = utils
56
56
  }
57
- Immunio.logger.info "Lua code updated to version #{version}."
57
+ Immunio.logger.info { "Lua code updated to version #{version}." }
58
58
  end
59
59
 
60
60
  def update_data(version, data)
@@ -65,7 +65,7 @@ module Immunio
65
65
  @data_version = version
66
66
  @data = new_data
67
67
  }
68
- Immunio.logger.debug "Lua data updated to version #{version}."
68
+ Immunio.logger.debug { "Lua data updated to version #{version}." }
69
69
  end
70
70
 
71
71
  def current_state
@@ -76,7 +76,7 @@ module Immunio
76
76
  end
77
77
 
78
78
  def new_vm
79
- Immunio.logger.debug "Creating new Lua VM"
79
+ Immunio.logger.debug { "Creating new Lua VM" }
80
80
  dev_mode_hook_update if @dev_mode
81
81
 
82
82
  @update_lock.synchronize {
@@ -87,7 +87,7 @@ module Immunio
87
87
  def dev_mode_hook_update
88
88
  # Load default hook handlers if present (they do not ship with the gem)
89
89
  path = File.expand_path("#{Immunio::DIR}/../lua-hooks/hooks")
90
- Immunio.logger.info "Checking hook handlers from #{path}"
90
+ Immunio.logger.info { "Checking hook handlers from #{path}" }
91
91
 
92
92
  unique_files = Dir[path + "/*.lua"].collect do |file|
93
93
  name = File.basename(file, ".*")
@@ -100,7 +100,7 @@ module Immunio
100
100
  end
101
101
  checksum = unique_files.join
102
102
  if checksum == @dev_checksum
103
- Immunio.logger.info "Reusing dev vm, files unchanged"
103
+ Immunio.logger.info { "Reusing dev vm, files unchanged" }
104
104
  return
105
105
  end
106
106
 
@@ -118,7 +118,7 @@ module Immunio
118
118
  handlers[name] = data
119
119
  handlers
120
120
  end
121
- Immunio.logger.info "Updating dev vm code, files changed"
121
+ Immunio.logger.info { "Updating dev vm code, files changed" }
122
122
  update_code("DEV-#{Time.now.strftime("%H:%M:%S")}", functions)
123
123
  @dev_checksum = checksum
124
124
  end
@@ -14,16 +14,61 @@ SRC = \
14
14
  ext/lpeg/lpprint.c \
15
15
  ext/lpeg/lpvm.c
16
16
 
17
+ LUA_SRC = \
18
+ lib/cookie.lua \
19
+ lib/DataDumper.lua \
20
+ lib/date.lua \
21
+ lib/defence.lua \
22
+ lib/escape.lua \
23
+ lib/extensions.lua \
24
+ lib/hooks.lua \
25
+ lib/idn.lua \
26
+ lib/lexgraph.lua \
27
+ lib/neturl.lua \
28
+ lib/paths.lua \
29
+ lib/permit.lua \
30
+ lib/sanitize_sql.lua \
31
+ lib/semver.lua \
32
+ lib/sha1.lua \
33
+ lib/snap.lua \
34
+ lib/utils.lua \
35
+ lib/lexers/bash_dqstr.lua \
36
+ lib/lexers/bash.lua \
37
+ lib/lexers/css_attr.lua \
38
+ lib/lexers/css.lua \
39
+ lib/lexers/html.lua \
40
+ lib/lexers/javascript.lua \
41
+ lib/lexer.lua \
42
+ lib/hooks/authenticate.lua \
43
+ lib/hooks/bad_cookie.lua \
44
+ lib/hooks/custom_threat.lua \
45
+ lib/hooks/eval.lua \
46
+ lib/hooks/exception.lua \
47
+ lib/hooks/file_io.lua \
48
+ lib/hooks/framework_csrf_check.lua \
49
+ lib/hooks/framework_login.lua \
50
+ lib/hooks/framework_password_reset.lua \
51
+ lib/hooks/framework_redirect.lua \
52
+ lib/hooks/framework_session.lua \
53
+ lib/hooks/framework_user.lua \
54
+ lib/hooks/http_request_finish.lua \
55
+ lib/hooks/http_request_start.lua \
56
+ lib/hooks/http_response_start.lua \
57
+ lib/hooks/should_report.lua \
58
+ lib/hooks/sql_execute.lua \
59
+ lib/hooks/template_render_done.lua
60
+
17
61
  OBJ = ${SRC:.c=.o}
18
62
 
19
63
  SHA1OBJ = ext/sha1/sha1.o
64
+ OBJ = ${SRC:.c=.o} ${SHA1OBJ}
20
65
 
21
66
  # Library archive. Used for compiling along agent bindings.
22
67
  SO_OUT = libimmunio.so
23
68
  A_OUT = libimmunio.a
24
69
 
25
70
  # CLI for running tests
26
- CLI = lua
71
+ CLI = ./lua
27
72
  CLI_SRC = ext/luajit/src/luajit.c ${SRC}
28
73
 
29
74
  XCFLAGS =
@@ -59,7 +104,7 @@ all: ${CLI} ${INIT_HOOK} ${HOOKS_TARBALL} ${HOOKS_SRCS_TARBALL}
59
104
  ${SHA1OBJ}:
60
105
  ${CC} -O -c ${INCS} -o ${SHA1OBJ} ${SHA1OBJ:.o=.c}
61
106
 
62
- ${SO_OUT}: ${OBJ} ${LUAJIT_OBJ} ${SHA1OBJ}
107
+ ${SO_OUT}: ${OBJ} ${LUAJIT_OBJ}
63
108
  ${CC} -shared ${CFLAGS} ${LIBS} -o $@ -lc $^
64
109
 
65
110
  ${A_OUT}: ${OBJ}
@@ -77,11 +122,9 @@ ${CLI}: ${CLI_SRC} ${LUAJIT_OBJ} ${SHA1OBJ}
77
122
  ${CC} ${CFLAGS} -DLUA_UNSAFE_MODE ${INCS} -o $@ $^ ${LIBS}
78
123
 
79
124
  # Concatenate init hooks into one __init__.lua hook with two newlines in between
80
- ${INIT_HOOK}: hooks/init/*.lua hooks/init/__header__
125
+ ${INIT_HOOK}: ${LUA_SRC} ${CLI}
81
126
  rm -f hooks/__init__.lua
82
- cat hooks/init/__header__ >> hooks/__init__.lua
83
- for file in hooks/init/*.lua; do cat "$$file" >> hooks/__init__.lua; printf "\n\n" >> hooks/__init__.lua; done
84
- echo "return utils" >> hooks/__init__.lua
127
+ ${CLI} ./luald.lua ${LUA_SRC} > hooks/__init__.lua
85
128
 
86
129
  build/%.lua: hooks/%.lua ${CLI}
87
130
  @mkdir -p build
@@ -1,290 +1,62 @@
1
- -- This file is executed when the Lua VM boots.
2
- require 'encode'
3
-
4
- -- This is required to make lexers load from test harness.
5
- -- In VM the path is handled for us by vm.rb --ol
6
- lexer_path='lib/lexers/?.lua'
7
- package.path = package.path..';'..lexer_path
8
-
9
- -- Define the environment available to code executing in the VM.
10
- -- All available functions must be declared here.
11
- -- Make sure the function is safe before adding it here.
12
- -- See http://lua-users.org/wiki/SandBoxes
13
- SANDBOX_ENV = {
14
- -- Lua libs
15
- ipairs = ipairs,
16
- next = next,
17
- pairs = pairs,
18
- pcall = pcall,
19
- tonumber = tonumber,
20
- tostring = tostring,
21
- type = type,
22
- unpack = unpack,
23
- assert = assert,
24
- error = error,
25
- getmetatable = getmetatable,
26
- setmetatable = setmetatable,
27
- rawget = rawget,
28
- rawset = rawset,
29
- collectgarbage = collectgarbage,
30
- math = math,
31
- string = string,
32
- bit = {
33
- band = bit.band,
34
- extract = bit.extract,
35
- bor = bit.bor,
36
- bnot = bit.bnot,
37
- arshift = bit.arshift,
38
- rshift = bit.rshift,
39
- rrotate = bit.rrotate,
40
- replace = bit.replace,
41
- lshift = bit.lshift,
42
- lrotate = bit.lrotate,
43
- btest = bit.btest,
44
- bxor = bit.bxor
45
- },
46
- coroutine = {
47
- create = coroutine.create,
48
- resume = coroutine.resume,
49
- running = coroutine.running,
50
- status = coroutine.status,
51
- wrap = coroutine.wrap,
52
- yield = coroutine.yield,
53
- },
54
- debug = {
55
- -- Block most debug in sandbox, but allow tracebacks
56
- traceback = debug.traceback
57
- },
58
- select = select,
59
- sha1 = sha1,
60
- utf8 = {
61
- byte = utf8.byte,
62
- char = utf8.char,
63
- find = utf8.find,
64
- format = utf8.format,
65
- gmatch = utf8.gmatch,
66
- gsub = utf8.gsub,
67
- len = utf8.len,
68
- lower = utf8.lower,
69
- match = utf8.match,
70
- rep = utf8.rep,
71
- reverse = utf8.reverse,
72
- sub = utf8.sub,
73
- upper = utf8.upper,
74
- split = utf8.split,
75
- escape = utf8.escape,
76
- charpos = utf8.charpos,
77
- insert = utf8.insert,
78
- remove = utf8.remove,
79
- next = utf8.next,
80
- ncasecmp = utf8.ncasecmp,
81
- },
82
- table = {
83
- insert = table.insert,
84
- maxn = table.maxn,
85
- remove = table.remove,
86
- sort = table.sort,
87
- map = table.map,
88
- reduce = table.reduce,
89
- length = table.length,
90
- concat = table.concat,
91
- },
92
- libinjection = {
93
- sqli = libinjection.sqli,
94
- fingerprint = libinjection.fingerprint,
95
- xss = libinjection.xss,
96
- sqli_tokenize = libinjection.sqli_tokenize
97
- },
98
- -- LPeg Library
99
- lpeg = {
100
- ptree = lpeg.ptree,
101
- pcode = lpeg.pcode,
102
- match = lpeg.match,
103
- B = lpeg.B,
104
- V = lpeg.V,
105
- C = lpeg.C,
106
- Cc = lpeg.Cc,
107
- Cmt = lpeg.Cmt,
108
- Cb = lpeg.Cb,
109
- Carg = lpeg.Carg,
110
- Cp = lpeg.Cp,
111
- Cs = lpeg.Cs,
112
- Ct = lpeg.Ct,
113
- Cf = lpeg.Cf,
114
- Cg = lpeg.Cg,
115
- P = lpeg.P,
116
- S = lpeg.S,
117
- R = lpeg.R,
118
- locale = lpeg.locale,
119
- version = lpeg.version,
120
- setmaxstack = lpeg.setmaxstack,
121
- type = lpeg.type,
122
- },
123
- -- pre built lexer library
124
- -- the call to load here will both load the code
125
- -- and compile the LPeg grammar
126
- lexers = {
127
- lexer = require('lexers/lexer'),
128
- bash = require('lexers/lexer').load('bash'), -- bash
129
- bash_dqstr = require('lexers/lexer').load('bash_dqstr'), -- bash strings
130
- html = require('lexers/lexer').load('html'),
131
- javascript = require('lexers/lexer').load('javascript'),
132
- css = require('lexers/lexer').load('css'),
133
- css_attr = require('lexers/lexer').load('css_attr'),
134
- },
135
- -- Immunio vars
136
- serverdata = {}, -- Default empty serverdata
137
- agentdata = {},
138
- utils = {}, -- Used to store utility functions declared in the sandbox.
139
- -- pass mode flags into the VM
140
- DEV_MODE = DEV_MODE,
141
- DEBUG_MODE = DEBUG_MODE,
142
- LUA_PLATFORM = LUA_PLATFORM or 'unix',
143
- IMMUNIO_KEY = IMMUNIO_KEY,
144
- IMMUNIO_SECRET = IMMUNIO_SECRET
145
- }
146
-
147
- -- Enable a few more things in dev mode. For debugging.
148
- if DEBUG_MODE or DEV_MODE then
149
- SANDBOX_ENV.print = print
150
- SANDBOX_ENV.snapshot = snapshot
151
- else
152
- SANDBOX_ENV.print = function(...) end
1
+ VM_VERSION = 1
2
+ -- Global reference to hold the VM itself.
3
+ VM = nil
4
+
5
+ -- Create global agentdata and serverdata
6
+ agentdata = agentdata or {}
7
+ serverdata = serverdata or {}
8
+
9
+ -- XXX Java agent has built in assumption that this function exists before VM
10
+ -- initialisation.
11
+ -- Encode a Lua object to be sent to the server.
12
+ function encode(object)
13
+ return cmsgpack.pack(object)
153
14
  end
154
15
 
155
-
156
- -- Perform a VM call a method of a lua pseudo-object
157
- function sandboxed_method_call(method, object, vars)
158
- if DEBUG_MODE then
159
- SANDBOX_ENV.utils.debug_prefix = "UNKNOWN"
160
- -- Change the values here to toggle debugging per module.
161
- SANDBOX_ENV.utils.debug_module_prefixes = {
162
- UNKNOWN = true,
163
- IO = true,
164
- SQLi = true,
165
- ExceptionHandler = true,
166
- Redirect = true,
167
- XSS = true,
168
- Eval = true,
169
- }
170
- end
171
- -- Merges the vars and the default sandbox env.
172
- -- The vars can override the sandbox environment.
173
- -- The table is copied to keep data from leaking
174
- -- out of the functions.
175
- local merged_vars = {}
176
- merged_vars._G = merged_vars
177
- for k, v in pairs(SANDBOX_ENV) do
178
- merged_vars[k] = v
179
- end
180
-
16
+ -- Function called by the Agent to call and sandbox a function.
17
+ function sandboxed_call(method, vars)
18
+ local rval = nil
19
+ -- Merge caller supplied vars
181
20
  if vars then
21
+ -- utils.debug_dump("Merge vars from agent: ", vars)
182
22
  for k, v in pairs(vars) do
183
- merged_vars[k] = v
184
- end
185
- end
186
-
187
- -- XXX Open sandbox in DEBUG_MODE
188
- if DEBUG_MODE then
189
- merged_vars['__REAL_G'] = _G
190
- end
191
- -- Sets the environment of the function.
192
- setfenv(method, merged_vars)
193
- -- Call it!
194
- local rval = nil
195
- if object then
196
- rval = method(object)
197
- else
198
- rval = method()
199
- end
200
- -- Hint the lua VM GC that the references held to values in merged_vars don't
201
- -- count anymore. If we omit this line the function environment is held onto
202
- -- by the GC and we leak the universe... --ol
203
- setmetatable( merged_vars, {__mode = "v"} )
204
- -- Remove merged_vars from function environment so it can be collected sooner
205
- setfenv(method, _G)
206
- return rval
207
- end
208
-
209
- -- Function called by the VM to call and sandbox a function.
210
- function sandboxed_call(func, vars)
211
- return sandboxed_method_call(func, nil, vars)
212
- end
213
-
214
- if DEBUG_MODE then
215
- -- Memory Snapshot Debugger
216
- local saved_snapshot = {}
217
- local saved_usage = 0
218
- function dump_snapshot( label )
219
- collectgarbage()
220
- collectgarbage()
221
- saved_snapshot = snapshot.snapshot()
222
- saved_usage = collectgarbage('count')
223
- print("------------------------\nSNAPSHOT\n")
224
- print("USAGE: " .. saved_usage .. "\n")
225
- if label then print(label) end
226
- for k,v in pairs(saved_snapshot) do
227
- print( "ALLOCATION:" .. tostring(k):gsub("userdata:", "") .. " " .. v)
228
- end
229
- end
230
-
231
- function update_snapshot()
232
- collectgarbage()
233
- collectgarbage()
234
- saved_snapshot = snapshot.snapshot()
235
- saved_usage = collectgarbage('count')
236
- end
237
-
238
- function diff_snapshot( update )
239
- collectgarbage()
240
- collectgarbage()
241
- local S = snapshot.snapshot()
242
- local U = collectgarbage('count')
243
- local output = ("------------------------\nDIFF SNAPSHOT\n")
244
- output = output .. "USAGE DELTA: " .. U - saved_usage .. "\n"
245
- for k,v in pairs(S) do
246
- if saved_snapshot[k] == nil then
247
- output = output .. "ALLOCATION:" .. tostring(k):gsub("userdata:", "") .. " " .. v .. "\n"
248
-
23
+ if k ~= "utils" then -- XXX agent API compatability. Ignore utils.
24
+ _G[k] = v
249
25
  end
250
26
  end
251
- if update then saved_snapshot = S end
252
- return output
253
27
  end
254
-
255
- function diff_count_snapshot( update )
256
- collectgarbage()
257
- collectgarbage()
258
- local S = snapshot.snapshot()
259
- local U = collectgarbage('count')
260
- local total = 0
261
- local count = 0
262
- local output = ("------------------------\nCOUNT SNAPSHOT\n")
263
- for k,v in pairs(S) do
264
- total = total + 1
265
- if saved_snapshot[k] == nil then
266
- count = count + 1
28
+ if type(method) == "function" then
29
+ -- legacy hooks. Convert to new hook call
30
+ rval = method(vars)
31
+ if rval and type(rval) == 'table' then
32
+ -- Special handling for the __init__ hook
33
+ -- If rval contains a _vm_update key then (re)install the package loader
34
+ -- and (re)load packages and hooks
35
+ if rval._vm_update then
36
+ VM = rval._vm_update(DEV_MODE, VM_VERSION)
37
+ rval = {}
267
38
  end
268
- end
269
- output = output .. "DELTA USAGE: " .. U - saved_usage .. "\n"
270
- output = output .. "\n*** NEW ALLOCATIONS ***\nTOTAL: " .. total .. "\nNEW: " .. count .. "\nUSAGE: " .. U .. "\n"
271
- total = 0
272
- count = 0
273
- for k,v in pairs(saved_snapshot) do
274
- total = total + 1
275
- if S[k] == nil then
276
- count = count + 1
39
+ -- Special handling for the other hooks
40
+ if rval._vm_hook_call then
41
+ -- swap _vm_hook_call string into method which will be passed to hooks.run below
42
+ method = rval._vm_hook_call
43
+ else
44
+ -- Just punt the rval back to the caller.
45
+ return rval
277
46
  end
278
47
  end
279
- output = output .. "\n*** OLD ALLOCATIONS ***\nTOTAL: " .. total .. "\nFREED: " .. count .. "\nUSAGE: " .. saved_usage .. "\n"
280
- if update then saved_snapshot = S end
281
- return output
282
48
  end
283
-
284
- -- Uncomment for snapshot tracing
285
- --snapshot.tron()
286
- -- Uncomment to generate a snapshot at boot.
287
- --dump_snapshot('BOOT')
288
- --snapshot.troff()
49
+ if type(method) == "string" then
50
+ -- new style hook call
51
+ if VM then
52
+ -- Call it!
53
+ rval = VM.run(method, vars)
54
+ else
55
+ error("Attempt to call hook '" .. method .. "' before VM code has loaded.")
56
+ end
57
+ elseif type(method) ~= 'function' then
58
+ error("sandboxed_call called with a method of type " .. type(method) .. ".")
59
+ end
60
+ return rval
289
61
  end
290
62