3

In ROBLOX Lua, I'm writing a game that involves users creating and running Lua scripts. Obviously, I need to prevent the use of certain services and functions, such as the Kick function on the Player class, or anything related to DataStore or TeleportService.

So far, I've been successful at making a sandboxed environment by using setfenv to set a function's environment to a metatable, which is attached to a "sandbox" table. On __index, if nothing is found in the sandbox table, it looks in the real environment like it normally would. This allows me to put fake functions in the sandbox table that will be used instead of their real counterparts.

However, let's say I sandboxed the ClearAllChildren function. Players could easily escape the sandbox by doing this:

someObject.Parent.someObject:ClearAllChildren()

This is because getting an instance's Parent gives them the real version as opposed to the sandboxed version. This flaw can be pulled off many other ways, too.

So I made an object wrapper. Calling wrap(obj) on an instance returns a fake version created with newproxy(true). The __index of its metatable makes sure any child of the object (or instance property such as Parent) will return a wrapped version.

My issue is likely with the way I have my wrapper set up. Attempting to call any method on an object inside the sandbox, like this:

x = someObject:GetChildren()

Results in the following error:

Expected ':' not '.' calling member function GetChildren

Here's the full code for my sandbox currently:

local _ENV = getfenv(); -- main environment

-- custom object wrapper
function wrap(obj)
    if pcall(function() return obj.IsA end) then -- hacky way to make sure it's real
        local realObj = obj;
        local fakeObj = newproxy(true);
        local meta = getmetatable(fakeObj);
        meta['__index'] = function(_, key)
            -- TODO: logic here to sandbox wrapped objects
            return wrap(realObj[key]) -- this is likely the source of method problem
        end;
        meta['__tostring'] = function()
            return realObj.Name or realObj;
        end;
        meta['__metatable'] = "Locked";
        return fakeObj;
    else
        return obj;
    end;
end;

-- sandbox table (fake objects/functions)
local sandbox = {
    game = wrap(game);
    Game = wrap(Game);
    workspace = wrap(workspace);
    Workspace = wrap(Workspace);
    script = wrap(script);
    Instance = {
        new = function(a, b)
            return wrap(Instance.new(a, b))
        end;
    };
};

-- sandboxed function
function run()
    print(script.Parent:GetChildren())
    print(script.Parent)
    script.Parent:ClearAllChildren()
end;

-- setting up the function environment
setfenv(run, setmetatable(sandbox, {__index = _ENV;}));

run();

How can I fix this?

NotAshley
  • 142
  • 2
  • 11

0 Answers0