Jump to content




Making Sandbox more Secure


15 replies to this topic

#1 HPWebcamAble

  • Members
  • 933 posts
  • LocationWeb Development

Posted 08 February 2016 - 04:19 AM

I'm working on a sandbox. How can I make it more secure (AKA prevent a program from getting around the restrictions)?

What it prevents the program from doing right now:
  • Directly accessing fs.open and fs.delete (these are overridden to tweak how they work)
  • Accessing through _G (Which is also overriden for the program)
Important Note:
Currently, it only restricts deleting and opening files. Lets assume it is only supposed to do that.

My Code

Edited by HPWebcamAble, 08 February 2016 - 04:21 AM.


#2 valithor

  • Members
  • 1,053 posts

Posted 08 February 2016 - 04:59 AM

Little bypass I can see with your system.

Say someone were to do something like:
os.queueEvent("key",keys.y,false)
fs.delete("somefile")

The pullEvent in your function would think the user pressed the key, but instead it is just grabbing the key the program qued. A thing you can do to fix this would be something like:
local randomNum = math.random(9999,1000000) --# Generating a random event name, so the program could not fake your special event

env.fos.open = function(path,mode)
  print("Allow "..args[1].." to access "..path.."?")
  print("Y/N")
  os.queueEvent(randomNum) 
  os.pullEvent(randomNum) --# will make sure there are no events in the queue, which would end up happening anyway if you were listening for input
  while true do
		local event = {os.pullEvent("key")}
		if event[2] == keys.y then
		  return _G.fs.open(path,mode)
		elseif event[2] == keys.n then
		  return setmetatable({},{__index = function() return false end})
		end
  end
end


#3 HPWebcamAble

  • Members
  • 933 posts
  • LocationWeb Development

Posted 08 February 2016 - 05:10 AM

View Postvalithor, on 08 February 2016 - 04:59 AM, said:

Little bypass I can see with your system.

Good point, I didn't even think about that. In the final version, it'll use a dialog window, but it could still be similarly bypassed by queuing a click in the right location.

Edited by HPWebcamAble, 08 February 2016 - 05:10 AM.


#4 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 08 February 2016 - 05:50 AM

View Postvalithor, on 08 February 2016 - 04:59 AM, said:

The pullEvent in your function would think the user pressed the key, but instead it is just grabbing the key the program qued. A thing you can do to fix this would be something like:

You'd want to generate a new randomNum every time env.fos.open() is called, or else a coder could sniff the event "signature" by pulling it via some coroutine manipulation.

Although, that might be the complex way to go about it, when this is an option:

parallel.waitForAll(function() fs.delete("somefile") end, function() os.queueEvent("key",keys.y,false) end)


#5 valithor

  • Members
  • 1,053 posts

Posted 08 February 2016 - 03:28 PM

View PostBomb Bloke, on 08 February 2016 - 05:50 AM, said:

parallel.waitForAll(function() fs.delete("somefile") end, function() os.queueEvent("key",keys.y,false) end)

