diff --git a/extensions/sandbox_test/try_exploit.lua b/extensions/sandbox_test/try_exploit.lua index 356f2dc..59c9280 100644 --- a/extensions/sandbox_test/try_exploit.lua +++ b/extensions/sandbox_test/try_exploit.lua @@ -48,21 +48,36 @@ local bad_values = { io.popen, } --- Have a list of field names to check in case of metatables +-- Have a list of field names to check in case of disabled iteration local interesting_field_names = { "meta", "class_meta", + "CreateChild", + "root", + "text", + "x", } for _, v in ipairs(bad_names) do -- All bad names are interesting table.insert(interesting_field_names, v) end +-- Functions that are known to shutdown the whole application if called without +-- parameters +local function_blacklist = { + "run_script_file", + "send_packet", + "disconnect", + "sub_tick", +} + local bad_names_set = {} for _, v in ipairs(bad_names) do bad_names_set[v] = true end local bad_values_set = {} for _, v in ipairs(bad_values) do bad_values_set[v] = true end local interesting_field_names_set = {} for _, v in ipairs(interesting_field_names) do interesting_field_names_set[v] = true end +local function_blacklist_set = {} +for _, v in ipairs(function_blacklist) do function_blacklist_set[v] = true end local function path_str(path) local result = "" @@ -114,12 +129,15 @@ local function search(value, checked_values_set, result_list, current_path) table.remove(current_path) end end - pcall(f) + pcall(f) -- Ignore errors end - -- Iterate through the value - if type(value) == 'table' then + -- Iterate using __next + if getmetatable(value) and getmetatable(value).__next then -- Use meta.__next - for field_name, v in pairs(value) do + local metapairs = function(t) + return getmetatable(value).__next, t, nil + end + for field_name, v in metapairs(value) do if v ~= nil then table.insert(current_path, field_name) if bad_names_set[field_name] then @@ -130,6 +148,9 @@ local function search(value, checked_values_set, result_list, current_path) table.remove(current_path) end end + end + -- Iterate through raw table value + if type(value) == 'table' then -- Don't use meta.__next local rawpairs = function(t) return next, t, nil @@ -146,6 +167,26 @@ local function search(value, checked_values_set, result_list, current_path) end end end + -- If it's a function or callable, call it and check the results + if type(value) == 'function' or + (getmetatable(value) and getmetatable(value).__call) then + -- Don't call if blacklisted + if not function_blacklist_set[current_path[#current_path]] then + -- Call with itself as parameter; that should give the most bang for + -- the buck + log:verbose("search: "..path_str(current_path).."(self)") + function f() + local ret = {value(value)} + for i = 1, table.getn(ret) do + local ret_v = ret[i] + table.insert(current_path, "()["..i.."]") + search(ret_v, checked_values_set, result_list, current_path) + table.remove(current_path) + end + end + pcall(f) -- Ignore errors + end + end end function M.run() @@ -204,8 +245,12 @@ function M.run() for _, extname in ipairs(extnames) do try_require_extension(extname) end - -- Make this global so it stays in the environment for checking through - sandbox.make_global({loaded_extensions = loaded_extensions}) + + -- Make results global so they stay in the environment for checking + sandbox.make_global({ + loaded_extensions = loaded_extensions, + }) + -- Get the environment (which isn't available for iteration normally) new_sandbox.env = local_getfenv(1) end