Security Misconfiguration Vulnerability in various Doctrine projects

Posted on August 31, 2015 by default


We are releasing new versions of Doctrine Cache, Annotations, ORM and MongoDB ODM today that fix a security misconfiguration vulnerability. This vulnerability was assigned CVE-2015-5723. It requires an attacker to have direct access to a user of the server to be exploitable. We consider exploitability to be low to medium.

Exploiting this vulnerability can allow attackers to perform local arbitrary code execution with privileges of other users (privilege escalation).

You are only affected by this vulnerability, if your application runs with a umask of 0.

Please update:

  • Annotations to 1.2.7
  • Cache to 1.4.2 or 1.3.2
  • Common to 2.5.1 or 2.4.3
  • ORM to 2.5.1 or 2.4.8
  • MongoDB ODM to 1.0.2
  • MongoDB ODM Bundle to 3.0.1

If you want to check the fix or apply patch manually, we provide a Gist with all patches.

If you cannot upgrade, see our notes below how to mitigate the problem without having to patch the code.

We want to thank Ryan Lane for finding the vulnerability, Jonathan Eskew from the AWS team to pass this security vulnerability to us and Anthony Ferrara for helping us discuss and find solutions to the problem.

Details

Doctrine uses different kinds of caches and some of them read the cached entries using require or include to make use of APC or Opcache. In case of proxy generation we actually need to execute the code to make a new auto-generated class part of the code-base.

Doctrine always uses mkdir($cacheDirectory, 0777); on many of those caches directories. If your application is running with umask(0), this allows an attacker to write arbitrary code into the cache directory which can be executed with the user privileges of the webserver.

Running your application with umask(0) is not generally a good idea, but is sometimes recommended as simple solution to solve filesystem access problems when a console and a web user both write to a common cache directory. In combination with a cache that executes the cache entries as code, this can allow local arbitrary code execution.

The patches released today change all caches that execute code to always use a default mask of 0775 instead of 0777.

  • In case of Cache and Annotations we solve this by implementing a userland configurable umask that defaults to 0002. We apply this to every mkdir and chmod so that you can reconfigure to another mask if you must.
  • In all the other cases its a hardcoded change to 0775 for directories and 0664 for files.

We are aware that if you depend on umask(0), this is a very inconvenient change, because your code will break when different users write to the same cache directory.

We feel it is not safe to make developers and operations responsible to know how to secure our cache implementations. They are often third party libraries to other open-source systems, we want them to be safe no matter how users configure their system.

Am I vulnerable?

Your application must run with umask(0) for this vulnerability to be exploitable. This must not necessarily be an explicit call to the PHP function, it can also happen if you misconfigured your shell or webserver to run with umask 0 by default.

You can easily check this by calling echo umask(); from both the shell and your webserver. It will return 0, if you are potentially vulnerable.

Second, you must be using using Doctrine with the Annotations FileCache or the PhpFileCache Cache implementation or one of the ORM or ODM ProxyGenerators. Of course this vulnerability can also be present in any other library or your own application, when you dynamically generate PHP code into a directory with world writable permissions.

Do you provide fixes for all branches of all affected components?

No, fixes are only applied to the most recent versions of Doctrine components.

If you are running older components and don't want to or cannot upgrade, you should look into the sections about immediate and proper fixes below, that show solutions that don't require upgrading your code.

If your system and application are correctly setup, it is also likely that you are not vulnerable. See the next section for information about that.

Is there an immediate fix when I can't upgrade?

Yes, as an immediate fix just make sure that your application runs with a non-zero umask all the time. Call umask(umask() | 0002); early in your code to prevent PHP from ever creating world writeable files and directories.

Warning: It can break your application if it relies on running with umask(0);.

This is not sufficient though, because the call to umask is not thread safe and a call to this function later in the code can reset the umask for all requests currently running. That means you must identify all code that calls umask(0); and change it.

When you are unsure if your generated cache is clean, you can regenerate all files after you have changed the umask of your application.

Is there a proper fix or security best-practive to avoid this issue?

Yes, the best way to fix this problem is to always execute PHP code for a single application with the same user, independent of being called from the webserver, php-fpm or the shell. In this case you can always create directories with the default permissions of 0775 and files with 0664:

<?php
// safety measure to overrule webserver or shell misconfiguration
umask(umask() | 0002);

mkdir("/some/directory", 0775);
file_put_contents("/some/directory/file", "data");
chmod("/some/directory/file", 0664);

On most linux distributions it is possible to execute cronjobs or supervisord jobs with the www-data, nginx or apache users that the webserver runs with.

Another way would be to use more advanced permission systems in Linux such as chmod +a or setfacl, both of which are not available on all distributions though.

Isn't everyone just using 0777/0666 everywhere?

Yes, this practice is extremely wide-spread in many projects. This is why we think it is very important to make sure your application runs with a proper umask.

However, in our case the potential vulnerability is more severe than usual, because we use require/include to execute the written cache files, which can allow an attacker with access to a local user the possibility for executing arbitrary code with the webservers user.

Code that is reading the generted/cache files using fopen/file_get_contents could "only" be poisoned with invalid or wrong data by an attacker. This is severe by itself, but does not allow arbitrary code execution.

We want users of Doctrine to be safe by default, so we are changing this even if it will cause inconveniences.

We have also notified as many OSS projects of this beforehand, mainly through PHP-FIG, because of the wide-spread practice. Several of them are preparing security releases for their libraries as well.

Again, the nature of this issue is mostly remedied by not running with umask of zero, so make sure this is the case for your applications.

Questions?

If you have questions you can signup to the Doctrine User Mailinglist and ask there or join #doctrine IRC Channel on Freenode.