tags:

views:

793

answers:

6

I was just working on a localizable Lua string solution, when I came up with this hack, problem is I don't know how to avoid getting hacked by it :) So I was wondering if anyone, has done something similar and or knows how to protect from this kind of attack. (in user code)

Since we can do this:

=("foo"):upper() -->output: FOO

It can be hacked like this:

getmetatable("foo").__index.upper = function() print("bye bye sucker");os.exit() end
=("foo"):upper() -->output: bye bye sucker (application quits)
-- or this way
=string.upper("bar") -->output: bye bye sucker (application quits)

Any ideas?

+3  A: 

If your hacker has the ability to add code, and you need to allow that code to call things like os.exit, then you're pretty much out of luck anyway.

You can restrict the functions that their code can call, though. It depends on what you still want user code to be able to do. See the doc for setfenv and google for "lua sandbox"

Paul
I mean of course os module isn't available to users , but I used it for the impact factor in my code. Anyways thanks for the sandbox idea, hadn't thought about googling that.
Robert Gould
+2  A: 

I am not sure why you have an issue, since you probably already know about sandboxes: you can remove dangerous functions like io.exit, and you can ensure the overridden functions are only those in the global table of the user, ie. the Lua functions used internally by your application will remain intact.
In any case, if the hacker can call os.exit directly, the fact he can shoot himself in the foot by supercharging an innocent function he will use later is his problem.
Beside, it is a problem only if you run user functions on your server, for example: if the hacker destroys his system, again, that's his problem!
Now, there is also the issue of distributing dangerous code: it is up to you to restrict the power of user scripts. After all, that's what browsers do with JavaScript.

PhiLho
The problem is overriding string.upper, not directly using os.exit. But I'm not sure if sandboxing will directly protect against the overriding, but now that you mention it I should also hide the get/setmetatable functions from the user environment.
Robert Gould
+1  A: 

I have no solution (I don't use Lua, I'm just interested in it from afar), but what you're after is called a "sandbox". Google for Lua sandbox, I found a few seemingly interesting pages that way. For example: http://lua-users.org/wiki/SandBoxes.

bart
+2  A: 

This security problem is typically illustrated with this sentence, said by Ford Prefect in the brilliant books The Hitchhiker's Guide to the Galaxy: It rather involved being on the other side of this airtight hatchway

My ability to write code cannot be said to be a security vulnerability, and if you can't control your code, that is your security problem, not what that code can do.

There are tons and tons of things you can do if you can just get the machine to execute some of your code. The security is to avoid getting the code in there in the first place. Everything after that is just collateral damage.

The way to avoid being hacked by that problem is to avoid getting unknown code into your application.

Lasse V. Karlsen
+1 for the reality check, however my goal is to allow some user code to be run. But yes you are right I need to rethink my problem here
Robert Gould
The sandbox approach others are mentioning is unknown to me, so it seems you do have a way to limit this ability in this case.
Lasse V. Karlsen
+4  A: 

First and foremost execute untrusted code in sandboxed environment only – as it was said by other posters. Except for loading bytecode chunks, Lua allows all other sandboxing issues to be covered. (And bytecode chunk problems get fixed promptly as discovered.)

See Lua Live Demo for an example of sandboxing. Sources are available here.

Your specific problem with metatables is solved by setting a __metatable field:

If you set a __metatable field in the metatable, getmetatable will return the value of this field, whereas setmetatable will raise an error.

– Roberto Ierusalimschy, Programming in Lua 1st edition, 13.3 - Library-Defined Metamethods

For example:

> mt = { __metatable = true }                                                   
> t = {}
> setmetatable(t, mt)
> setmetatable(t, mt)
stdin:1: cannot change a protected metatable
stack traceback:
 [C]: in function 'setmetatable'
 stdin:1: in main chunk
 [C]: ?

So, all you have to do is:

getmetatable("").__metatable = true
Alexander Gladysh
__metatable is what I what I was looking for, had forgotten this!
Robert Gould
+1  A: 

I don't see the possibility to redefine upper as the problem. Being able to see os.exit is the problem.

As suggested by others, make a sandboxed environment for your scripts. Each script can get a new one; then a person can redefine upper or anything like that, and all they'll screw up is their own thing.

Creating Lua states is so fast and easy, this won't cause any problems.

Another thing you might beware of is eternal loops. Making a 'watchdog' that kills a script after, say, 10000 instructions takes about 10 lines of C code. I can send you sample if you need.

akauppi