gcttong00 2010-05-21
国内顶级安全团队80sec于5.20日下午6点发布了一个关于nginx的漏洞通告,由于该漏洞的存在,使用nginx+php组建的网站只要允许上传图片就可能被黑客入侵,直到5.21日凌晨,nginx尚未发布补丁修复该漏洞。
根据Netcraft的统计,直到2010年4月,全球一共有1300万台服务器运行着nginx程序;非常保守的估计,其中至少有600万台服务器运行着nginx并启用了php支持;继续保守的估计,其中有1/6,也就是100万台服务器允许用户上传图片
由于nginx有漏洞,这100万台服务器可能通过上传图片的方法被黑客轻易的植入木马。植入木马的过程也非常简单,就是把木马改成图片上传就是了,由于危害非常大,就不说细节了。有兴趣的请访问http://www.80sec.com/nginx-securit.html
说了那么多,我想大家对80sec这个顶级安全团队比较好奇吧,素包子简单介绍一下。
80sec团队由一群年轻、充满活力、充满体力、充满激情、富有创造力的未婚dota男组成,他们均在各大互联网公司从事信息安全工作,他们的口号是knowitthenhackit,素包子非常认同这个观点:“我们只要非常熟悉一个事物,就有可能客观的发现它的不足之处,同时我们也能的发现该事物的优点”。
80sec的意思是“80端口的安全”,也就是“web安全”;同时由于该团队成员都是80后的年轻人,我们也可以理解为“80后安全”;另外由于sec的发音是seke,我们还可以理解为“80后色客”、“80后摄客”或“80后S客”,我们对80sec的理解仅受限于想象力。
下面介绍一下他们的丰功伟绩,他们曾发现IIS、IE、FireFox、Maxthon、世界之窗、PHPWind、DeDeCMS、QQmail、QuarkMail、EXTMail等软件的漏洞,可见硕果累累。
既然介绍了80sec,就不得不介绍另外一个非常专注WEB安全的顶级安全团队80vul,该团队同样也是由80后的男童鞋组成(90后表示压力很大:p),他们也发现了大量WEBAPP的安全漏洞,例如IE、Gmail、wordpress、PHPWind、DISCUZ、MYBB等。
看到这里,想必大家心里都有那么点遗憾,那就是为何没有80后女黑客(我不歧视伪娘,但我必须说明不是伪娘),我也有相同的遗憾。
最后发一个小道消息,据说黑客已经在行动了;安全人员、系统管理人员、行动起来吧,赶紧修复该漏洞;最好不要有侥幸心理,否则下一个被黑客入侵的可能就是你的网站。根据80sec安全公告的描述,临时修复方法如下,可3选其一。
1、设置php.ini的cgi.fix_pathinfo为0,重启php。最方便,但修改设置的影响需要自己评估。
2、给nginx的vhost配置添加如下内容,重启nginx。vhost较少的情况下也很方便。
if($fastcgi_script_name~\..*\/.*php){
return403;
}
3、禁止上传目录解释PHP程序。不需要动webserver,如果vhost和服务器较多,短期内难度急剧上升;建议在vhost和服务器较少的情况下采用。
作者:Hily原始链接:http://hily.me/blog/2010/05/nginx-php-configure-security-problem/
版权声明:可以转载,转载时务必以超链接形式标明文章原始出处和作者信息及版权声明
漏洞危险等级:毁灭性。
这个漏洞严格上说并不是Nginx和PHP本身的漏洞造成的,而是由配置造成的。在我之前写的许多配置中,都普遍存在这个漏洞。
简易检测方法:
打开Nginx+PHP服务器上的任意一张图片,如:
如果在图片链接后加一串/xxx.php(xxx为任意字符)后,如:
图片还能访问的话,说明你的配置存在漏洞。
漏洞分析:
下面通过分析一个很常见的Nginx配置来解释下漏洞的成因:
server{
listen80;
server_nametest.local;
access_log/work/www/logs/test.access.logmain;
error_log/work/www/logs/test.error.log;
location/{
root/work/www/test;
indexindex.htmlindex.htmindex.php;
}
location~\.php${
root/work/www/test;
fastcgi_indexindex.php;
fastcgi_paramSCRIPT_FILENAME$document_root$fastcgi_script_name;
includefastcgi_params;
fastcgi_passunix:/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;MSIE6.0;WindowsNT5.1;SV1;QQPinyin689;QQDownload627;Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1;SV1);.NETCLR2.0.50727;.NETCLR3.0.4506.2152;.NETCLR3.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_paramSCRIPT_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_pathinfoprovides*real*PATH_INFO/PATH_TRANSLATEDsupportforCGI.PHP's
;previousbehaviourwastosetPATH_TRANSLATEDtoSCRIPT_FILENAME,andtonotgrok
;whatPATH_INFOis.FormoreinformationonPATH_INFO,seethecgispecs.Setting
;thisto1willcausePHPCGItofixitspathstoconformtothespec.Asetting
;ofzerocausesPHPtobehaveasbefore.Defaultis1.Youshouldfixyourscripts
;touseSCRIPT_FILENAMEratherthanPATH_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,这样静态文件就永远不能被解析了。