I had thought of something like that, which might lead to something like this:
env.coroutine.yield = function(...)
  local event = {coroutine,yield}
  while event[#event] == "Program Queued Event") do
	table.remove(event,#event)
  end
  return event
end

env.os.queueEvent = function(...)
  os.queueEvent(...,"Program Queued Event")
end

local randomNum = math.random(9999,1000000) --# Generating a random event name, so the program could not fake your special event

env.fos.open = function(path,mode)
  print("Allow "..args[1].." to access "..path.."?")
  print("Y/N")
  while true do
				local event = {os.pullEvent("key")}
				if not event[#event] == "Program Queued Event" then
				  if event[2] == keys.y then
					return _G.fs.open(path,mode)
				  elseif event[2] == keys.n then
					return setmetatable({},{__index = function() return false end})
				  end
				end
  end
end

The program would only behave different if it for some reason queued a event with "Program Queued Event" at the end, but even then that could be accounted for. Only events queued by the program would be tagged, and anything outside of the program wouldn't remove the things at the end.

Edited by valithor, 08 February 2016 - 03:38 PM.


#6 SquidDev

    Frickin' laser beams | Resident Necromancer

  • Members
  • 1,427 posts
  • LocationDoes anyone put something serious here?

Posted 08 February 2016 - 03:55 PM

I haven't tested these, but I'm pretty sure they'd allow me to get the un-sandboxed environment:
local env = getfenv(5) -- Probably high enough to be in the shell somewhere
local env = getfenv(print)
local env = _ENV -- CC 1.75+

Then:
env.fs.delete("foobar")

Edited by SquidDev, 08 February 2016 - 03:56 PM.


#7 HPWebcamAble

  • Members
  • 933 posts
  • LocationWeb Development

Posted 08 February 2016 - 10:55 PM

View PostBomb Bloke, on 08 February 2016 - 05:50 AM, said:

You'd want to generate a new randomNum every time env.fos.open() is called, or else a coder could sniff the event "signature" by pulling it via some coroutine manipulation.
That's what I was thinking. Of course, it's pretty easy to generate a new number each time.

View Postvalithor, on 08 February 2016 - 03:28 PM, said:

local env = getfenv(5) -- Probably high enough to be in the shell somewhere
local env = getfenv(print)
local env = _ENV -- CC 1.75+

_ENV.fs.delete doesn't bypass the sandbox, at least not in CCEmuRedux running CC 1.78

getfenv(5) and getfenv(print) do bypass it, but couldn't you just override them in the sandbox as well?
They'll be removed in the update to Lua 5.2 anyway.

Edited by HPWebcamAble, 08 February 2016 - 10:56 PM.


#8 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 09 February 2016 - 02:25 AM

View Postvalithor, on 08 February 2016 - 03:28 PM, said:

I had thought of something like that, which might lead to something like this:

Unfortunately you can't do this:

env.os.queueEvent = function(...)
  os.queueEvent(...,"Program Queued Event")
end

It'll return only the first parameter + "PQE". This'd work:

env.os.queueEvent = function(...)
  arg[arg.n + 1] = "Program Queued Event"
  os.queueEvent(unpack(arg))
end

... unless the coder did:

os.queueEvent("key",keys.y,false,nil)

... which'd cause unpack to trip on the nil...

#9 valithor

  • Members
  • 1,053 posts

Posted 09 February 2016 - 02:40 AM

View PostBomb Bloke, on 09 February 2016 - 02:25 AM, said:

Unfortunately you can't do this:

Ehh thats right. Might be easier to just move the "Program Queued Event" to before the ...

There really isn't any reason it needed to be at the end.

#10 MentalHamburger

  • Members
  • 12 posts

Posted 17 February 2016 - 08:46 AM

couldnt you just use
shell.run("rm program")

to get past deleting something

Edited by MentalHamburger, 17 February 2016 - 08:46 AM.


#11 valithor

  • Members
  • 1,053 posts

Posted 17 February 2016 - 12:23 PM

View PostMentalHamburger, on 17 February 2016 - 08:46 AM, said:

couldnt you just use
shell.run("rm program")

to get past deleting something

That would just run a program that uses fs.delete, so it would also be restricted.

#12 Quartz101

  • Members
  • 141 posts
  • Location/dev/nvme0n1

Posted 23 February 2016 - 10:39 AM

View PostMentalHamburger, on 17 February 2016 - 08:46 AM, said:

couldnt you just use
shell.run("rm program")

to get past deleting something

You could just block shell.run

#13 valithor

  • Members
  • 1,053 posts

Posted 23 February 2016 - 12:38 PM

View PostQuartz101, on 23 February 2016 - 10:39 AM, said:

View PostMentalHamburger, on 17 February 2016 - 08:46 AM, said:

couldnt you just use
shell.run("rm program")

to get past deleting something

You could just block shell.run

But shell.run doesn't bypass anything...

#14 HPWebcamAble

  • Members
  • 933 posts
  • LocationWeb Development

Posted 24 February 2016 - 01:52 AM

View PostQuartz101, on 23 February 2016 - 10:39 AM, said:

View PostMentalHamburger, on 17 February 2016 - 08:46 AM, said:

couldnt you just use
shell.run("rm program")

to get past deleting something

You could just block shell.run

As valithor mentioned just before your comment, the 'rm' program uses fs.delete, so it's already covered.

#15 PixelToast

  • Signature Abuser
  • 2,265 posts
  • Location3232235883

Posted 24 February 2016 - 05:03 AM

View PostHPWebcamAble, on 24 February 2016 - 01:52 AM, said:

View PostQuartz101, on 23 February 2016 - 10:39 AM, said:

View PostMentalHamburger, on 17 February 2016 - 08:46 AM, said:

couldnt you just use
shell.run("rm program")

to get past deleting something

You could just block shell.run

As valithor mentioned just before your comment, the 'rm' program uses fs.delete, so it's already covered.

no, shell.run runs commands in the unsandboxed environment

#16 HPWebcamAble

  • Members
  • 933 posts
  • LocationWeb Development

Posted 24 February 2016 - 11:20 PM

View PostPixelToast, on 24 February 2016 - 05:03 AM, said:

shell.run runs commands in the unsandboxed environment

I was actually thinking about that. I'll have to test it to make sure, but you're probably correct.
Modifying shell.run should fix that.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users