当前位置:web 服务器 > Nginx >>

Nginx + PHP CGI的安全漏洞:fix_pathinfo


具体的重现过程,用php代码修改后缀名后上传,比如说www.zhaoxi.org/1.jpg,访问的时候用www.zhaoxi.org/1.jpg/xxx.php

这段jpg代码将会被执行!!!

cgi.fix_pathinfo “1″ PHP_INI_ALL 从 PHP 4.3.0 起可用 请注意:默认为1


为什么会这样呢?

比如, 如下的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 (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…

 
解决办法:
1.修改php.ini中的cgi.cgi.fix_pathinfo为0(即使你在php.ini中没有搜到,也要设置,没有搜到表示默认为1)
2.判断文件上传类型时使用严格的判断
3.把nginx的判断正则修改为去除/
if ( $fastcgi_script_name ~ \..*\/.*php ) {
return 403;
}

Apache
IIS
Nginx
Tomcat
如果你遇到web 服务器难题:
请访问www.zzzyk.com 试试
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,