immunio 1.0.4 → 1.0.5

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