Possible widespread PHP configuration issue - security risk

Look, not had a lot of success raising this quietly. The Nginx wiki
has a number of very insecure PHP configuration suggestions. Anyone
using these example configurations should immediately review their
configuration and ensure that they aren’t vulnerable to an upload attack
where uploaded files might be accidentally treated as executable files
by nginx

The core of the problem is that most of the example configurations
enable php scripts in all directories on the server. Coupled with
relatively poor upload handling (in most PHP apps) and you have an
upload attack waiting to blow up on you.

Try the following:

  1. PHP Uploads allows (erk…)

Create a file test.php containing:

<?php echo 'hello' ?>

Try and upload this. If you can then probably turn off the server until
you fix the issue…

The attack is to construct a URL which points to the uploads directory,
eg:
http://myserver/uploads/test.php

  1. JPG uploads allowed, and wildcard ~ .php execution allowed

Create a test file test.jpg as follows:
# echo -e “\xff\xd8\xff\xe0\n<?php echo 'hello'; ?>” > test.jpg
# file test.jpg
test.jpg: JPEG image data

Now try and upload this test.jpg file to your server. If it succeeds
then probably turn off the server until you fix the issue…

The attack is to construct a URL which points to the uploads directory
and then append /.php on the URL, eg
http://myserver/uploads/test.jpg/.php

Under certain configurations (wildcard php without a specific
SCRIPT_URL set) this will cause the execution of test.jpg by the php
interpreter

The correct solution is where possible:

  • Enable PHP only on files in certain directories (if possible). Exclude
    upload dirs!
  • Specifically disable (lots of) stuff on any upload locations!!
    Remember configuration ordering in nginx puts regexp before named
    locations (order is important)
  • Use try_files and other techniques to additionally lock down uri to
    file mapping
  • Check for any Apache .htaccess files shipped with your app and
    translate to nginx config where appropriate (eg blocking certain
    locations completely)

There are plenty of examples of dangerous configuration on the nginx
wiki. eg the Wordpress initially presented configuration seems
vulnerable, but further down that page a more secure config is
presented:
WordPress | NGINX
The Media wiki example seems to show the same vulnerability:
http://wiki.nginx.org/NginxMediaWiki

Please just treat your uploads directory carefully. It’s a huge attack
vector.

Any volunteers to help improve the Wiki? Anyone got some better example
configurations (which are secure)? I don’t use most of the PHP apps
listed, so hard to test their configurations?

Note this is not a problem with Nginx, this is a configuration issue.
However, the docs recommend such an insecure default configuration that
there must surely be loads of people vulnerable here…

Cheers

Ed W

On 8/27/10 11:22 AM, Ed W wrote:

upload attack waiting to blow up on you.

Now try and upload this test.jpg file to your server. If it succeeds
then probably turn off the server until you fix the issue…

It doesn’t work on the apps I mentioned. It simply won’t upload.

But again, it is still up to individual webmasters to test and secure
their own apps.

The correct solution is where possible:

There are plenty of examples of dangerous configuration on the nginx
wiki. eg the Wordpress initially presented configuration seems
vulnerable, but further down that page a more secure config is presented:
WordPress | NGINX
The Media wiki example seems to show the same vulnerability:
http://wiki.nginx.org/NginxMediaWiki

So stop complaining about the Wiki and fix it. The Wiki is after all a
community project. If you have better ideas post them.

there must surely be loads of people vulnerable here…

Cheers


Jim O.

http://myserver/uploads/test.jpg/.php - this attack relyes on some
php-fcgi feature ?

I don’t think it will work on ‘proxy_pass’ to Apache

Actually, there is difference between
location ~ .php$ { }
and
location ~ .php {}

Last one will match ‘test.php.jpg’, but Apache will still handle such
file as image/jpeg, so ‘fastcgi_pass’ is still required to exploit such
configuration.

It also applyes to first exploit too - most installations forbid access
to *.php files in upload/ dir by .htaccess, so ‘proxy_pass’ will return
403 in most cases.

But, again, people using ‘fastcgi_pass’ should take a look at their
configs, they really may be vulnerable.

Posted at Nginx Forum:

On 27/08/2010 16:45, Jim O. wrote:

