Security Misconfiguration Vulnerability in various Doctrine projects
Posted on
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 and0664
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.