PHP CGI 中 fix_pathinfo 引起的安全隐患

May 22nd, 2010 | Filed under PHP

这两天网上开始疯传一个“nginx文件类型错误解析漏洞”,这个“漏洞”是这样的:

假设有如下的 URL:http://phpvim.net/foo.jpg,当访问 http://phpvim.net/foo.jpg/a.php 时,foo.jpg 将会被执行,如果 foo.jpg 是一个普通文件,那么 foo.jpg 的内容会被直接显示出来,但是如果把一段 php 代码保存为 foo.jpg,那么问题就来了,这段代码就会被直接执行。这对一个 Web 应用来说,所造成的后果无疑是毁灭性的。

关于这个问题,已有高手 laruence 做过详细的分析,这里再多啰嗦几句。

首先不管你是否有用到正则来解析 PATH_INFO,这个漏洞都是存在的。比如下面这个最基本的 nginx 配置:

1
2
3
4
5
6
location ~ \.php$ {
    fastcgi_pass  127.0.0.1:9000;
    fastcgi_index index.php;
    include       fastcgi_params;
    fastcgi_param SCRIPT_FILENAME   $document_root$fastcgi_script_name;
}

漏洞同样会出现,如 laruence 所说,实际上这个漏洞和 nginx 真的没什么关系,nginx 只是个 Proxy,它只负责根据用户的配置文件,通过 fastcgi_param 指令将参数忠实地传递给 FastCGI Server,问题在于 FastCGI Server 如何处理 nginx 提供的参数?

比如访问下面这个 URL:

1
http://phpvim.net/foo.jpg/a.php/b.php/c.php

那么根据上面给出的配置,nginx 传递给 FastCGI 的 SCRIPT_FILENAME 的值为:

1
/home/verdana/public_html/unsafe/foo.jpg/a.php/b.php/c.php

也就是 $_SERVER[‘ORIG_SCRIPT_FILENAME’]。

当 php.ini 中 cgi.fix_pathinfo = 1 时,PHP CGI 以 / 为分隔符号从后向前依次检查如下路径:

1
2
3
4
/home/verdana/public_html/unsafe/foo.jpg/a.php/b.php/c.php
/home/verdana/public_html/unsafe/foo.jpg/a.php/b.php
/home/verdana/public_html/unsafe/foo.jpg/a.php
/home/verdana/public_html/unsafe/foo.jpg

直到找个某个存在的文件,如果这个文件是个非法的文件,so… 悲剧了~

PHP 会把这个文件当成 cgi 脚本执行,并赋值路径给 CGI 环境变量——SCRIPT_FILENAME,也就是 $_SERVER[‘SCRIPT_FILENAME’] 的值了。

在很多使用 php-fpm (<0.6) 的主机中也会出现这个问题,但新的 php-fpm 的已经关闭了 cgi.fix_pathinfo,如果你查看 phpinfo() 页面会发现这个选项已经不存在了,代码 ini_get("cgi.fix_pathinfo") 的返回值也是 "false"。 原因是似乎因为 APC 的一个 bug,当 cgi.fix_pathinfo 开启时,PATH_TRANSLATED 有可能是 NULL,从而引起内存异常,造成 php-fpm crash,所以 php-fpm 关闭这个选项。

Tags: , ,
Comments are closed.