Stop file access from Ruby - ruby

I have a server application that allows users to execute their own ruby scripts. The server that the scripts run on is a virtual instance on Amazon's EC2 so no permanent damage can be done. However I'd like to take whatever precautions I can to stop any dangerous/malicious script, reboots are still something I'd like to avoid.
At the moment I disallow any scripts that contain "require" or "include". I think it would actualy be safe to allow "include"? There is no need for any users to access the server's file system so if I disallow any occurrence of the string "file." will that prevent users being able to access the server's file system?

Disallowing occurrence of the string "file" will not help you at all. They still have eval, pack/unpack, Dir, ` and tons of other stuff.
YMMV, but this is what I would have done:
Run the ruby process as an unprivileged user
in a jailed environment (i.e. chroot, freebsd jail or equivalent)
in a stripped environment (no suids, no other unnecessary files -- bare minimum is best)
with $SAFE >= 2
and with no write access to any files/folders
Probably still not secure, but it's a start.
EDIT: Might also be a good idea to set limits on system resource consumption using ulimit or equivalent.

Sounds like you are in for a guessing game. Wouldn't it be easier to run the scripts as a user with very low privileges? Or you could take a look at how TryRuby solved similar problems.
Seems there are several options for sandboxing Ruby but I haven't used any of them so I can't hand out recommendations.

Related

Deploy go web project on windows server 2008

My project: go - 1.12.5; gin-gonic; vue-cli - 3.8.2.
On windows server 2008 go under the local account, run main.exe - works well. But when log off my account, all local account programs are closed, including my go server.
The first thing I did was try to configure IIS for my GO. Nothing good came of it.
Then I tried to run main.exe from the SYSTEM account psexec -s c:\rafd\main.exe. When log off the process does not close. But the frontend is in my account and SYSTEM does not see the local files (js, html, css) of my project
Tell me how to start the Go server, to after log off my project did not stop life
Two ways to approach it.
Go with ISS (or another web server).
Should you pick this option, you have further choices:
Leave your project's code as is, but
Make sure it's able to be told which socket to listen for connections on—so that you can tell it to listen, say, on localhost:8080.
For instance, teach your program to accept a command-line parameter for that—such as -listen or whatever.
Configure IIS in a way so that it reverse-proxies incoming HTTP requests on a certain virtual host and/or path prefix to a running instance of your server. You'll have to make the IIS configuration—the socket it proxies the requests to—and the way IIS starts your program agree with each other.
Rework the code to use FastCGI protocol instead.
This basically amounts to using net/fastcgi instead of net/http.
The upside is that IIS (even its dirt-old versions) support FastCGI out of the box.
The downsides are that FastCGI is beleived to be slightly slower than plain HTTP in Go, and that you'll lose the ability to run your program in the standalone mode.
Turn your program into a proper Windows™ service or "wrap" it with some helper tool to make it a Windows™ service.
The former is cleaner as it allows your program to actually be aware of control requests the Windows Service Management subsystem would send to you. You could also easily turn your program into a shrink-wrapped product, if/when needed. You could start with golang.org/x/sys/windows/svc.
The latter may be a bit easier, but YMMV.
If you'd like to explore this way, look for tools like srvany, nssm, winsv etc.
Note that of these, only srvany is provided by Microsoft® and, AFAIK, it's missing since Win7, W2k8, so your best built-in bet might be messing with sc.exe.
In either case, should you pick this route, you'll have to deal with the question of setting up proper permissions on your app's assets.
This question is reasonably complex in itself since there are many moving parts involved.
For a start, you have to make sure your assets are tried to be accessed not from "the process' current directory"—which may be essentially random when it runs as a service—but either from the place the process was explicitly told about when run (via command-line option or whatever) or figured out somehow using a reasonably engeneered guess (and this is a complicated topic in itself).
Next, you either have to make sure the account your Windows™ uses to run your service really has the permissions to access the place your assets are stored in.
Another possibility is to add a dedicated account and make the SCM use it for running your service.
Note that in either case proper error handling and their reporting is paramount: when your program is being run non-interactively, you want to know when something goes wrong: socket failed to be opened or listened on, assets not found, access was denied when trying to open an asset file, and so on—in all these cases you have to 1) handle the error, and 2) report it in a way you can deal with it.
For a non-interactive Windows™ program the best way may be to use the Event Log (say, via golang.org/x/sys/windows/svc/eventlog).
Simplest solutions would be using windows schedular.
Start your exe file on system logon with highest privilage in background. So whenever your system will logon it will start your exe and make runnign in background.
You can refer this answer,
How do I set a Windows scheduled task to run in the background?

Ways to find out if the process is created by system (by pid) on macOS?

I'm implementing API which allows to launch other apps (using NSTask) inside VFS (FUSE on macOS). After VFS is mounted a bunch of processes start accessing launched VFS in which my app works, and I'd like to implement some kind of filtering mechnism which will allow to detect whether process which is accessing the VFS is created by system (and potentially safe) or not, and if so it'll be granted an access to the file system where my app runs.
So far I'm able to get basic information of the process by it's pid. For example: process path, uid, ppid, code signature of the process etc (using Security framework, libproc etc)
I've done a couple of tests and see that there are process with uid != 0 and still critical for my app to run (if I deny access to them app which is started in VFS crashes) (e.g. /usr/libexec/secinitd, /System/Library/CoreServices/Dock.app/Contents/MacOS/Dock), so looks like approach with filtering processes by pids, uids, ppids might not work.
So the question is: is it possible to distinguish whether process which is accessing my app was created by system and is potentially safe? I also don't want to do too much work by denying accees to critical system processes which will allow the app to successfully start and run in VFS.
Judging from the comment thread, your threat model is data theft via malware etc.
In this case, you can trust almost nothing, so the best way is probably to maintain an explicit whitelist of processes which are allowed to access your mount point, and block access to everything else by default. Log any processes to which access is denied, and allow the user to reverse that decision and add them to the whitelist. In other words, let the user decide what applications they consider safe.
Your said that according to your inspection, there were several processes which were mandatory for the process to run, so why won't use try-and-error approach.
You deploy you FUSE drive on clean environment and record all processes that attempt to access your files - try to prevent each process and keep only those which crash your apps, and add them to a white-list.
Of course that this list is subject to change in different macOS versions, but it can give you the general idea.
Alternatively, you can break your app into couple of parts. for example, put the sensitive logic inside separated dylib file, and prevent access to this file only.. since dylib is not the main executable in your app, I believe fewer processes require mandatory access it.

How would I build a game that allowed players to write their engines with resource constraints in Ruby?

I want to copy the Scribd developers challenge, but build it using the Gosu framework in ruby. I know how to do most of it, except I'm not 100% sure how to do the following. I'd like a few ideas on the best way to approach this.
Other people (students) will be able to check their ruby code into the repo and I'd like to eventually run all the different bots against each other to determine a winner. Here are my questions about how I would do this.
There is a time limit and ram usage limit. How would you enforce this. Essentially, what I think I want to do is have the game class have a board representation, and then call each engine's main method and pass it in the game board. The method then should return a move. If it doesn't return a move in the time limit, then we move on to the next move. Also, there should be a ram limit such that they can't just iterate over all possibilities and store them in memory and essentially store all the states in the game.
Specifically, how can I spawn a process I can monitor and kill in ruby?
Time and RAM are concerns, sure, but the greater concern is security. Running arbitrary user code on your server invites attacks. What's to prevent a user from uploading code that monkey-patches your app code in order to cheat, or send spam from your server, or break things with FileUtils.rm_rf(__dir__) or while { fork }?
To run user code safely, you must run it in a sandbox. But I'll get back to that.
The simplest way to start (and solve the time/RAM problem) will be to...
Run user code in a separate process
Mandate that the user's script must define a class (or module) with a specific name, e.g. Bot, that implements your main interface. Write a wrapper script that will take as an argument the path to a user's script and read the board data (as Marshaled data, or serialized to YAML or JSON) from $stdin. The script will then require the temporary file and pass the board data to Bot. Finally, it will take the output from Bot, marshal/serialized it, and write it to $stdout.
When a user uploads a script, your app will write it to a temporary file and run the above wrapper script (with e.g. Open3), passing it the marshaled/serialized board data on stdin, then reading and unmarshaling/deserializing the result from its stdout/stderr.
How does this solve the time/RAM problem? Well, since you're just running your wrapper script in a separate process by invoking ruby, you can lean on your OS's process-management features, thus removing the possibility of the user monkey-patching their way around those restrictions. If you google e.g. "limit process memory" along with the name of your OS you'll find lots of information. For example, for Linux this tool looks handy: timeout. With such a tool you might run e.g.:
$ timeout -t 60 -m 10000 ruby /path/to/user/script.rb
Security
Okay, so what about security? It's a hard problem, not least because Ruby is so flexible, and so I can't just tell you "this is the solution."
One thing you could do is run all user code in a virtual machine using e.g. Docker. This would make it easy to prevent the user code from accessing your (real) filesystem or the network. (In this case it may make sense to have a simple Ruby server running on the VM that can receive scripts and board data from your app, run the scripts, and respond with the results, since your app won't be able to directly invoke ruby on the VM.)
This still leaves a lot of room for mischief, though. It mitigates the damage that can be done by FileUtils.rm_rf or while { fork }, as you can just spin up a fresh VM, but that's still an inconvenience. To prevent those entirely, you really need a sandbox that reliably keeps the user from accessing methods and modules that could be used maliciously. There's no One True Way to do this in Ruby, alas, but there are some tools and some code out there that will help you get started. Googling "Ruby sandbox" will turn up a lot. One project I've found instructive is RubyFiddle, which is open source and so its code is available on GitHub. It will point you to jruby-sandbox, which does sandboxing with JRuby because Java, unlike (MRI) Ruby, does have mature sandboxing solutions.
I hope that's helpful. Good luck!

Get logged in username from script launched by launchdeamon

I am trying to find the current (logged in) users name. The script looks for a particular user and changes the network configuration.
The script is started by a LaunchDeamon in /Library/LaunchDeamons.
I am not able to find a way to get the users name who is logging, so if I login as Tom when I call the script the username is root.
Can one one suggest a way to get Tom?
A LaunchDaemon is a system process. It may run when no one is logged in. If you want something that runs in a user's context, you likely want a LaunchAgent instead.
Note that "the current (logged in) user" is somewhat poorly defined because there may be fast user switching (so multiple logged in users), and users may login without a GUI session (via SSH for instance). If you use a LaunchAgent, there may be multiple copies running (and if no user is logged in, there may be no copies running).
For your example, you may just be looking to fetch current login session information (though remember, if you're a LaunchDaemon, then there may be no login session currently). This is best described in Multiple User Environment Programming Topics. In particular, look at "Getting Login Session Information."
In some cases it may be preferable to let a central system daemon communicate with per-session agents. One easy technique for that is NSDistributedNotification, particularly if data only needs to go in one direction. If you need more complex interactions between a system daemon and the user sessions, you should investigate XPC services, which are designed for that kind of problem. See "Creating XPC Services" in the Daemons and Service Programming Guide.
System-level programming, especially things involving user sessions, is exceedingly subtle on OS X (particularly compared to Linux). You should study the Daemons and Services Programming Guide carefully before undertaking it. Things that sound very simple turn out to have many corner cases and surprises. Fast user switching, non-local accounts, mounted home directories, privilege separation (particularly post-10.7), the incredibly vagaries of launchd.... It's all quite manageable, but definitely important to spend some study time before diving in.
OS X allows multiple users to be logged in at the same time. If you are trying to get the name of active console user, the script given below might help.
LOGGED_IN_USER=`stat -f%Su /dev/console`
You cannot as launch daemon runs in the system context and not user context.
As per Apple:
Most daemons run in the system context of the system—that is, they run at the lowest level of the system and make their services available to all user sessions. Daemons at this level continue running even when no users are logged into the system, so the daemon program should have no direct knowledge of users. Instead, the daemon must wait for a user program to contact it and make a request. As part of that request, the user program usually tells the daemon how to return any results.

Best secure single running app guard on windows

I would like to improve the way how an application is checking that another instance is not already running. Right now we are using named mutexes with checking of running processes.
The goal is to prevent security attacks (as this is security software). My idea right now is that "bulletproof" solution is only to write an driver, that will serve this kind of information and will authenticate client via signed binaries.
Does anyone solved such problem?
What are your opinions and recommendations?
First, let me say that there is ultimately no way to protect your process from agents that have administrator or system access. Even if you write a rootkit driver that intercepts all system calls (a difficult and unsafe practice in of itself), there are still ways to use admin access to get in. You have the wrong design if this is a requirement.
If you set up your secure process to run as a service, you can use the Service Control Manager to start it. The SCM will only start one instance, will monitor that it stays up, allow you to define actions to execute if it crashes, and allow you to query the current status. Since this is controlled by the SCM and the service database can only be modified by administrators, an attacking process would not be able to spoof it.
I don't think there's a secure way of doing this. No matter what kind of system-unique, or user-unique named object you use - malicious 3rd party software can still use the exact same name and that would prevent your application from starting at all.
If you use the method of checking the currently executing processes, and checking if no executable with the same name is running - you'd run into problems, if the malicious software has the same executable name. If you also check the path, of that executable - then it would be possible to run two copies of your app from different locations.
If you create/delete a file when starting/finishing - that might be tricked as well.
The only thing that comes to my mind is you may be able to achieve the desired effect by putting all the logic of your app into a COM object, and then have a GUI application interact with it through COM interfaces. This would, only ensure, that there is only one COM object - you would be able to run as many GUI clients as you want. Note, that I'm not suggesting this as a bulletproof method - it may have it's own holes (for example - someone could make your GUI client to connect to a 3rd party COM object, by simply editing the registry).
So, the short answer - there is no truly secure way of doing this.
I use a named pipe¹, where the name is derived from the conditions that must be unique:
Name of the application (this is not the file name of the executable)
Username of the user who launched the application
If the named pipe creation fails because a pipe with that name already exists, then I know an instance is already running. I use a second lock around this check for thread (process) safety. The named pipe is automatically closed when the application terminates (even if the termination was due to an End Process command).
¹ This may not be the best general option, but in my case I end up sending data on it at a later point in the application lifetime.
In pseudo code:
numberofapps = 0
for each process in processes
if path to module file equals path to this module file
increment numberofapps
if number of apps > 1
exit
See msdn.microsoft.com/en-us/library/ms682623(VS.85).aspx for details on how to enumerate processes.

Resources