nginx文件类型错误解析漏洞
www.xxx.com/1.jpg
内容为PHP 代码,如
<?php
phpinfo();
?>
后面加任意 .php
www.xxx.com/1.jpg/xxx.php
导致代码被执行
php.ini
cgi.fix_pathinfo=1
PHP_INI_ALL 从 PHP 4.3.0 起可用 请注意:默认为1
两者访问时的区别
www.xxx.com/1.jpg
HTTP/1.1 200 OK
Server: nginx/版本
Date: XXX
Content-Type: text/plain
Content-Length: XX
Last-Modified: XX
Connection: keep-alive
Keep-Alive: timeout=20
Accept-Ranges: bytes
www.xxx.com/1.jpg/xxx.php
HTTP/1.1 200 OK
Server: nginx/版本
Date: XXX
Content-Type: text/html
Content-Length: XX
Last-Modified: XX
Connection: keep-alive
Keep-Alive: timeout=20
Accept-Ranges: bytes
就在Content-Type: text/plain与Content-Type: text/html
如果 jpg 是普通文件,内容直接显示,但如内容是php代码就杯具了,代码直接执行
即使是最普通的配置
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;
}
漏洞同样会出现,实际和 nginx关系,nginx 只是个 Proxy,只负责根据用户的配置文件,通过 fastcgi_param 指令将参数忠实地传递给 FastCGI Server,问题在于 FastCGI Server 如何处理 nginx 提供的参数
http://xx.com/foo.jpg/a.php/b.php/c.php
nginx 传递给 FastCGI 的 SCRIPT_FILENAME 的值为:
/foo.jpg/a.php/b.php/c.php
也就是 $_SERVER['ORIG_SCRIPT_FILENAME']
php.ini 中 cgi.fix_pathinfo = 1 时,PHP CGI 以 / 为分隔符号从后向前依次检查如下路径:
/foo.jpg/a.php/b.php/c.php
/foo.jpg/a.php/b.php
/foo.jpg/a.php
/foo.jpg
直到找个某个存在的文件,如果这个文件是个非法的文件,悲剧
PHP 会把这个文件当成 cgi 脚本执行,并赋值路径给 CGI 环境变量——SCRIPT_FILENAME,也就是 $_SERVER['SCRIPT_FILENAME'] 的值
解决办法
1,上传时代码判断文件类型
2, nginx 解析
如
if ( $fastcgi_script_name ~ \..*\/.*php ) {
return 403;
}
http://www.54chen.com/php-tech/nginx-php-cgi-of-security-hole.html
http://www.st0p.org/blog/tag/cgi-fix_pathinfo