So stop complaining about the Wiki and fix it. The Wiki is after all a
community project. If you have better ideas post them.

I’m posting and yet you are apparently telling me not to post any more?

On 8/27/10 12:07 PM, Ed W wrote:

On 27/08/2010 16:45, Jim O. wrote:

So stop complaining about the Wiki and fix it. The Wiki is after all a
community project. If you have better ideas post them.

I’m posting and yet you are apparently telling me not to post any more?

Don’t be so dramatic.

I said to stop complaining about the content of the Wiki and feel free
to fix it. You seem to have all the answers.

Out…


Jim O.

Ed W Wrote:

by nginx

More discussion and proposed fixes here:

In addition to:

  1. disabling .php execution in upload directories;
  2. adding a try_files to your .php location to check that the requested
    .php file exists;
    you can also change this setting in php.ini

cgi.fix_pathinfo=1

to

cgi.fix_pathinfo=0

to disable that feature and then use

location ~ ^(.+.php)(.)$ {
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+.php)(.
)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass http://localhost:9000;
}

if you have software that needs the path_info feature. The only thing I
use that does is chive.

Thanks in advance for updating the wiki

Posted at Nginx Forum:

On 27/08/2010 17:15, Jim O. wrote:

I said to stop complaining about the content of the Wiki and feel free
to fix it. You seem to have all the answers.

Oh fuck off you twit.

If the content is dangerously wrong (my assertion only for sure) then
sticking your head in the sand and telling the person highlighting the
problem to shut up is hardly a solution?

I don’t have all the answers. Why don’t you get off your high horse
and we will see if we can’t together design a better general fastcgi
config?

Regards

Ed W

On 27/08/2010 16:47, zuborg wrote:

http://myserver/uploads/test.jpg/.php - this attack relyes on some
php-fcgi feature ?

I think it’s purely down to use of this configuration stanza:

 location ~ \.php$ {
     fastcgi_pass myphp;
 }

What I try and do as far as possible is use a tighter stanza so that it
only applies to certain files or directories or whatever. I have done
it on a slightly ad-hoc basis so far and used IF statements if I need to
exclude stuff and a tigher regexp in other situations

My implicit question was really because I suspect there is perhaps a
better and more general way to right this generic config assuming:

  • large number of arbitrary locations containing PHP files
  • some dangerous locations which need to be excluded
  • complicated mapping between URIs and file locations

Perhaps someone has a better base config for the above and fastcgi?

Remember the other hint here was that many web apps ship with a bunch of
.htaccess files for apache. It feels very likely that many nginx users
forget to scan for these and translate them into appropriate nginx
configuration. How could we better document that this usually shouldn’t
be ignored?

Ed W

On Fri, Aug 27, 2010 at 17:25, Ed W [email protected] wrote:

Oh fuck off you twit.

Gee, you’re so mature.

Hi

More discussion and proposed fixes here:
Re: nginx 0day exploit for nginx + fastcgi PHP

Thanks for the link.

However, I have to say with my “typical user” hat on: I started reading
the thread, got about halfway through, skipped to the end to find some
kind of executive summary and then came away deciding that it looked too
complicated…

Look, there are some smart cookies here and I’m sure most of the people
on this list have their server’s setup securely. However, there are a
massive 99% of other people who just want to cut and paste a config and
it’s my opinion that the default configs they are likely using have big
holes in them

This isn’t new stuff. EVERY web app needs to secure the uploads
directory. The point is more that the main config examples are for
Apache and less skilled nginx users will easily miss these subtleties.

I last posted about this 23/2/2009. Didn’t raise the slightest interest
then either.

In addition to:

  1. disabling .php execution in upload directories;

Yes, but this isn’t that obvious how to do?

  1. adding a try_files to your .php location to check that the requested
    .php file exists;

I agree. However, we still don’t have a cut’n’paste solution for the
average user?

if you have software that needs the path_info feature. The only thing I
use that does is chive.

Actually I think we might be overthinking the problem here. I don’t
think it’s the path_info which is the problem - the post you mentioned
was really just a special case of getting the interpreter to run
something in the uploads dir. I think the big final config change is to
give a more generic way to avoid running files in the upload dir at
all
. All the other stuff such as try_files, etc is really icing after
that?

