4

I have a follow up question on this answer about executing image files as php. The answer explains that nginx support virtual directories. One can run

www.something.com/blan.php/one/two/3

and one/two/3 will be virtual subdirectories. Then, according to the answer, if we have a file named malicious.jpg, we can trick nginx to run it as a php file like this:

localhost/malicious.jpg/something.php

How can this be possible? Is it misconfiguration or human error?

  • This used to be possible in older PHP versions in case file headers were not checked by the the upload mechanism. What you'd do is create a PHP file, rename it to a JPG (or any other allowed extension) and use a null byte in the filename. It would be come something like malicious.php%00.jpg. Since the null byte will terminate the execution flow, in certain cases it was possible the system wrote the file to the filesystem as malicious.php. – Jeroen Sep 16 at 10:49
3

This is not strictly an Nginx problem, but rather is an issue with old versions of PHP. It has been fixed for quite a long while (I'm not sure exactly what version, but it certainly isn't a concern with PHP 7.0). The answers to this question:

https://serverfault.com/q/627903/377662

Explain the underlying issue and solution in detail. The short answer is that what you are calling "virtual directories" are common in many web server applications (including Apache and Nginx) and are used so that the website can show nice urls (aka /categories/5) instead of (categories.php?id=5). Imagine this flow:

  1. User: Server, please give me /categories/5
  2. Server (to itself): Hmm... /categories/5 isn't a file
  3. Server (to itself): That's okay, this rule says that categories.php knows what to do
  4. Server: PHP, The user requested /categories/5, and categories.php should be able to handle that. Can you tell me what to return?
  5. PHP: Okay, I talked to categories.php and here is your answer!
  6. Server: User, here is the contents of /categories/5

Which is generally a fairly straightforward exchange. The server has done everything properly - PHP needs to know not just the name of the file to execute, but also the details about what URL was originally requested.

Unfortunately older versions of PHP used to get confused and, despite being told by the server that categories.php was the thing to execute, would sometimes attempt to "fix" the information coming from the server and may end up executing a different file than what the server actually suggested. This would lead to PHP executing test.jpg on the basis of the fact that the original URL was test.jpg/whatever.php, even though the server told it to execute a completely different file.

This should no longer be a relevant issue at all. If you are worried though, you can just set the fix_pathinfo directive to 0 in your php.ini file. Again, full details and background are explained extensively in the answers to this question.

  • Thanks for your answer. It is perfect. – pax Sep 18 at 11:03
  • this is half-true.... yes PHP used to handle this badly unless you coded for this usecase. however its the webserver that passes the request the PHP in the first case. My awnser (with thehupdate) and this anwser tells the full story. ( mine goes into the webserver config, this explains the PHP side of things). – LvB Sep 24 at 13:24
1

The issue is that most often people configure their PHP block like this:

    location ~ '\.php' {
        include fastcgi.conf;
        include fastcgi_params;
        fastcgi_param HTTP_PROXY "";
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param QUERY_STRING $query_string;
        fastcgi_intercept_errors on;
        fastcgi_pass unix:/sockets/php.socket;
    }

This would match any url path ending in .php This is done due to many (bad) examples online and due to previous versions of the nginx example config not clearly explaining this risk. The way to mitigate it is to limit php execution from all of the places that contain user uploaded files.

  • Thanks for your answer. To conclude your answer, that kind of attack can be possible only because of user's misc-configuration and using old version of nginx. Am I right? And for old version of nginx, can this kind of attack be possible without user's misc-configuration? – pax Sep 17 at 11:07
  • Unfortunately this is incorrect. There is nothing dangerous in this nginx configuration file. Just to make sure I wasn't crazy, I went ahead and tested it - I used this config file, I created a test.png file that contained php, I verified that I can request test.png, and then I requested test.png/anything.php. I received only a 404. The issue the OP is asking about is an issue in PHP, not in nginx. You're looking in the wrong place. – Conor Mancone Sep 17 at 12:20
  • To be clear, your final advice is perfectly correct - you should not allow your server to try to execute anything inside a directory that contains user-uploaded files. My issue is that this doesn't explain the issue the OP is asking about. – Conor Mancone Sep 17 at 12:35
  • @ConorMancone oops you are correct I mistakenly pasted the correct way of doing it( so with the '$' sign in place) I updated my awnser by removing it.. your test should than work as expected if you would repeat it without the $. – LvB Sep 24 at 13:22
  • @LvB I'm happy to be proven wrong, but I gave it a try without the $ to match the end of the filename, and I still can't get a .jpg file to execute as PHP. I would suggest confirming the exploit yourself and then posting a more complete example. – Conor Mancone Sep 24 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.