php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #50837 Allowing execution of non-.php file from erroneous path
Submitted: 2010-01-25 21:25 UTC Modified: 2010-01-25 23:07 UTC
From: info at karlblessing dot com Assigned:
Status: Not a bug Package: CGI/CLI related
PHP Version: 5.2.12 OS: Debian 5.0 x86_64 GNU/Linux
Private report: No CVE-ID: None
 [2010-01-25 21:25 UTC] info at karlblessing dot com
Description:
------------
Webserver Used : Nginx 0.8.32
PHP Build Used : PHP 5.2.12 with FPM patch
PHP is configured to run as fastcgi

Non-php files could be excuted as php, when appended with a path and 
erroneous php file. 

Affects setups running PHP via Fastcgi, primarily on non-Apache setups. 
Could potentially allow someone uploading exploits, such as a jpeg with 
php code in it to wordpress (which doesn't check if its an actual jpeg, 
or headers), and execute code from there. 

Reproduce code:
---------------
Save <?php phpinfo(); ?> into a file called test.txt and access it via http://domain.com/test.txt/fake.php

Expected result:
----------------
No input file specified.

Actual result:
--------------
Actual result shows the usual PHP Info printout, with the following 
variables.

_SERVER["SCRIPT_NAME"]	no value
_SERVER["SCRIPT_FILENAME"]	/opt/html/domain/test.txt
_SERVER["REQUEST_URI"]	/test.txt/1.php
_SERVER["DOCUMENT_URI"]	/test.txt/1.php
_SERVER["DOCUMENT_ROOT"]	/opt/html/domain
_SERVER["PATH_INFO"]	no value
_SERVER["PATH_TRANSLATED"]	/opt/html/domain

_SERVER["ORIG_PATH_INFO"]	no value
_SERVER["ORIG_SCRIPT_NAME"]	/test.txt/1.php
_SERVER["ORIG_SCRIPT_FILENAME"]	/opt/html/domain/test.txt/1.php
_SERVER["ORIG_PATH_TRANSLATED"]	/opt/html/domain


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-01-25 21:29 UTC] rasmus@php.net
This is a web server problem or configuration issue.  Not a PHP issue.
 [2010-01-25 22:17 UTC] info at karlblessing dot com
As evidently shown, PHP accepted the original request uri of 
/test.txt/fake,php, and evidently shown in the php_info , it took that 
and changed the script_file name to test.txt, 

It should have tried to execute fake.php and returned no file could be 
found. If the webserver had instead sent test.txt as the 
script_filename, and /fake.php as the path_info, then I could understand 
it happening, but it did not.
 [2010-01-25 22:30 UTC] rasmus@php.net
Well, first, there is no fake.php in your output there.  So I don't 
know about your "evidently" since your evidence doesn't match at all.  
And second, PHP doesn't set SCRIPT_FILENAME, your web server does.  So 
your web server determined that the script to execute was 
"/opt/html/domain/test.txt" evidently as per your own evidence.  So PHP 
executed that script.  I am not sure why that is surprising to you.  
Why is your web server telling PHP to run test.txt?  PHP doesn't check 
the filetype.  It runs what it is told to run.
 [2010-01-25 22:32 UTC] info at karlblessing dot com
1.php was from a previous test when I typed /1.php after test.txt, if 
you type /fake.php after test.txt it'll show fake.txt, just like how I 
don't own domain.com, you apparently can't go back and edit the 
original.
 [2010-01-25 22:35 UTC] info at karlblessing dot com
Regarding the webserver, Nginx matches up php via regex, as per the 
wiki provided 

http://wiki.nginx.org/PHPFcgiExample#Connecting_Nginx_to_the_running_F
astCGI_Process

location ~ \.php$ { ... } would match up to a php file request. 

It is my opinion that the PHP parser should take script_filename 
litterally. 

That is to say
script_filename = /test.txt/1.php
path_info = no value

shouldn't execute

but
script_filename = /test.txt
path_info = /1.php

should execute, if the webserver indeed sent it those values. In my 
case it only sent /test.txt/1.php , which should not have worked 
because that filename does not exist on the system.
 [2010-01-25 22:38 UTC] rasmus@php.net
It still doesn't matter.  By the time the request makes it to PHP, PHP 
is going to execute.  I bet you can't reproduce this on a properly 
configured Apache server that correctly finds the script and the 
pathinfo.  Note that in your output your ORIG_PATH_INFO is empty, which 
is incorrect.  If your URI is /test.txt/1.php and /test.txt exists, 
then "/1.php" is the PATH_INFO.  Obviously your server doesn't seem to 
understand that and determines the URI should be executed by PHP.  The 
executable part of your URI is /test.txt and it isn't PHP's job to 
second-guess that.

 [2010-01-25 22:41 UTC] info at karlblessing dot com
But PHP is second guessing, it was sent "/test.txt/1.php" as the 
original script_filename, that file doesn't exist on the system, so how 
does it execute the code if 1.php does not exist? As a result it was the 
parser that move down to the test.txt. Again, note the original 
script_filename sent to the parser.
 [2010-01-25 22:52 UTC] rasmus@php.net
PHP walks back through the script_filename it is passed and tries to 
find the script to execute.  Once again, it is the web server's job to 
figure out that a URI doesn't exist.  PHP doesn't serve up 404s under 
any circumstances.  If all your web server is doing is a simple regex 
to determine whether something should be executed or not, then your web 
server is broken.
 [2010-01-25 23:07 UTC] info at karlblessing dot com
Digging into it quote a bit for future readers of the bug. 

The ~ \.php { } matchup as taught by nginx wiki and nginx creator is 
indeed insecure if php is to execute the way described above. 

Turns out to fix, needs to have something like this:

location ~ [^/.][a-zA-Z0-9_-]+\.php[s]? { } 

doing such will 404 on the above /test.txt/fake.php example, but will 
still correctly parse path_info. 

#50837 CLOSED/BOGUS , no further argument from me. I'll go update the 
wiki
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 04:01:29 2024 UTC