6

While I do know that system calls and security don't go hand in hand, there is a project for which I do need it. I'm writing a small code checker and I need to compile and execute the user submitted code to test against my test cases.

Basically I want to run the code in a sandbox, so that it can't touch any files outside of the temporary directory and any files that it creates can't be accessed by the outside world. Recently I came across an exploit with with which the user could create a file say shell.php with the following contents.

<?php
  echo system($_GET['x']);
?>

This gives the attacker a remote shell and since the owner of the file is apache, the attacker could basically move around my entire /var/www where mysql passwords were stored along with other configuration information.

While I am aware of threats like SQL Injections and have sanitized the user input before any operations that involve the DB, I have no idea as to how I can set up the sandbox. What are the techniques that I can use to disable system calls (right now I'm searching for the word 'system' in the user submitted code and not executing those snippets where it is found) and restrict the access to the files that the user submitted code creates.

As of now my code checker only works for C and I plan to add support for other languages like C++, Java, Ruby and Python after I can secure it. Also I'd like to learn more about this problem that I've encountered so pointers to a place where I could learn more about web security would also be appreciated.

My development machine is running Mac OS Lion and the deployment machine is a linux server so if a solution, that was cross platform would be most appreciated but one that dealt with just the linux machine would do too.

nikhil
  • 8,925
  • 21
  • 62
  • 102
  • do you want to disable system command completely ? – Hawili Aug 12 '12 at 07:32
  • No no, without that I wouldn't be able to pass code to the gcc compiler. I want the user submitted code not to make system calls. – nikhil Aug 12 '12 at 07:33
  • 1
    you can always use this php function [escapeshellarg](http://php.net/manual/en/function.escapeshellarg.php), you just have to specify the allowed command in list using switch case or if condition then such a function will protect from injecting any more commands – Hawili Aug 12 '12 at 07:36
  • 1
    I want to know how I can run programs in a sandbox. – nikhil Aug 14 '12 at 18:37
  • Run PHP in CGI or FAST CGI mode, under a user with very little privileges, check php-fpm – Hawili Aug 15 '12 at 05:37
  • 1
    See [1](http://stackoverflow.com/questions/4249063/how-can-i-run-an-untrusted-c-program-in-a-sandbox-in-linux "how-can-i-run-an-untrusted-c-program-in-a-sandbox-in-linux"), [2](http://user-mode-linux.sf.net/ "user-mode-linux"), [3](http://www.xs4all.nl/~weegen/eelis/geordi/ "geordi") – Shiplu Mokaddim Aug 26 '12 at 22:41
  • Not sure if this helps completely, but have you considered dynamically spinning up instances with amazon web services? It could be still considered dangerous, but the master instance can shutdown the slave instances with more control and you may not be compromising other services on that machine. – badunk Aug 27 '12 at 18:05
  • @shiplu.mokadd.im The 3rd link is dead. – nikhil Aug 27 '12 at 18:58
  • @badunk I don't think spinning up a new instance for each submission would be feasible. I'd like to be able to run this both over the college lan and later maybe the internet. I'm curious as to how sites like spoj implement their code checkers. – nikhil Aug 27 '12 at 18:59

5 Answers5

5

What you will probably want to do is set up a chroot to some random temp directory on your filesystem for the user running your scripts. Here is some reading on setting up a chroot, and some security to-know's.

I would suggest you also install a security module such as suExec or MPM-iTK for Apache. Then, within your Apache's VirtualHost (if you are not running a virtual host, do so!), assign a specific UserID to handle requests for this specific VirtualHost. This separates the request from the Apache default user, and adds a little security.

    AssignUserID nonprivilegeduser nonprivilegeduser 

Then, harden PHP a little by setting the following PHP options so the user cannot access files outside of the specific directories, and move your tmp_dir and session_save_path within this directory. This will prevent the users access outside of their base directory.

    php_admin_value open_basedir /var/www/
    php_admin_value upload_tmp_dir /var/www/tmp
    php_admin_value session.save_path /var/www/tmp

Along with the lines of PHP, prevent access to specific functions and classes, and read up on PHP's security write-up.

Also, I would have you look into for that user, disabling access to sudo and su, to prevent a script from attempting to access root privileges. Learn more, here.

All in all, you said it nice and clear. There is no way to fully prevent a user from accessing your system if they have the will. The trick is to just make it as difficult as possible, and confusing as possible for them.

Community
  • 1
  • 1
Mike Mackintosh
  • 13,917
  • 6
  • 60
  • 87
  • Thanks for the fantastic answer. I have lots to learn from this, I'll get to setting up the environment right away. – nikhil Aug 28 '12 at 17:10
  • 1
    If you have more questions about this field, look at serverfault and itsecurity. It is geared a bit more to server configs, hardening and etc. – Mike Mackintosh Aug 28 '12 at 17:36
1

There is no way to make this work on a cross-platform basis, period. Sandboxing is inherently highly system-specific.

On Mac OS X, there is the Sandbox facility. It is poorly documented, but quite effective (Google Chrome relies heavily on it). Some enterprising souls have documented parts of it. However, it's only available on Mac OS X, so that probably rules it out.

On Linux, your options are considerably less developed. Some kernels support the seccomp mechanism to prevent processes from using any except a small "safe" set of system calls; however, not all do. Moreover, that "safe" subset doesn't include some calls that you are likely to need in code that hasn't been specifically written to run under seccomp -- for instance, mmap and sbrk are not permitted, so you can't allocate memory. Helper tools like seccomp-nurse may get you somewhere, though.

1

Here are the things I suggest doing.

1. Disable system classes and functions in php.ini with

disable_functions="system,curl_init,fopen..."
disable_classes="DirectoryIterator,SplFileObject..."

2. Run in a read only environment with no important data stored on it. In case anyone ever got into your server you don't want them to access anything. A good way to do this is buy an Amazon AWS EC2 and use a jailed user to run your server and PHP.

3. Ask people to break it. The only way you can find flaws and loop holes that you are unaware of is to find them. If necessary, get a temporary server with a "test" application that replicates the same type of application your "production" environment will be.

Here are some helpful resources.

Community
  • 1
  • 1
Baylor Rae'
  • 3,995
  • 20
  • 39
1

I think what you are looking for is Mandatory Access Control. In Linux, it is available via SeLinux. Using it you can limit who can execute what command. In your case, you can limit the php user (Apache) to execute only limited commands like gcc etc. Also look into AppArmor

Also, look into runkit php virtual environment

gauravphoenix
  • 2,814
  • 3
  • 25
  • 33
0

You can try to run user submitted code in a container (docker) which are very light weight VMs. They start in less than a second.

gauravphoenix
  • 2,814
  • 3
  • 25
  • 33