Problem/Motivation

There are multiple vulnerabilities in the way Aegir runs tasks in the backend that makes it vulnerable to code execution by users that have access to the modules or themes directories of a site.

These are the entry points:

1. hook_cron runs as the aegir user (optional fix)
2. contrib module code (hook_init / hook_exit / code outside functions) is loaded by the aegir user
3. drush.inc files are loaded by the aegir user
4. settings.php readable from all sites (fixed)
5. private files are readable and writable by any site

Here are the implications of each issue: #1, #2 and #3 mean the attacker can run code as the aegir user, which means they can do anything the aegir user can do, which is pretty much everything in the Aegir world. #4 mean that any attacker can read DB credentials from other sites, and therefore add/read/change/delete content from those sites. Since aegir is one of those sites, this could be leveraged to root the whole aegir install as with the scenarios in #1. #5 is the least critical issue: as things stand, any site can read/write any file uploaded by any other site.

Overall, it should be understood that it's still unsafe, out of the box, to give arbitrary users PHP access to your sites or modules.

To test this, install the evil module and see if it spews out warnings when tasks are ran.

Proposed resolution

The basic problem we have is that drush commands runs always as the same user from the dispatcher. So the solution is to either not bootstrap Drupal or bootstrap in a safe way.

  • make sure we only bootstrap Drupal when necessary, which involves:
    1. make an inventory of all provision and drush code that bootstraps non-core Drupal code (or even Drupal code, if we can't trust the platform)
    2. try to determine if there are commands in there that don't need to bootstrap
    3. trim the bootstrap level of those commands to DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION, assuming the platform is trusted (!!)
  • don't bootstrap evil code, which can be down in one of two ways:
    1. the hackish way, for example with the hardened_modules module, part of the provision_plesk project, which also involves a patch to Drupal core
    2. the "right" way, for example by making Drush bootstrap only trusted modules (#769264: have a whitelist of modules to bootstrap commandfiles and drupal code) - although that is only about .drush.inc files, not the Drupal bootstrap - and anyways if we don't trust the platform we're screwed here anyways
  • bootstrap evil code, but in a "sandbox" which means running under a separate user, with sudo for example, or by moving the modules/themes files to a directory outside of /var/aegir and chroot the user into /var/aegir before running jobs

Some fixes were implemented already:

Remaining tasks

I believe the next step is to avoid bootstrapping non-trusted code, or do it as the www-data user. The means changes to the sudoers file and provision.

User interface changes

Hopefully the user interface wouldn't change at all here.

API changes

The API would probably change in a way because some provision commands would run in a different environment (e.g. as www-data instead of aegir, so they won't have access to the Aegir aliases).

Original report by GuyPaddock

We're setting up a system that allows users to sign-up for Drupal hosting with us. Basically, we'll use Aegir to perform core upgrades, and update a few select shared modules (like CCK, Views, etc) with Drush, but users will essentially be able to run the rest of their site on their own. Each user will have their own user account, and their site will run under that user account. We have pretty much everything worked out to keep the system secure, except for a potential exploit with three hooks -- hook_cron, hook_init, and hook_cron.

For hook_cron, if we use the Cron Queue feature of Aegir, then Aegir directly invokes all hook_cron hooks of a site while running as the "aegir" user account, rather than the user who owns the site. This presents two problems. First, orphaned file clean-up usually fails because the aegir account does not have permission to delete a site owner's files (without taking ownership first). Second, a user can write arbitrary code in an implementation of hook_cron in their own custom module, and it will have the full privileges that the aegir account has. To work around this, we'll either have to re-work our set-up so that the Cron Queue runs through an HTTP request instead, allowing mpm-itk to execute cron under the owner's credentials; or, we'll have to just do cron the old-fashioned way without cron queue.

A similar problem exists for hook_init and hook_boot. These hooks are fired whenever drush performs a full bootstrap of a Drupal site, which happens for practically all Aegir/Provision operations. This means that users can write the same kind of custom module I mentioned before and run arbitrary code as the aegir account. I am yet to come up with a workaround for this one.

Would you happen to know if it would be possible to keep Provision and/or Aegir from executing said custom code while performing operations, or is it absolutely required that all modules have a chance to init and bootstrap?

Comments

anarcat’s picture

Category: support » bug

This is not a "slight security issue", it's a major design flaw right now, and it is known: you shouldn't let untrusted users access your modules or themes directory as Drush will happily load any code sitting in there (not only hook_init() or hook_cron(), but also any *.drush.inc file).

I have considered the problem and I think the only solution is to make the dispatcher switch user ids when executing the provision tasks.

anarcat’s picture

Title: Slight security issue with aegir permissions and the execution of hook_boot, hook_init, and hook_cron » Design security issue with developper access to sites' modules and themes

A more proper title, in my opinion.

guypaddock’s picture

The solution we ended up going with for the moment is to skip loading of all site-specific modules when drush is running as the Aegir user. Unfortunately, this required a patch to core that calls into a custom Drush module to determine whether or not a specific module is "safe" to load. This will work for our needs, at least.

The patch and custom module are mentioned here: http://drupal.org/project/provision_plesk
The code is currently in CVS, if you're curious.

guypaddock’s picture

Title: Design security issue with developper access to sites' modules and themes » Design security issue with developer access to sites' modules and themes
anarcat’s picture

I see. But be aware that this won't cover the .drush.inc case: any module defining a .drush.inc file will be able to hijack the dispatcher and run code as the aegir user.

anarcat’s picture

Also note that the proposed solution will still bootstrap drupal, which /could/ run code sitting in blocks or other php-available stuff from the frontend (to be verified).

anarcat’s picture

Since this is a rather old issue, I believe it would be worthwhile to make a little summary of the current situation regarding security implications of letting untrusted users run PHP code in Aegir sites.

There are multiple vulnerabilities here:

1. hook_cron runs as the aegir user (fixed in #788868: Can we switch to cron.php (standard wget) in Aegir?, though not the default)
2. contrib module code (hook_init / hook_exit / code outside functions) is loaded by the aegir user (still an issue, although the provision_plesk extension solves some of this)
3. drush.inc files are loaded by the aegir user (still an issue)
4. settings.php readable from all sites (fixed by moving the credentials to the environment in #334416: security between sites (settings.php protection) and #730424: Putting credentials in Apache VHost environment is insecure)
5. private files are readable and writable by any site (still an issue)

Here are the implications of each issue: #1, #2 and #3 mean the attacker can run code as the aegir user, which means they can do anything the aegir user can do, which is pretty much everything in the Aegir world. #4 mean that any attacker can read DB credentials from other sites, and therefore add/read/change/delete content from those sites. Since aegir is one of those sites, this could be leveraged to root the whole aegir install as with the scenarios in #1. #5 is the least critical issue: as things stand, any site can read/write any file uploaded by any other site.

I am hoping the work on the ACL stuff can resolve the issues with #5 and help provide a framework to resolve the other issues. The basic problem we have is that drush runs always as the same user, and therefore the safest approach would be to switch users before running sensitive tasks. Putting the ACLs in place is the first to make this possible, the next step would be to give the aegir user sudo rights to execute sensitive tasks as the right user.

Another approach is the one taken by provision_plesk extension to avoid bootstrapping modules in certain situations. The problem is that it doesn't resolve the issue for drush.inc files and requires patching core (!), which is very inconvenient, to say the least.

I would appreciate feedback on how to go forward with this, without patching core. :)

Overall, it should be understood that it's still unsafe, out of the box, to give arbitrary users PHP access to your sites or modules.

izmeez’s picture

subscribing

anarcat’s picture

Priority: Normal » Major

Marking major.

Basically, I see a few ways to tackle this:

  • make sure we only bootstrap Drupal when necessary, which involves:
    1. make an inventory of all provision and drush code that bootstraps non-core Drupal code (or even Drupal code, if we can't trust the platform)
    2. try to determine if there are commands in there that don't need to bootstrap
    3. trim the bootstrap level of those commands
  • don't bootstrap evil code, which can be down in one of two ways:
    1. the hackish way, for example with the hardened_modules module, part of the provision_plesk project, which also involves a patch to Drupal core
    2. the "right" way, for example by making Drush bootstrap only trusted modules (#769264: have a whitelist of modules to bootstrap commandfiles and drupal code) - although that is only about .drush.inc files, not the Drupal bootstrap - and anyways if we don't trust the platform we're screwed here anyways
  • bootstrap evil code, but in a sandbox, which involves running sudo or SELinux or some other magic trick. here, provisionacl helps as it allows regular users to run drush commands, but we'll probably need more than that to write aliases and so on...
anarcat’s picture

A word on drush bootstrap levels while I do the inventory. This is defined in environment.inc

DRUSH_BOOTSTRAP_DRUSH - safe, bootstraps only drush
DRUSH_BOOTSTRAP_DRUPAL_ROOT - loads the drushrc of the platform, safe
DRUSH_BOOTSTRAP_DRUPAL_SITE - loads the drushrc of the site and the .drush.inc in the site-specific directory, unsafe
DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION - loads settings.php and bootstrap.inc, safe for trusted platforms
DRUSH_BOOTSTRAP_DRUPAL_DATABASE - loads database.inc and connects to the DB, safe for trusted platforms
DRUSH_BOOTSTRAP_DRUPAL_FULL - bootstraps both site-specific and platform-wide modules and .drush.inc files, unsafe
DRUSH_BOOTSTRAP_DRUPAL_LOGIN - bootstraps both site-specific and platform-wide modules and .drush.inc files, unsafe

So problems start happening at DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION for untrusted platforms and DRUSH_BOOTSTRAP_DRUPAL_SITE (for .drush.inc, this is what #769264: have a whitelist of modules to bootstrap commandfiles and drupal code tries to solve) and especially DRUSH_BOOTSTRAP_DRUPAL_FULL for untrusted sites.

greg.1.anderson’s picture

I think it is a failure to allow users to add modules to their Drupal site, but then tell them that the cron hooks in their modules will not run. There are too many useful features that suddenly become non-useful; if you leave out cron support, then the claim that you can "add your own modules" becomes false advertising.

I think that the only real solution here is to use sudo or some other mechanism per the last bullet in #9 to insure that the cron task for each user runs with the correct permissions for that user. Anything else is a non-starter.

greg.1.anderson’s picture

The other obvious solution I missed would be to simply not call cron.php or drush cron and instead rely on Poor man's cron to run periodic actions.

anarcat’s picture

The problem is not just cron - about every other aegir command bootstraps the site: verify, enable and so on will all load the hostile modules happily. See comment #7 for the inventory of fun stuff in there.

We run cron through wget these days anyways to profit from the APC cache. :)

anarcat’s picture

I test this using the evil module: https://drupal.org/project/evil

crea’s picture

Did anyone research chrooting option ? When chrooted, one could have completely isolated environments. I suppose the issue is Aegir uses multisiting to run many sites on the same platform, and chrooting would require changing that behavior. That would require to run separated platform clones resulting in increased memory usage. But that would be perfect from the point of security.
Php-fpm can chroot out of the box.

anarcat’s picture

We worked with chrooting here. We moved the files/ and modules/ directories in the chroot and symlinked there, so that the user can only access those. But it doesn't resolve the issue: if the user uploads a .drush.inc or a .module and enables it, you're still running his code as the aegir user.

crea’s picture

Could running the aegir as chrooted platform user help in that case ?

User A runs a site on platform X in a chroot AA
User B runs a site on platform X in a chroot BB
AA and BB are different paths.
Users can't access each other files. Their webservers and php processes can access only own files since they run in the chroot (and under dedicated user if needed).

I suppose this kind of setup is what many hosting providers use (in the of world of general web hosting, not just Drupal).

anarcat’s picture

Problem with chrooting is that you cut off access to stuff you actually want: commands (tar, mysqldump), core Drupal code, etc. So that wouldn't actually work, IMHO. Better to just switch to another user completely.

crea’s picture

As far as I understand hosting companies make copies of required stuff into the chroot. I would trade disk space for increased security any day - it's cheap resource.

greg.1.anderson’s picture

Agree that chroot is not a good option here, as you have to copy a bunch of files as mentioned in #18. n.b. also that if you do not set up chroot correctly, it is possible that someone could write /etc/passwd or /etc/sudoers and gain full root to the box. This is generally only a problem for people who are careless and copy all of /bin or /usr/bin and accidentally pick up su or sudo (or even chmod) rather than cherry-picking the tools needed.

crea’s picture

I wonder what companies that advertise Aegir as a mass service do about these problems ? Koumbit, Omega8cc huh ?
Or is it "let's sell and hope that noone breaks it" approach :P

If chroot is a bad option, I agree that something like "sudo siteuser" for running site tasks that could invoke arbitrary uploaded code is the best target.

anarcat’s picture

Version: 6.x-0.4-alpha3 » 6.x-1.1

We (koumbit) are giving sftp access only to trusted users and clients, basically. We are looking at giving full shell access to everyone this summer as we fix this, probably through a new dispatcher.

omega8cc’s picture

Version: 6.x-1.1 » 6.x-0.4-alpha3

@crea

With Aegir based on Nginx we have even more serious issue, because settings.php file includes database credentials not cloaked like in the Apache version.

Our solution is to avoid using Aegir for Drupal site-level hosting, and instead we are creating separate environments for every Aegir instance using Octopus approach for Aegir basic instances (with virtual chroot/jail etc) and VServer separation for bigger instances.

This works great for our target audience - Drupal dev and/or design agencies, hosting and managing sites for their clients.

omega8cc’s picture

Version: 6.x-0.4-alpha3 » 6.x-1.1

Version changed because of race condition :)

greg.1.anderson’s picture

chroot can be a useful tool in some instances (e.g. #23) but beware of implementing chroot setups lightly, as chroot can often lead to reduced security, ironically enough. See Abusing chroot. Edit: Actually, that conversation is not particularly relevant here, as it discusses situations where the user in question already has root access. Just be careful of privileged escalation as mentioned in #20.

pearcec’s picture

sub

pearcec’s picture

Hi anarcat, et al,

You mention dispatcher a few times in this thread. You also are listed as the group spearheading the effort to resolve this. I want to help if I can. I just install the hosting_queue_runner today. It was fairly painless. Reading over the code seems like this is something that we could use to do the dispatching. We could run this as root and then spawn off a process that changed the uid and gid?

What did you have planned?

anarcat’s picture

Nothing yet. The problem is that you can't change the UID before you run hosting-task, you need to do this withing hosting-task, and then things start to get blurry because some commands touch both the system-level config files (e.g. provision-save) and site-specific data (e.g. provision-verify) which makes the whole thing fairly hairy to do properly.

But if you want to dig into this, please be my guest.

Robin Millette’s picture

subbing

helmo’s picture

subscribe

tema’s picture

subscribe

anarcat’s picture

I wrote an issue summary here for people that are monitoring this issue. Basically, I think the next step here is to see if we can run tasks under sudo -u www-data...

anarcat’s picture

Issue summary: View changes

make an issue summary

anarcat’s picture

A change in provisionacl (#1416056: give access to entire site directory (was: add support for .git)) actually broadened the attack surface here. With provisionacl enabled and ACLs applied, users can write directly to their site directory, which means that they can write local.settings.php or even remove and rewrite settings.php. So it means that DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION isn't safe anymore.

Updating summary.

anarcat’s picture

Issue summary: View changes

Updated issue summary.

anarcat’s picture

Issue summary: View changes

update the status of the safe bootstrap level

ergonlogic’s picture

Version: 6.x-1.1 » 7.x-3.x-dev
Status: Active » Postponed

I believe this will take a major refactoring to fix properly, probably using something like LXC to isolate process pools, or ITK to run each site under an individual user. To my knowledge none of the core team is actively working on this at the moment. Feel free to update the status as soon as someone does undertake this. Either way, it should be done in the dev branch.

omega8cc’s picture

We are experimenting with this in BOA-2.2.x series, and so far, after hacking Drush a bit, we have made some progress. Currently the only (but still critical) remaining problem is obviously ability to trick provision to run arbitrary code during Drupal bootstrap, since we have eliminated ability to trick Drush into running such code directly. That said, we have also discovered that hiding db credentials, so they are not listed explicitly in the settings.php doesn't really solve this problem at all, and it is trivial to obtain these credentials anyway. So, while it may seem postponed, we are actively working on a permanent solution, probably by re-invoking dangerous tasks involving too high Drupal bootstrap, via subsequent calls and modified PHP and other restrictions on the fly. We are already half way in this direction, even if it turned out to be far more complex and beyond just Aegir and Drush level modifications, than we originally expected.

~Grace