nginx+php 上传含有php脚本的木马图片文件的漏洞解决

 

http://www.80sec.com/nginx-securit.html漏洞详解

 

解决方法:

解决方案:

我们已经尝试联系官方,但是此前你可以通过以下的方式来减少损失
关闭cgi.fix_pathinfo为0

或者

if ( $fastcgi_script_name ~ /..*//.*php ) {
return 403;
}

 

漏洞危险等级:毁灭性。
这个漏洞严格上说并不是 Nginx 和 PHP 本身的漏洞造成的,而是由配置造成的。在我之前写的许多配置中,都普遍存在这个漏洞。

简易检测方法:
打开 Nginx + PHP 服务器上的任意一张图片,如:

如果在图片链接后加一串 /xxx.php (xxx为任意字符)后,如:

图片还能访问的话,说明你的配置存在漏洞。

漏洞分析:
下面通过分析一个很常见的 Nginx 配置来解释下漏洞的成因:
server {
     listen       80;
     server_name  test.local;

     access_log  /work/www/logs/test.access.log  main;
     error_log  /work/www/logs/test.error.log;

     location / {
         root   /work/www/test;
         index  index.html index.htm index.php;
     }

     location ~ /.php$ {
         root           /work/www/test;
         fastcgi_index  index.php;
         fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
         include        fastcgi_params;
         fastcgi_pass   unix:/tmp/php-fpm.sock;
     }
}

我们在 /work/www/test/ 目录下新建一个文件 test.png,内容如下:
那么访问  时,输出为文本内容:
但是当在后面加上 /xxx.php 时,即 http://test.local/test.png/xxx.php,可怕的事情发生了:
Array
(
     [HOSTNAME] =>
     [PATH] => /usr/local/bin:/usr/bin:/bin
     [TMP] => /tmp
     [TMPDIR] => /tmp
     [TEMP] => /tmp
     [OSTYPE] =>
     [MACHTYPE] =>
     [MALLOC_CHECK_] => 2
     [USER] => www
     [HOME] => /home/www
     [FCGI_ROLE] => RESPONDER
     [SCRIPT_FILENAME] => /work/www/test/test.png
     [QUERY_STRING] =>
     [REQUEST_METHOD] => GET
     [CONTENT_TYPE] =>
     [CONTENT_LENGTH] =>
     [SCRIPT_NAME] => /test.png/xxx.php
     [REQUEST_URI] => /test.png/xxx.php
     [DOCUMENT_URI] => /test.png/xxx.php
     [DOCUMENT_ROOT] => /work/www/test
     [SERVER_PROTOCOL] => HTTP/1.1
     [GATEWAY_INTERFACE] => CGI/1.1
     [SERVER_SOFTWARE] => nginx/0.7.62
     [REMOTE_ADDR] => 192.168.1.163
     [REMOTE_PORT] => 4080
     [SERVER_ADDR] => 192.168.1.12
     [SERVER_PORT] => 80
     [SERVER_NAME] => test.local
     [REDIRECT_STATUS] => 200
     [HTTP_ACCEPT] => image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/QVOD, application/QVOD, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
     [HTTP_ACCEPT_LANGUAGE] => zh-cn
     [HTTP_ACCEPT_ENCODING] => gzip, deflate
     [HTTP_USER_AGENT] => Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQPinyin 689; QQDownload 627; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2; TheWorld)
     [HTTP_HOST] => test.local
     [HTTP_CONNECTION] => Keep-Alive
     [ORIG_SCRIPT_FILENAME] => /work/www/test/test.png/xxx.php
     [PATH_TRANSLATED] => /work/www/test
     [PHP_SELF] => /test.png/xxx.php
     [REQUEST_TIME] => 1274125615
)
环境变量中,SCRIPT_FILENAME 是 Nginx 传过来的:
fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
$fastcgi_script_name 变量说明请参考:
http://wiki.nginx.org/NginxHttpFcgiModule

Nginx 传给 PHP 的值为 /work/www/test/test.png/xxx.php,即 $_SERVER 中 ORIG_SCRIPT_FILENAME 的值,但是 $_SERVER 中 SCRIPT_FILENAME 却是 /work/www/test/test.png。
原因是,/work/www/test/test.png/xxx.php 并不存在,对于这些不存在的路径,PHP 会检查路径中存在的文件,并将多余的部分当作 PATH_INFO。
这里,/work/www/test/test.png 被 PHP 解析为 SCRIPT_FILENAME,/xxx.php 被 PHP 解析为 PATH_INFO 后被丢弃,因此并没有在 $_SERVER 中出现。

解决方法:
解决这个漏洞的方法很显然:关闭上面所述的解析即可。
这个解析可以在 PHP 的配置文件中设置,默认为开启。在这里我们需要将它关闭:
; 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 its 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.
; http://php.net/cgi.fix-pathinfo
;cgi.fix_pathinfo=1
cgi.fix_pathinfo=0
其中 cgi.fix_pathinfo=0 为新增的配置行,表示关闭 PHP 的自动 PATH_INFO 检测。关闭后,该配置漏洞即可消除。

更好的解决方案?
以上方案并不是最完美的,如果你先前有用到 cgi.fix_pathinfo 这个特性,影响会很大,比如关闭后,我的 Blog(Wordpress)文章的 URL 目录形式就得用 rewrite 来实现了。
如果可以将 PHP 设置成只解析 .php 为扩展名的文件,那么这个问题解决起来会更合理。
不过我没找到相关的设置项,或许今后应该出现在 php-fpm 的配置文件中?

总结:
这类问题基本上是无法预料的,但是如果架构设计良好的话,即使存在这个问题,也不会影响安全性。这里给出架构上的安全建议:
* 尽可能使动静内容分离,所有的静态内容存在于静态内容服务器,静态内容服务器上不解析PHP,这样静态文件就永远不能被解析了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值