PHP jailing arbitrary code
Asked Answered
A

2

6

We have a Java IRC application where users are allowed to execute arbitrary PHP and get the result. Here is one example of what this is used for:

btc: <php>$btc = json_decode(file_get_contents('https://btc-e.com/api/2/1/ticker'), true); $ticker = $btc['ticker']; echo "Current BTC Ticker: High: $".$ticker['high']." Low: $".$ticker['low']." Average: $" . $ticker['avg'];

We also have a python setup, but we like PHP because PHP does not require newlines in the code anywhere. (Because this is IRC, we cannot give it newlines unless we exec a web-loaded .py file)

The issue is how to prevent people from trying to exploit the system, such as in:

<php>echo readfile("/etc/passwd");

Which would, clearly, read out the passwd file for all to see.
We are also having this problem, after we tried to block readfile():

<php>$rf = readfile; echo $rf("/etc/passwd");

How should we go about securing this system? (The full code is on github, for any interested: https://github.com/clone1018/Shocky)

As an aside, no real sensitive information is being exposed, as the whole thing is in a VM, so it isn't a "timebomb" or anything. We still want to lock it down though.

Altimetry answered 14/5, 2012 at 18:12 Comment(11)
Why does your web server have the rights to read /etc/passwd? Lock down your web user for starters.Puttergill
@Puttergill That has nothing to do with the web user; /etc/passwd is world readable by default on most Linux distributions. Some programs require access to that file in order to function, and it doesn't contain any passwords anyway.Distracted
@Ryan P - By "web user" I meant the user running apache, not the user on the website.Puttergill
@Puttergill Yeah I understand that. What I'm saying is that you can't do anything to the web user, because the file permissions themselves say any user account on the system can read it. You could lock down /etc/passwd with no 'other' permissions, but that will break or disable functionality in many programs (including ls).Distracted
You might not be exposing any sensitive information, but what's preventing someone from hijacking the VM and infecting it, turning it into a zombie system?Politi
@damianb: That's sort of what this is about, in a certain interpretation of your comment. My point was that this isn't time-critical.Altimetry
@Riking: Here's the thing - unless you're willing to plug most of the useful functions/classes/whatnot in php, you're in for real pain. You'll have to prevent backticks, shell_exec, eval, preg_replace (take a look at what the /e modifier does), the pcntl_ functions, and a whole lot of other things as well. plus, you'd want to isolate the user so it can't write to anything that's ever in any user's $PATH on the VM, you'd want to prevent it from executing anything external, from making remote connections (wheee, free DoS anyone?) and from saving new files/serving files.Politi
@Altimetry Oh, and the reason I specify saving new files/serving files, is because you could be used as a tool for piracy, and I doubt you'd want to get a DMCA notice just from running what has the intention of being used as a beneficial tool for development. Perhaps you should seek another angle to help your end-users? You could show them how to set up wampserver (if they're a windows user) and show them phpconsole - github.com/Seldaek/php-consolePoliti
I should also point out that there's nothing that will stop it from running something that will whore CPU cycles like crazy and bottleneck the bot itself. There's also a number of exploits I've found in the past half-hour alone, but seeing as you aren't open to input ("I think I'm done with this question. Bye~") or having vulnerabilities pointed out, I think I'd be more likely to take the exploits I've found and bring them to the attention of security mailing lists, instead of opening github issues. ;)Politi
We already prevent backtickets, shell_exec, eval, we'll check that out, pcntl_*, and a whole slew of dangerous code, we're not asking how to make the bot secure, or how to disable functions, or anything like that. We're asking how to disable/detect variable variables. We stop file saving, local file reading, we throttle external connections. There is no way in hell we'd allow file saving, and I don't see Riking saying that anywhere, not sure where you got it from. And again you're misunderstanding, the bot is a bot, it's a regular IRC bot with regular IRC functions.Quittor
This PHP evaluator is just another function of the bot, a helpful little tool to write factoids/plugins/or just inline code. You assume yet again that we don't have protection against CPU whoring, we do. Feel free to post this information on whatever security mailing lists you please, because I'm sure they'll be more helpful then you.Quittor
D
4

That sounds like plugging one hole in a colander. Filesystem security should be handled by the OS, not the application. And as far as /etc/passwd goes, the OS is already securing it.

Here's the first line of my /etc/passwd - yes, I'm going to post it publicly:

root:x:0:0:root:/root:/bin/bash

Usually, passwords aren't actually stored in /etc/passwd. User information is, but the passwords are replaced with x, with the real password only available to the root user.

However, you should lock down PHP to some degree. You can change many PHP options during runtime with ini_set, including open_basedir. http://www.php.net/manual/en/ini.core.php#ini.open-basedir

Distracted answered 14/5, 2012 at 18:21 Comment(6)
@Ryan P: That's still not fixing the root problem, if we do that, they could still $a = 'include'; $a('sql.php'); or similar. @afuzzyllama: That's also avoiding the root problem, /etc/passwd was just an example. Even if the user was in a chrooted env they'd still be able to access the other files in that jail, we don't want that.Quittor
If you set open_basedir to a directory with no files, then you cannot open anything other than the running script itself. The method used to open the file is irrelevant; it affects include as well.Distracted
If we set it to an empty location, how would we include the Requests library or anything else we wanted to add? What about the Safe.php file for that matter? (Take a look here btw github.com/clone1018/Shocky/tree/master/php ). Keep in mind ini_set isn't accessible for security purposes.Quittor
That's simple; order of operations. You can include anything you want, BEFORE setting open_basedir. The key is that you don't set open_basedir until right before you fire user code. And ini_set is perfectly accessible outside the user code.Distracted
ini_set is disabled with Safe.php and inside the actual php.ini. It is not accessible anywhere. What if they did $a = 'ini_set'; $a('foo','bar');Quittor
@clone1018: You cannot $a = 'include'; $a('sql.php'); since include is not a function.Kingwood
T
-4

If you only want to restrict the file reading maybe this can help http://www.php.net/manual/en/ini.core.php#ini.open-basedir

If you are using an old version of php < 5.4 you can consider using php safe mode

http://php.net/manual/en/ini.sect.safe-mode.php

Set the following vars for safe mode to restrict php

safe_mode_exec_dir
disable_functions = readfile,system

and many other

Also the user wont be able to read any file for which uid is different, e.g. /etc/password. Be advised that safe mode is depreciated/ removed from latest versions of php

Tejeda answered 14/5, 2012 at 18:32 Comment(3)
You shouldn't suggest anyone use deprecated functionality, especially when it has been removed in the current version.Distracted
Booo said the old wise man :-P. In this case for this particular use case safe mode seems to be the better bet even if depreciated, than an un-answer from the old wise man (that does not even remotely tries to touch upon the solution to the questions but still get +2).Tejeda
A solution to a problem and an answer to a question are not the same thing. I try to give solutions to problems rather than blindly answering questions, as the former is often preferable to the latter.Distracted

© 2022 - 2024 — McMap. All rights reserved.