Look, heres my best attempt. I think it’s poor hence I hope someone has
a better suggestion:

Single script, enable only that single script:

             location ~ /blah/script\.php$ {
                     include /etc/nginx/fastcgi_params;
                     fastcgi_pass    localhost:9000;
             }

Exclude single dir, everything else executable:

             location ~ .*.php$ {
                     include /etc/nginx/fastcgi_params;
                     if ( $uri !~ "^/images/") {
                         fastcgi_pass    localhost:9000;
                     }
             }

Thanks in advance for updating the wiki

I don’t know what the definitive solution should be yet? All I see are
a very confused bunch of posts showing how if you are an nginx guru it
won’t happen to you…? Lets get a core solution shall we and then we
can work from there?

Ed W

On 27/08/2010 17:32, Nuno Magalhães wrote:

I said to stop complaining about the content of the Wiki and feel
free to fix it. You seem to have all the answers.

Oh fuck off you twit.
Gee, you’re so mature.

How is your post advancing the solution?

How about you avoid quoting out of context parts of my message and focus
on the rest of that message?

Regards

Ed W

I’m not sure why a bunch of people are attacking me over this?

The problem is clearly worded. I have taken some time to try and
explain the issue. I have appealed for help designing a solution and yet
half the responses are flames?

Look, I’m reasonably sure my servers are fine. I don’t really care if
thousands of people I don’t know get their servers taken over. However,
I have taken the time to try and help here and try to encourage
discussion on a new and better baseline config - I don’t see why I’m
getting attacked over this?

Regards

Ed W

Hey Ed W,

Just want to say that while I’m not participating in this dialog since
it is over my head, I am listening and I do appreciate your asking
these questions, as well as your general commitment to Nginx and its
community.

Hopefully I am part of a silent majority in this regard.

Best,
Raina G.

On Fri, 2010-08-27 at 17:45 +0100, Ed W wrote:

on the rest of that message?
And destroy the theme of this thread?

Aside from the first post I haven’t seen a single response that didn’t
overreact to the previous one.

My personal opinion is that if you have PHP installed you already have
serious security concerns (every server I take live almost immediately
undergoes a hostile scan for every popular PHP package in existence).

Nevertheless, I’ve updated the MediaWiki entry. I’m sure there’s still
8000 other security holes in MediaWiki that allow remote execution of
code, but hopefully this isn’t one of them.

That being said: Ed, if you have specific information about
misconfigurations on the wiki, PLEASE update them or at least make a
note on the wiki itself that there are concerns. As has been pointed
out, it’s a community-driven project. If something is wrong we need
people to fix it. Your long email would have been better served as a
wiki page that was linked to from all PHP configs that appear
vulnerable.

Now, everyone fuck off.

Regards,
Cliff

Ed W Wrote:

This isn’t new stuff. EVERY web app needs to
secure the uploads
directory. The point is more that the main config
examples are for
Apache and less skilled nginx users will easily
miss these subtleties.

As you say, your web app should have a plan for mitigating the dangers
of user uploads. Drupal puts an .htaccess file in the upload directory
which changes the apache file handler. Of course, that does nothing
with nginx and so you want something like

location ~ ./files/. {
try_files $uri =404 # or index.php?q=$uri or @drupal depending on your
config
}

located before your location ~ .php so you get a match on the files
directory and you don’t execute malicious .php. Or something more
restrictive when it comes to .php files like specifying the permitted
executable files explicitly. see
http://test.brianmercer.com/content/nginx-configuration-drupal

I don’t think it’s the path_info which is the problem -

Your situation number 2 is about path info which is enabled in PHP by
default so that requests like

http://mysite.com/chive/index.php/site/login

will work. Most web apps don’t need the cgi.fix_pathinfo feature turned
on. Drupal, Wordpress use queries. i.e.
http://mysite.com/wordpress/index.php?q=/site/login

Some things like chive need the path info feature, and so the PHP devs
ship PHP with cgi.fix_pathinfo turned on by default, which leads to the
vulnerability with common nginx configurations. Luckily, nginx has
support for pathinfo without enabling cgi.fix_pathinfo in php. I noted
the config above.

The only solution is to alert people to these complexities, and to
update the sample configs on the wiki. Unfortunately, there’s about a
thousand sample configs on the web which don’t account for this issue.
A page on the wiki specifically addressing upload directories and
cgi.fix_pathinfo would also be a good idea.

Posted at Nginx Forum:

Nevertheless, I’ve updated the MediaWiki entry. I’m sure there’s still
8000 other security holes in MediaWiki that allow remote execution of
code, but hopefully this isn’t one of them.

The nginx wiki has of a few moments ago stopped responding for me? I
could get to it a before, now the browser just hangs saying “connecting
to wiki.nginx.org”?

Update - I can reach some of it, but the javascript “wikibits.js” isn’t
downloading, this is blocking page loading for me?

That aside, I hope we can do better than whatever you wrote (don’t
know what you wrote though…).

Can you please see my more recent email where I have listed some general
categories of application and perhaps we can hammer out some generic
configurations that solve those situations?

After that I think is the best time to update the wiki?

Cheers

Ed W

Hello!

On Fri, Aug 27, 2010 at 05:42:38PM +0100, Ed W wrote:

[…]

Look, heres my best attempt. I think it’s poor hence I hope someone
has a better suggestion:

Single script, enable only that single script:

            location ~ /blah/script\.php$ {
                    include /etc/nginx/fastcgi_params;
                    fastcgi_pass    localhost:9000;
            }

Use exact match location instead:

location = /blah/script.php {
    ...
}

Exclude single dir, everything else executable:

            location ~ .*.php$ {
                    include /etc/nginx/fastcgi_params;
                    if ( $uri !~ "^/images/") {
                        fastcgi_pass    localhost:9000;
                    }
            }

Use normal location instead, with “^~” (don’t execute regexp
locations) modifier:

location ^~ /images/ {
    # just handle as static, don't consult regexps
}

location ~ \.php$ {
    fastcgi_pass ...
}

Or, alternatively (and much more clear, but may have problems
in older nginx versions), use inclusive/nested locations:

location / {
    ...

    location ~ \.php$ {
        fastcgi_pass ...
    }
}

location /images/ {
    # just handle as static
}

Maxim D.

On Fri, Aug 27, 2010 at 9:17 PM, brianmercer [email protected]
wrote:

located before your location ~ .php so you get a match on the files
directory and you don’t execute malicious .php. Or something more
restrictive when it comes to .php files like specifying the permitted
executable files explicitly. see
http://test.brianmercer.com/content/nginx-configuration-drupal
By the way, you can just write:
location ^~ /files/
{
try_files …;
}
And if the request matches this location, no regular expressions
locations will be tried.


Boris D…

Hi

ship PHP with cgi.fix_pathinfo turned on by default, which leads to the
vulnerability with common nginx configurations. Luckily, nginx has
support for pathinfo without enabling cgi.fix_pathinfo in php. I noted
the config above.

Thanks for clarifying this - I guess I didn’t understand my own example
correctly

This stuff is quite subtle - I hope we are getting somewhere towards a
generic config starting point now…

The only solution is to alert people to these complexities, and to
update the sample configs on the wiki. Unfortunately, there’s about a
thousand sample configs on the web which don’t account for this issue.
A page on the wiki specifically addressing upload directories and
cgi.fix_pathinfo would also be a good idea.

Sounds excellent - I’m hoping some smarter folks can also suggest a
baseline cgi config and then we have all the bits together?

Note some other smart people might point out that there are other nginx
specific config that might usefully be applied to untrusted upload
directories? Anyone think of anything that might be missed along the
SSI/directory listing line that could be abused?

Cheers

Ed W

On Fri, 2010-08-27 at 18:21 +0100, Ed W wrote:

That aside, I hope we can do better than whatever you wrote (don’t
know what you wrote though…).

Can you please see my more recent email where I have listed some general
categories of application and perhaps we can hammer out some generic
configurations that solve those situations?

I simply do not have time for the next several days. I’m literally
working day and night on an app that I need ready by Monday.

Plus, I am probably the worst person to work on PHP issues as I firmly
believe PHP to be utter crap starting from its conception right down to
the last byte of its actual implementation. It tries my patience in
ways a toddler wired on espresso couldn’t.

Regards,
Cliff